From 24fbe571516161d48b499d587f9adb3e683dbf88 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 31 Jan 2011 17:37:59 +0000 Subject: Imported Upstream version 1.2.24 --- AUTHORS | 64 + COPYING | 552 + ChangeLog | 5 + ChangeLog.pre-1-0 | 15146 ++++++++++ ChangeLog.pre-1-2 | 2027 ++ Doxyfile.in | 181 + HACKING | 341 + INSTALL | 234 + Makefile.am | 59 + Makefile.in | 971 + NEWS | 0 NEWS.pre-1-0 | 614 + NEWS.pre-1-2 | 153 + README | 153 + acinclude.m4 | 133 + aclocal.m4 | 9032 ++++++ bus/Makefile.am | 234 + bus/Makefile.in | 1458 + bus/activation-exit-codes.h | 45 + bus/activation-helper-bin.c | 100 + bus/activation-helper.c | 563 + bus/activation-helper.h | 31 + bus/activation.c | 2351 ++ bus/activation.h | 68 + bus/bus.c | 1569 + bus/bus.h | 122 + bus/config-loader-expat.c | 294 + bus/config-loader-libxml.c | 323 + bus/config-parser-common.c | 183 + bus/config-parser-common.h | 59 + bus/config-parser-trivial.c | 696 + bus/config-parser-trivial.h | 71 + bus/config-parser.c | 3466 +++ bus/config-parser.h | 89 + bus/connection.c | 2303 ++ bus/connection.h | 141 + bus/dbus-daemon.1 | 760 + bus/dbus-daemon.1.in | 760 + bus/desktop-file.c | 800 + bus/desktop-file.h | 56 + bus/dir-watch-default.c | 40 + bus/dir-watch-dnotify.c | 93 + bus/dir-watch-inotify.c | 279 + bus/dir-watch-kqueue.c | 255 + bus/dir-watch.h | 40 + bus/dispatch.c | 4725 +++ bus/dispatch.h | 38 + bus/driver.c | 2022 ++ bus/driver.h | 52 + bus/expirelist.c | 412 + bus/expirelist.h | 80 + bus/main.c | 479 + bus/messagebus.in | 92 + bus/policy.c | 1296 + bus/policy.h | 164 + bus/rc.messagebus.in | 79 + bus/selinux.c | 1091 + bus/selinux.h | 72 + bus/services.c | 1306 + bus/services.h | 94 + bus/session.conf.in | 60 + bus/signals.c | 2030 ++ bus/signals.h | 88 + bus/system.conf.in | 83 + bus/test-launch-helper.c | 146 + bus/test-main.c | 151 + bus/test-system.c | 106 + bus/test.c | 346 + bus/test.h | 58 + bus/utils.c | 48 + bus/utils.h | 36 + cleanup-man-pages.sh | 86 + compile | 143 + config.guess | 1501 + config.h.in | 380 + config.sub | 1705 ++ configure | 29138 +++++++++++++++++++ configure.in | 1567 + dbus-1.pc.in | 15 + dbus/Makefile.am | 203 + dbus/Makefile.in | 1060 + dbus/dbus-address.c | 826 + dbus/dbus-address.h | 61 + dbus/dbus-arch-deps.h | 67 + dbus/dbus-arch-deps.h.in | 67 + dbus/dbus-auth-script.c | 803 + dbus/dbus-auth-script.h | 39 + dbus/dbus-auth-util.c | 168 + dbus/dbus-auth.c | 2690 ++ dbus/dbus-auth.h | 81 + dbus/dbus-bus.c | 1587 + dbus/dbus-bus.h | 82 + dbus/dbus-connection-internal.h | 120 + dbus/dbus-connection.c | 5947 ++++ dbus/dbus-connection.h | 406 + dbus/dbus-credentials-util.c | 204 + dbus/dbus-credentials.c | 550 + dbus/dbus-credentials.h | 79 + dbus/dbus-dataslot.c | 477 + dbus/dbus-dataslot.h | 96 + dbus/dbus-errors.c | 418 + dbus/dbus-errors.h | 82 + dbus/dbus-hash.c | 2193 ++ dbus/dbus-hash.h | 142 + dbus/dbus-internals.c | 951 + dbus/dbus-internals.h | 346 + dbus/dbus-keyring.c | 1154 + dbus/dbus-keyring.h | 52 + dbus/dbus-list.c | 1405 + dbus/dbus-list.h | 98 + dbus/dbus-macros.h | 137 + dbus/dbus-mainloop.c | 908 + dbus/dbus-mainloop.h | 76 + dbus/dbus-marshal-basic.c | 1982 ++ dbus/dbus-marshal-basic.h | 261 + dbus/dbus-marshal-byteswap-util.c | 105 + dbus/dbus-marshal-byteswap.c | 246 + dbus/dbus-marshal-byteswap.h | 42 + dbus/dbus-marshal-header.c | 1489 + dbus/dbus-marshal-header.h | 133 + dbus/dbus-marshal-recursive-util.c | 3565 +++ dbus/dbus-marshal-recursive.c | 2739 ++ dbus/dbus-marshal-recursive.h | 196 + dbus/dbus-marshal-validate-util.c | 588 + dbus/dbus-marshal-validate.c | 1204 + dbus/dbus-marshal-validate.h | 203 + dbus/dbus-memory.c | 842 + dbus/dbus-memory.h | 59 + dbus/dbus-mempool.c | 577 + dbus/dbus-mempool.h | 44 + dbus/dbus-message-factory.c | 1228 + dbus/dbus-message-factory.h | 61 + dbus/dbus-message-internal.h | 74 + dbus/dbus-message-private.h | 125 + dbus/dbus-message-util.c | 1349 + dbus/dbus-message.c | 4173 +++ dbus/dbus-message.h | 235 + dbus/dbus-misc.c | 248 + dbus/dbus-misc.h | 51 + dbus/dbus-object-tree.c | 1949 ++ dbus/dbus-object-tree.h | 62 + dbus/dbus-pending-call-internal.h | 67 + dbus/dbus-pending-call.c | 824 + dbus/dbus-pending-call.h | 65 + dbus/dbus-protocol.h | 439 + dbus/dbus-resources.c | 194 + dbus/dbus-resources.h | 52 + dbus/dbus-server-debug-pipe.c | 432 + dbus/dbus-server-debug-pipe.h | 47 + dbus/dbus-server-protected.h | 160 + dbus/dbus-server-socket.c | 539 + dbus/dbus-server-socket.h | 49 + dbus/dbus-server-unix.c | 236 + dbus/dbus-server-unix.h | 37 + dbus/dbus-server.c | 1202 + dbus/dbus-server.h | 91 + dbus/dbus-sha.c | 968 + dbus/dbus-sha.h | 55 + dbus/dbus-shared.h | 131 + dbus/dbus-shell.c | 640 + dbus/dbus-shell.h | 41 + dbus/dbus-signature.c | 542 + dbus/dbus-signature.h | 81 + dbus/dbus-spawn.c | 1457 + dbus/dbus-spawn.h | 61 + dbus/dbus-string-private.h | 126 + dbus/dbus-string-util.c | 878 + dbus/dbus-string.c | 2918 ++ dbus/dbus-string.h | 321 + dbus/dbus-sysdeps-pthread.c | 363 + dbus/dbus-sysdeps-unix.c | 3495 +++ dbus/dbus-sysdeps-unix.h | 134 + dbus/dbus-sysdeps-util-unix.c | 1175 + dbus/dbus-sysdeps-util.c | 176 + dbus/dbus-sysdeps.c | 1102 + dbus/dbus-sysdeps.h | 531 + dbus/dbus-test-main.c | 54 + dbus/dbus-test.c | 190 + dbus/dbus-test.h | 83 + dbus/dbus-threads-internal.h | 53 + dbus/dbus-threads.c | 816 + dbus/dbus-threads.h | 196 + dbus/dbus-timeout.c | 490 + dbus/dbus-timeout.h | 75 + dbus/dbus-transport-protected.h | 143 + dbus/dbus-transport-socket.c | 1357 + dbus/dbus-transport-socket.h | 45 + dbus/dbus-transport-unix.c | 181 + dbus/dbus-transport-unix.h | 37 + dbus/dbus-transport.c | 1411 + dbus/dbus-transport.h | 92 + dbus/dbus-types.h | 139 + dbus/dbus-userdb-util.c | 442 + dbus/dbus-userdb.c | 667 + dbus/dbus-userdb.h | 121 + dbus/dbus-uuidgen.c | 129 + dbus/dbus-uuidgen.h | 47 + dbus/dbus-watch.c | 674 + dbus/dbus-watch.h | 83 + dbus/dbus.h | 103 + depcomp | 630 + doc/Makefile.am | 41 + doc/Makefile.in | 463 + doc/TODO | 155 + doc/busconfig.dtd | 65 + doc/dbus-faq.html | 437 + doc/dbus-faq.xml | 674 + doc/dbus-specification.html | 2081 ++ doc/dbus-specification.xml | 4086 +++ doc/dbus-test-plan.html | 141 + doc/dbus-test-plan.xml | 232 + doc/dbus-tutorial.html | 991 + doc/dbus-tutorial.xml | 1667 ++ doc/dcop-howto.txt | 559 + doc/diagram.png | Bin 0 -> 78762 bytes doc/diagram.svg | 590 + doc/file-boilerplate.c | 27 + doc/introspect.dtd | 37 + doc/introspect.xsl | 106 + doc/system-activation.txt | 80 + install-sh | 520 + ltmain.sh | 8406 ++++++ missing | 376 + test/Makefile.am | 158 + test/Makefile.in | 1046 + .../auth/anonymous-client-successful.auth-script | 16 + .../auth/anonymous-server-successful.auth-script | 13 + test/data/auth/cancel.auth-script | 19 + .../data/auth/client-out-of-mechanisms.auth-script | 7 + test/data/auth/external-failed.auth-script | 11 + test/data/auth/external-root.auth-script | 11 + test/data/auth/external-silly.auth-script | 12 + test/data/auth/external-successful.auth-script | 12 + test/data/auth/extra-bytes.auth-script | 10 + test/data/auth/fail-after-n-attempts.auth-script | 34 + test/data/auth/fallback.auth-script | 17 + test/data/auth/invalid-command-client.auth-script | 8 + test/data/auth/invalid-command.auth-script | 7 + test/data/auth/invalid-hex-encoding.auth-script | 6 + test/data/auth/mechanisms.auth-script | 8 + test/data/equiv-config-files/basic/basic-1.conf | 25 + test/data/equiv-config-files/basic/basic-2.conf | 5 + .../equiv-config-files/basic/basic.d/basic.conf | 13 + .../equiv-config-files/entities/basic.d/basic.conf | 13 + .../equiv-config-files/entities/entities-1.conf | 14 + .../equiv-config-files/entities/entities-2.conf | 5 + test/data/incomplete-messages/missing-body.message | 19 + test/data/invalid-config-files/badselinux-1.conf | 10 + test/data/invalid-config-files/badselinux-2.conf | 10 + test/data/invalid-config-files/circular-1.conf | 4 + test/data/invalid-config-files/circular-2.conf | 4 + test/data/invalid-config-files/circular-3.conf | 4 + .../data/invalid-config-files/not-well-formed.conf | 5 + test/data/invalid-config-files/truncated-file.conf | 9 + test/data/invalid-messages/array-of-nil.message | 31 + .../array-with-mixed-types.message | 52 + .../invalid-messages/bad-boolean-array.message | 27 + test/data/invalid-messages/bad-boolean.message | 22 + test/data/invalid-messages/bad-endian.message | 25 + .../bad-header-field-alignment.message | 38 + .../boolean-has-no-value.message-raw | Bin 0 -> 102 bytes test/data/invalid-messages/local-namespace.message | 21 + test/data/invalid-messages/no-dot-in-name.message | 19 + .../not-nul-header-padding.message | 25 + test/data/invalid-messages/overlong-name.message | 20 + .../too-little-header-padding.message | 24 + .../too-much-header-padding-by-far.message | 26 + .../too-much-header-padding.message | 23 + test/data/invalid-messages/too-short-dict.message | 28 + .../org.freedesktop.DBus.TestSuiteNoExec.service | 4 + ...org.freedesktop.DBus.TestSuiteNoExec.service.in | 4 + ...org.freedesktop.DBus.TestSuiteNoService.service | 4 + ....freedesktop.DBus.TestSuiteNoService.service.in | 4 + .../org.freedesktop.DBus.TestSuiteNoUser.service | 4 + ...org.freedesktop.DBus.TestSuiteNoUser.service.in | 4 + test/data/sha-1/Readme.txt | 83 + test/data/sha-1/bit-hashes.sha1 | 1239 + test/data/sha-1/bit-messages.sha1 | 4009 +++ test/data/sha-1/byte-hashes.sha1 | 343 + test/data/sha-1/byte-messages.sha1 | 2294 ++ .../debug-allow-all-fail.conf | 17 + .../debug-allow-all-fail.conf.in | 17 + .../debug-allow-all-pass.conf | 17 + .../debug-allow-all-pass.conf.in | 17 + test/data/valid-config-files/basic.conf | 32 + test/data/valid-config-files/basic.d/basic.conf | 13 + .../valid-config-files/debug-allow-all-sha1.conf | 16 + .../debug-allow-all-sha1.conf.in | 16 + test/data/valid-config-files/debug-allow-all.conf | 15 + .../valid-config-files/debug-allow-all.conf.in | 15 + test/data/valid-config-files/entities.conf | 14 + test/data/valid-config-files/many-rules.conf | 59 + test/data/valid-config-files/session.conf | 60 + test/data/valid-config-files/system.conf | 83 + test/data/valid-config-files/system.d/test.conf | 20 + .../array-of-array-of-uint32.message | 33 + test/data/valid-messages/dict-simple.message | 15 + test/data/valid-messages/dict.message | 47 + test/data/valid-messages/emptiness.message | 63 + test/data/valid-messages/lots-of-arguments.message | 65 + test/data/valid-messages/no-padding.message | 22 + test/data/valid-messages/opposite-endian.message | 30 + test/data/valid-messages/recursive-types.message | 99 + test/data/valid-messages/simplest-manual.message | 30 + test/data/valid-messages/simplest.message | 10 + .../standard-acquire-service.message | 26 + test/data/valid-messages/standard-hello.message | 22 + .../valid-messages/standard-list-services.message | 22 + .../valid-messages/standard-service-exists.message | 24 + .../valid-messages/unknown-header-field.message | 19 + ...g.freedesktop.DBus.TestSuiteEchoService.service | 5 + ...reedesktop.DBus.TestSuiteEchoService.service.in | 5 + ...eedesktop.DBus.TestSuiteSegfaultService.service | 5 + ...esktop.DBus.TestSuiteSegfaultService.service.in | 5 + ...ktop.DBus.TestSuiteShellEchoServiceFail.service | 5 + ...p.DBus.TestSuiteShellEchoServiceFail.service.in | 5 + ...p.DBus.TestSuiteShellEchoServiceSuccess.service | 5 + ...Bus.TestSuiteShellEchoServiceSuccess.service.in | 5 + ...g.freedesktop.DBus.TestSuite.PrivServer.service | 4 + ...reedesktop.DBus.TestSuite.PrivServer.service.in | 4 + ...g.freedesktop.DBus.TestSuiteEchoService.service | 4 + ...reedesktop.DBus.TestSuiteEchoService.service.in | 4 + ...esktop.DBus.TestSuiteForkingEchoService.service | 3 + ...top.DBus.TestSuiteForkingEchoService.service.in | 3 + ...eedesktop.DBus.TestSuiteSegfaultService.service | 4 + ...esktop.DBus.TestSuiteSegfaultService.service.in | 4 + ...ktop.DBus.TestSuiteShellEchoServiceFail.service | 4 + ...p.DBus.TestSuiteShellEchoServiceFail.service.in | 4 + ...p.DBus.TestSuiteShellEchoServiceSuccess.service | 4 + ...Bus.TestSuiteShellEchoServiceSuccess.service.in | 4 + test/decode-gcov.c | 2652 ++ test/name-test/Makefile.am | 66 + test/name-test/Makefile.in | 857 + test/name-test/run-test-systemserver.sh | 50 + test/name-test/run-test.sh | 55 + test/name-test/run-with-tmp-session-bus.conf | 87 + test/name-test/test-activation-forking.py | 60 + test/name-test/test-ids.c | 55 + test/name-test/test-pending-call-dispatch.c | 123 + test/name-test/test-pending-call-timeout.c | 102 + test/name-test/test-privserver-client.c | 116 + test/name-test/test-privserver.c | 118 + test/name-test/test-shutdown.c | 67 + test/name-test/test-threads-init.c | 179 + test/name-test/test-wait-for-echo.py | 41 + test/name-test/tmp-session-like-system.conf | 87 + test/shell-test.c | 108 + test/spawn-test.c | 41 + test/test-exit.c | 8 + test/test-names.c | 78 + test/test-segfault.c | 28 + test/test-service.c | 489 + test/test-shell-service.c | 195 + test/test-sleep-forever.c | 16 + test/test-utils.c | 343 + test/test-utils.h | 26 + tools/Makefile.am | 47 + tools/Makefile.in | 797 + tools/dbus-cleanup-sockets.1 | 43 + tools/dbus-cleanup-sockets.c | 431 + tools/dbus-launch-x11.c | 463 + tools/dbus-launch.1 | 183 + tools/dbus-launch.c | 1214 + tools/dbus-launch.h | 58 + tools/dbus-monitor.1 | 78 + tools/dbus-monitor.c | 354 + tools/dbus-print-message.c | 407 + tools/dbus-print-message.h | 31 + tools/dbus-send.1 | 95 + tools/dbus-send.c | 526 + tools/dbus-uuidgen.1 | 89 + tools/dbus-uuidgen.c | 161 + tools/run-with-tmp-session-bus.sh | 76 + 373 files changed, 215661 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 ChangeLog.pre-1-0 create mode 100644 ChangeLog.pre-1-2 create mode 100644 Doxyfile.in create mode 100644 HACKING create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 NEWS create mode 100644 NEWS.pre-1-0 create mode 100644 NEWS.pre-1-2 create mode 100644 README create mode 100644 acinclude.m4 create mode 100644 aclocal.m4 create mode 100644 bus/Makefile.am create mode 100644 bus/Makefile.in create mode 100644 bus/activation-exit-codes.h create mode 100644 bus/activation-helper-bin.c create mode 100644 bus/activation-helper.c create mode 100644 bus/activation-helper.h create mode 100644 bus/activation.c create mode 100644 bus/activation.h create mode 100644 bus/bus.c create mode 100644 bus/bus.h create mode 100644 bus/config-loader-expat.c create mode 100644 bus/config-loader-libxml.c create mode 100644 bus/config-parser-common.c create mode 100644 bus/config-parser-common.h create mode 100644 bus/config-parser-trivial.c create mode 100644 bus/config-parser-trivial.h create mode 100644 bus/config-parser.c create mode 100644 bus/config-parser.h create mode 100644 bus/connection.c create mode 100644 bus/connection.h create mode 100644 bus/dbus-daemon.1 create mode 100644 bus/dbus-daemon.1.in create mode 100644 bus/desktop-file.c create mode 100644 bus/desktop-file.h create mode 100644 bus/dir-watch-default.c create mode 100644 bus/dir-watch-dnotify.c create mode 100644 bus/dir-watch-inotify.c create mode 100644 bus/dir-watch-kqueue.c create mode 100644 bus/dir-watch.h create mode 100644 bus/dispatch.c create mode 100644 bus/dispatch.h create mode 100644 bus/driver.c create mode 100644 bus/driver.h create mode 100644 bus/expirelist.c create mode 100644 bus/expirelist.h create mode 100644 bus/main.c create mode 100755 bus/messagebus.in create mode 100644 bus/policy.c create mode 100644 bus/policy.h create mode 100644 bus/rc.messagebus.in create mode 100644 bus/selinux.c create mode 100644 bus/selinux.h create mode 100644 bus/services.c create mode 100644 bus/services.h create mode 100644 bus/session.conf.in create mode 100644 bus/signals.c create mode 100644 bus/signals.h create mode 100644 bus/system.conf.in create mode 100644 bus/test-launch-helper.c create mode 100644 bus/test-main.c create mode 100644 bus/test-system.c create mode 100644 bus/test.c create mode 100644 bus/test.h create mode 100644 bus/utils.c create mode 100644 bus/utils.h create mode 100755 cleanup-man-pages.sh create mode 100755 compile create mode 100755 config.guess create mode 100644 config.h.in create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.in create mode 100644 dbus-1.pc.in create mode 100644 dbus/Makefile.am create mode 100644 dbus/Makefile.in create mode 100644 dbus/dbus-address.c create mode 100644 dbus/dbus-address.h create mode 100644 dbus/dbus-arch-deps.h create mode 100644 dbus/dbus-arch-deps.h.in create mode 100644 dbus/dbus-auth-script.c create mode 100644 dbus/dbus-auth-script.h create mode 100644 dbus/dbus-auth-util.c create mode 100644 dbus/dbus-auth.c create mode 100644 dbus/dbus-auth.h create mode 100644 dbus/dbus-bus.c create mode 100644 dbus/dbus-bus.h create mode 100644 dbus/dbus-connection-internal.h create mode 100644 dbus/dbus-connection.c create mode 100644 dbus/dbus-connection.h create mode 100644 dbus/dbus-credentials-util.c create mode 100644 dbus/dbus-credentials.c create mode 100644 dbus/dbus-credentials.h create mode 100644 dbus/dbus-dataslot.c create mode 100644 dbus/dbus-dataslot.h create mode 100644 dbus/dbus-errors.c create mode 100644 dbus/dbus-errors.h create mode 100644 dbus/dbus-hash.c create mode 100644 dbus/dbus-hash.h create mode 100644 dbus/dbus-internals.c create mode 100644 dbus/dbus-internals.h create mode 100644 dbus/dbus-keyring.c create mode 100644 dbus/dbus-keyring.h create mode 100644 dbus/dbus-list.c create mode 100644 dbus/dbus-list.h create mode 100644 dbus/dbus-macros.h create mode 100644 dbus/dbus-mainloop.c create mode 100644 dbus/dbus-mainloop.h create mode 100644 dbus/dbus-marshal-basic.c create mode 100644 dbus/dbus-marshal-basic.h create mode 100644 dbus/dbus-marshal-byteswap-util.c create mode 100644 dbus/dbus-marshal-byteswap.c create mode 100644 dbus/dbus-marshal-byteswap.h create mode 100644 dbus/dbus-marshal-header.c create mode 100644 dbus/dbus-marshal-header.h create mode 100644 dbus/dbus-marshal-recursive-util.c create mode 100644 dbus/dbus-marshal-recursive.c create mode 100644 dbus/dbus-marshal-recursive.h create mode 100644 dbus/dbus-marshal-validate-util.c create mode 100644 dbus/dbus-marshal-validate.c create mode 100644 dbus/dbus-marshal-validate.h create mode 100644 dbus/dbus-memory.c create mode 100644 dbus/dbus-memory.h create mode 100644 dbus/dbus-mempool.c create mode 100644 dbus/dbus-mempool.h create mode 100644 dbus/dbus-message-factory.c create mode 100644 dbus/dbus-message-factory.h create mode 100644 dbus/dbus-message-internal.h create mode 100644 dbus/dbus-message-private.h create mode 100644 dbus/dbus-message-util.c create mode 100644 dbus/dbus-message.c create mode 100644 dbus/dbus-message.h create mode 100644 dbus/dbus-misc.c create mode 100644 dbus/dbus-misc.h create mode 100644 dbus/dbus-object-tree.c create mode 100644 dbus/dbus-object-tree.h create mode 100644 dbus/dbus-pending-call-internal.h create mode 100644 dbus/dbus-pending-call.c create mode 100644 dbus/dbus-pending-call.h create mode 100644 dbus/dbus-protocol.h create mode 100644 dbus/dbus-resources.c create mode 100644 dbus/dbus-resources.h create mode 100644 dbus/dbus-server-debug-pipe.c create mode 100644 dbus/dbus-server-debug-pipe.h create mode 100644 dbus/dbus-server-protected.h create mode 100644 dbus/dbus-server-socket.c create mode 100644 dbus/dbus-server-socket.h create mode 100644 dbus/dbus-server-unix.c create mode 100644 dbus/dbus-server-unix.h create mode 100644 dbus/dbus-server.c create mode 100644 dbus/dbus-server.h create mode 100644 dbus/dbus-sha.c create mode 100644 dbus/dbus-sha.h create mode 100644 dbus/dbus-shared.h create mode 100644 dbus/dbus-shell.c create mode 100644 dbus/dbus-shell.h create mode 100644 dbus/dbus-signature.c create mode 100644 dbus/dbus-signature.h create mode 100644 dbus/dbus-spawn.c create mode 100644 dbus/dbus-spawn.h create mode 100644 dbus/dbus-string-private.h create mode 100644 dbus/dbus-string-util.c create mode 100644 dbus/dbus-string.c create mode 100644 dbus/dbus-string.h create mode 100644 dbus/dbus-sysdeps-pthread.c create mode 100644 dbus/dbus-sysdeps-unix.c create mode 100644 dbus/dbus-sysdeps-unix.h create mode 100644 dbus/dbus-sysdeps-util-unix.c create mode 100644 dbus/dbus-sysdeps-util.c create mode 100644 dbus/dbus-sysdeps.c create mode 100644 dbus/dbus-sysdeps.h create mode 100644 dbus/dbus-test-main.c create mode 100644 dbus/dbus-test.c create mode 100644 dbus/dbus-test.h create mode 100644 dbus/dbus-threads-internal.h create mode 100644 dbus/dbus-threads.c create mode 100644 dbus/dbus-threads.h create mode 100644 dbus/dbus-timeout.c create mode 100644 dbus/dbus-timeout.h create mode 100644 dbus/dbus-transport-protected.h create mode 100644 dbus/dbus-transport-socket.c create mode 100644 dbus/dbus-transport-socket.h create mode 100644 dbus/dbus-transport-unix.c create mode 100644 dbus/dbus-transport-unix.h create mode 100644 dbus/dbus-transport.c create mode 100644 dbus/dbus-transport.h create mode 100644 dbus/dbus-types.h create mode 100644 dbus/dbus-userdb-util.c create mode 100644 dbus/dbus-userdb.c create mode 100644 dbus/dbus-userdb.h create mode 100644 dbus/dbus-uuidgen.c create mode 100644 dbus/dbus-uuidgen.h create mode 100644 dbus/dbus-watch.c create mode 100644 dbus/dbus-watch.h create mode 100644 dbus/dbus.h create mode 100755 depcomp create mode 100644 doc/Makefile.am create mode 100644 doc/Makefile.in create mode 100644 doc/TODO create mode 100644 doc/busconfig.dtd create mode 100644 doc/dbus-faq.html create mode 100644 doc/dbus-faq.xml create mode 100644 doc/dbus-specification.html create mode 100644 doc/dbus-specification.xml create mode 100644 doc/dbus-test-plan.html create mode 100644 doc/dbus-test-plan.xml create mode 100644 doc/dbus-tutorial.html create mode 100644 doc/dbus-tutorial.xml create mode 100644 doc/dcop-howto.txt create mode 100644 doc/diagram.png create mode 100644 doc/diagram.svg create mode 100644 doc/file-boilerplate.c create mode 100644 doc/introspect.dtd create mode 100644 doc/introspect.xsl create mode 100644 doc/system-activation.txt create mode 100755 install-sh create mode 100755 ltmain.sh create mode 100755 missing create mode 100644 test/Makefile.am create mode 100644 test/Makefile.in create mode 100644 test/data/auth/anonymous-client-successful.auth-script create mode 100644 test/data/auth/anonymous-server-successful.auth-script create mode 100644 test/data/auth/cancel.auth-script create mode 100644 test/data/auth/client-out-of-mechanisms.auth-script create mode 100644 test/data/auth/external-failed.auth-script create mode 100644 test/data/auth/external-root.auth-script create mode 100644 test/data/auth/external-silly.auth-script create mode 100644 test/data/auth/external-successful.auth-script create mode 100644 test/data/auth/extra-bytes.auth-script create mode 100644 test/data/auth/fail-after-n-attempts.auth-script create mode 100644 test/data/auth/fallback.auth-script create mode 100644 test/data/auth/invalid-command-client.auth-script create mode 100644 test/data/auth/invalid-command.auth-script create mode 100644 test/data/auth/invalid-hex-encoding.auth-script create mode 100644 test/data/auth/mechanisms.auth-script create mode 100644 test/data/equiv-config-files/basic/basic-1.conf create mode 100644 test/data/equiv-config-files/basic/basic-2.conf create mode 100644 test/data/equiv-config-files/basic/basic.d/basic.conf create mode 100644 test/data/equiv-config-files/entities/basic.d/basic.conf create mode 100644 test/data/equiv-config-files/entities/entities-1.conf create mode 100644 test/data/equiv-config-files/entities/entities-2.conf create mode 100644 test/data/incomplete-messages/missing-body.message create mode 100644 test/data/invalid-config-files/badselinux-1.conf create mode 100644 test/data/invalid-config-files/badselinux-2.conf create mode 100644 test/data/invalid-config-files/circular-1.conf create mode 100644 test/data/invalid-config-files/circular-2.conf create mode 100644 test/data/invalid-config-files/circular-3.conf create mode 100644 test/data/invalid-config-files/not-well-formed.conf create mode 100644 test/data/invalid-config-files/truncated-file.conf create mode 100644 test/data/invalid-messages/array-of-nil.message create mode 100644 test/data/invalid-messages/array-with-mixed-types.message create mode 100644 test/data/invalid-messages/bad-boolean-array.message create mode 100644 test/data/invalid-messages/bad-boolean.message create mode 100644 test/data/invalid-messages/bad-endian.message create mode 100644 test/data/invalid-messages/bad-header-field-alignment.message create mode 100644 test/data/invalid-messages/boolean-has-no-value.message-raw create mode 100644 test/data/invalid-messages/local-namespace.message create mode 100644 test/data/invalid-messages/no-dot-in-name.message create mode 100644 test/data/invalid-messages/not-nul-header-padding.message create mode 100644 test/data/invalid-messages/overlong-name.message create mode 100644 test/data/invalid-messages/too-little-header-padding.message create mode 100644 test/data/invalid-messages/too-much-header-padding-by-far.message create mode 100644 test/data/invalid-messages/too-much-header-padding.message create mode 100644 test/data/invalid-messages/too-short-dict.message create mode 100644 test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service create mode 100644 test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in create mode 100644 test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service create mode 100644 test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in create mode 100644 test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service create mode 100644 test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in create mode 100644 test/data/sha-1/Readme.txt create mode 100644 test/data/sha-1/bit-hashes.sha1 create mode 100644 test/data/sha-1/bit-messages.sha1 create mode 100644 test/data/sha-1/byte-hashes.sha1 create mode 100644 test/data/sha-1/byte-messages.sha1 create mode 100644 test/data/valid-config-files-system/debug-allow-all-fail.conf create mode 100644 test/data/valid-config-files-system/debug-allow-all-fail.conf.in create mode 100644 test/data/valid-config-files-system/debug-allow-all-pass.conf create mode 100644 test/data/valid-config-files-system/debug-allow-all-pass.conf.in create mode 100644 test/data/valid-config-files/basic.conf create mode 100644 test/data/valid-config-files/basic.d/basic.conf create mode 100644 test/data/valid-config-files/debug-allow-all-sha1.conf create mode 100644 test/data/valid-config-files/debug-allow-all-sha1.conf.in create mode 100644 test/data/valid-config-files/debug-allow-all.conf create mode 100644 test/data/valid-config-files/debug-allow-all.conf.in create mode 100644 test/data/valid-config-files/entities.conf create mode 100644 test/data/valid-config-files/many-rules.conf create mode 100644 test/data/valid-config-files/session.conf create mode 100644 test/data/valid-config-files/system.conf create mode 100644 test/data/valid-config-files/system.d/test.conf create mode 100644 test/data/valid-messages/array-of-array-of-uint32.message create mode 100644 test/data/valid-messages/dict-simple.message create mode 100644 test/data/valid-messages/dict.message create mode 100644 test/data/valid-messages/emptiness.message create mode 100644 test/data/valid-messages/lots-of-arguments.message create mode 100644 test/data/valid-messages/no-padding.message create mode 100644 test/data/valid-messages/opposite-endian.message create mode 100644 test/data/valid-messages/recursive-types.message create mode 100644 test/data/valid-messages/simplest-manual.message create mode 100644 test/data/valid-messages/simplest.message create mode 100644 test/data/valid-messages/standard-acquire-service.message create mode 100644 test/data/valid-messages/standard-hello.message create mode 100644 test/data/valid-messages/standard-list-services.message create mode 100644 test/data/valid-messages/standard-service-exists.message create mode 100644 test/data/valid-messages/unknown-header-field.message create mode 100644 test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service create mode 100644 test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in create mode 100644 test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service create mode 100644 test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in create mode 100644 test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service create mode 100644 test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in create mode 100644 test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service create mode 100644 test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in create mode 100644 test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service create mode 100644 test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in create mode 100644 test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service create mode 100644 test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in create mode 100644 test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service create mode 100644 test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in create mode 100644 test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service create mode 100644 test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in create mode 100644 test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service create mode 100644 test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in create mode 100644 test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service create mode 100644 test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in create mode 100644 test/decode-gcov.c create mode 100644 test/name-test/Makefile.am create mode 100644 test/name-test/Makefile.in create mode 100755 test/name-test/run-test-systemserver.sh create mode 100755 test/name-test/run-test.sh create mode 100644 test/name-test/run-with-tmp-session-bus.conf create mode 100644 test/name-test/test-activation-forking.py create mode 100644 test/name-test/test-ids.c create mode 100644 test/name-test/test-pending-call-dispatch.c create mode 100644 test/name-test/test-pending-call-timeout.c create mode 100644 test/name-test/test-privserver-client.c create mode 100644 test/name-test/test-privserver.c create mode 100644 test/name-test/test-shutdown.c create mode 100644 test/name-test/test-threads-init.c create mode 100755 test/name-test/test-wait-for-echo.py create mode 100644 test/name-test/tmp-session-like-system.conf create mode 100644 test/shell-test.c create mode 100644 test/spawn-test.c create mode 100644 test/test-exit.c create mode 100644 test/test-names.c create mode 100644 test/test-segfault.c create mode 100644 test/test-service.c create mode 100644 test/test-shell-service.c create mode 100644 test/test-sleep-forever.c create mode 100644 test/test-utils.c create mode 100644 test/test-utils.h create mode 100644 tools/Makefile.am create mode 100644 tools/Makefile.in create mode 100644 tools/dbus-cleanup-sockets.1 create mode 100644 tools/dbus-cleanup-sockets.c create mode 100644 tools/dbus-launch-x11.c create mode 100644 tools/dbus-launch.1 create mode 100644 tools/dbus-launch.c create mode 100644 tools/dbus-launch.h create mode 100644 tools/dbus-monitor.1 create mode 100644 tools/dbus-monitor.c create mode 100644 tools/dbus-print-message.c create mode 100644 tools/dbus-print-message.h create mode 100644 tools/dbus-send.1 create mode 100644 tools/dbus-send.c create mode 100644 tools/dbus-uuidgen.1 create mode 100644 tools/dbus-uuidgen.c create mode 100755 tools/run-with-tmp-session-bus.sh diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..f295d6f1 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,64 @@ +Olivier Andrieu +Jonas B +Waldo Bastian +Daniel P. Berrange +Philip Blundell +Ross Burton +Carlos Garcia Campos +Brian Cameron +Anders Carlsson +Frederic Crozat +Christian Ehrlicher +Harald Fernengel +Owen Fraser-Green +Peter O'Gorman +Jens Granseuer +Ralf Habacker +Mikael Hallendal +Kimmo Hämäläinen +Magnus Henoch +Kristian Høgsberg +Iain Holmes +Richard Hughes +Richard Hult +Peter Kuemmel +Alex Larsson +Bernard Leak +Tor Lillqvist +Ryan Lortie +Andrea Luzzardi +Marcelo Ricardo Leitner +Thiago Macieira +Kjartan Maraas +Mark McLoughlin +Robert McQueen +Michael Meeks +Dave Meikle +Rodrigo Moya +Seth Nickell +Benjamin Otte +John (J5) Palmieri +Tom Parker +Havoc Pennington +Frederic Peters +Andras Porjesz +Harri Porten +Marco Pracucci +Timothy Redaelli +Benjamin Reed +Daniel Reed +Matthew Rickard +Kristian Rietveld +Zack Rusin +Olli Salli +Joe Shaw +Kay Sievers +Sjoerd Simons +Ray Strode +Alp Toker +Jon Trowbridge +Miloslav Trmac +Julio M. Merino Vidal +Colin Walters +James Willcox +David Zeuthen diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..8260b100 --- /dev/null +++ b/COPYING @@ -0,0 +1,552 @@ +D-Bus is licensed to you under your choice of the Academic Free +License version 2.1, or the GNU General Public License version 2 +(or, at your option any later version). + +Both licenses are included here. Some of the standalone binaries are +under the GPL only; in particular, but not limited to, +tools/dbus-cleanup-sockets.c and test/decode-gcov.c. Each source code +file is marked with the proper copyright information - if you find a +file that isn't marked please bring it to our attention. + +The Academic Free License +v. 2.1 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following notice immediately following the copyright notice for the Original Work: + +Licensed under the Academic Free License version 2.1 + +1) Grant of Copyright License. Licensor hereby grants You a +world-wide, royalty-free, non-exclusive, perpetual, sublicenseable +license to do the following: + +a) to reproduce the Original Work in copies; + +b) to prepare derivative works ("Derivative Works") based upon the Original Work; + +c) to distribute copies of the Original Work and Derivative Works to the public; + +d) to perform the Original Work publicly; and + +e) to display the Original Work publicly. + +2) Grant of Patent License. Licensor hereby grants You a world-wide, +royalty-free, non-exclusive, perpetual, sublicenseable license, under +patent claims owned or controlled by the Licensor that are embodied in +the Original Work as furnished by the Licensor, to make, use, sell and +offer for sale the Original Work and Derivative Works. + +3) Grant of Source Code License. The term "Source Code" means the +preferred form of the Original Work for making modifications to it and +all available documentation describing how to modify the Original +Work. Licensor hereby agrees to provide a machine-readable copy of the +Source Code of the Original Work along with each copy of the Original +Work that Licensor distributes. Licensor reserves the right to satisfy +this obligation by placing a machine-readable copy of the Source Code +in an information repository reasonably calculated to permit +inexpensive and convenient access by You for as long as Licensor +continues to distribute the Original Work, and by publishing the +address of that information repository in a notice immediately +following the copyright notice that applies to the Original Work. + +4) Exclusions From License Grant. Neither the names of Licensor, nor +the names of any contributors to the Original Work, nor any of their +trademarks or service marks, may be used to endorse or promote +products derived from this Original Work without express prior written +permission of the Licensor. Nothing in this License shall be deemed to +grant any rights to trademarks, copyrights, patents, trade secrets or +any other intellectual property of Licensor except as expressly stated +herein. No patent license is granted to make, use, sell or offer to +sell embodiments of any patent claims other than the licensed claims +defined in Section 2. No right is granted to the trademarks of +Licensor even if such marks are included in the Original Work. Nothing +in this License shall be interpreted to prohibit Licensor from +licensing under different terms from this License any Original Work +that Licensor otherwise would have a right to license. + +5) This section intentionally omitted. + +6) Attribution Rights. You must retain, in the Source Code of any +Derivative Works that You create, all copyright, patent or trademark +notices from the Source Code of the Original Work, as well as any +notices of licensing and any descriptive text identified therein as an +"Attribution Notice." You must cause the Source Code for any +Derivative Works that You create to carry a prominent Attribution +Notice reasonably calculated to inform recipients that You have +modified the Original Work. + +7) Warranty of Provenance and Disclaimer of Warranty. Licensor +warrants that the copyright in and to the Original Work and the patent +rights granted herein by Licensor are owned by the Licensor or are +sublicensed to You under the terms of this License with the permission +of the contributor(s) of those copyrights and patent rights. Except as +expressly stated in the immediately proceeding sentence, the Original +Work is provided under this License on an "AS IS" BASIS and WITHOUT +WARRANTY, either express or implied, including, without limitation, +the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL +WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential +part of this License. No license to Original Work is granted hereunder +except under this disclaimer. + +8) Limitation of Liability. Under no circumstances and under no legal +theory, whether in tort (including negligence), contract, or +otherwise, shall the Licensor be liable to any person for any direct, +indirect, special, incidental, or consequential damages of any +character arising as a result of this License or the use of the +Original Work including, without limitation, damages for loss of +goodwill, work stoppage, computer failure or malfunction, or any and +all other commercial damages or losses. This limitation of liability +shall not apply to liability for death or personal injury resulting +from Licensor's negligence to the extent applicable law prohibits such +limitation. Some jurisdictions do not allow the exclusion or +limitation of incidental or consequential damages, so this exclusion +and limitation may not apply to You. + +9) Acceptance and Termination. If You distribute copies of the +Original Work or a Derivative Work, You must make a reasonable effort +under the circumstances to obtain the express assent of recipients to +the terms of this License. Nothing else but this License (or another +written agreement between Licensor and You) grants You permission to +create Derivative Works based upon the Original Work or to exercise +any of the rights granted in Section 1 herein, and any attempt to do +so except under the terms of this License (or another written +agreement between Licensor and You) is expressly prohibited by +U.S. copyright law, the equivalent laws of other countries, and by +international treaty. Therefore, by exercising any of the rights +granted to You in Section 1 herein, You indicate Your acceptance of +this License and all of its terms and conditions. + +10) Termination for Patent Action. This License shall terminate +automatically and You may no longer exercise any of the rights granted +to You by this License as of the date You commence an action, +including a cross-claim or counterclaim, against Licensor or any +licensee alleging that the Original Work infringes a patent. This +termination provision shall not apply for an action alleging patent +infringement by combinations of the Original Work with other software +or hardware. + +11) Jurisdiction, Venue and Governing Law. Any action or suit relating +to this License may be brought only in the courts of a jurisdiction +wherein the Licensor resides or in which Licensor conducts its primary +business, and under the laws of that jurisdiction excluding its +conflict-of-law provisions. The application of the United Nations +Convention on Contracts for the International Sale of Goods is +expressly excluded. Any use of the Original Work outside the scope of +this License or after its termination shall be subject to the +requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 +et seq., the equivalent laws of other countries, and international +treaty. This section shall survive the termination of this License. + +12) Attorneys Fees. In any action to enforce the terms of this License +or seeking damages relating thereto, the prevailing party shall be +entitled to recover its costs and expenses, including, without +limitation, reasonable attorneys' fees and costs incurred in +connection with such action, including any appeal of such action. This +section shall survive the termination of this License. + +13) Miscellaneous. This License represents the complete agreement +concerning the subject matter hereof. If any provision of this License +is held to be unenforceable, such provision shall be reformed only to +the extent necessary to make it enforceable. + +14) Definition of "You" in This License. "You" throughout this +License, whether in upper or lower case, means an individual or a +legal entity exercising rights under, and complying with all of the +terms of, this License. For legal entities, "You" includes any entity +that controls, is controlled by, or is under common control with +you. For purposes of this definition, "control" means (i) the power, +direct or indirect, to cause the direction or management of such +entity, whether by contract or otherwise, or (ii) ownership of fifty +percent (50%) or more of the outstanding shares, or (iii) beneficial +ownership of such entity. + +15) Right to Use. You may use the Original Work in all ways not +otherwise restricted or conditioned by this License or by law, and +Licensor promises not to interfere with or be responsible for such +uses by You. + +This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights +reserved. Permission is hereby granted to copy and distribute this +license without modification. This license may not be modified without +the express written permission of its copyright owner. + + +-- +END OF ACADEMIC FREE LICENSE. The following is intended to describe the essential +differences between the Academic Free License (AFL) version 1.0 and other +open source licenses: + +The Academic Free License is similar to the BSD, MIT, UoI/NCSA and Apache +licenses in many respects but it is intended to solve a few problems with +those licenses. + +* The AFL is written so as to make it clear what software is being +licensed (by the inclusion of a statement following the copyright notice +in the software). This way, the license functions better than a template +license. The BSD, MIT and UoI/NCSA licenses apply to unidentified software. + +* The AFL contains a complete copyright grant to the software. The BSD +and Apache licenses are vague and incomplete in that respect. + +* The AFL contains a complete patent grant to the software. The BSD, MIT, +UoI/NCSA and Apache licenses rely on an implied patent license and contain +no explicit patent grant. + +* The AFL makes it clear that no trademark rights are granted to the +licensor's trademarks. The Apache license contains such a provision, but the +BSD, MIT and UoI/NCSA licenses do not. + +* The AFL includes the warranty by the licensor that it either owns the +copyright or that it is distributing the software under a license. None of +the other licenses contain that warranty. All other warranties are disclaimed, +as is the case for the other licenses. + +* The AFL is itself copyrighted (with the right granted to copy and distribute +without modification). This ensures that the owner of the copyright to the +license will control changes. The Apache license contains a copyright notice, +but the BSD, MIT and UoI/NCSA licenses do not. +-- +START OF GNU GENERAL PUBLIC LICENSE +-- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..0bc33d45 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,5 @@ +2008-04-16 John (J5) Palmieri + + * tools/dbus-monitor.c: take out the trailing comma in the + ProfileAttributeFlags enum as it isn't in our style guides + and causes some compilers to error out diff --git a/ChangeLog.pre-1-0 b/ChangeLog.pre-1-0 new file mode 100644 index 00000000..eab5982f --- /dev/null +++ b/ChangeLog.pre-1-0 @@ -0,0 +1,15146 @@ +2006-11-09 John (J5) Palmieri + + * Released 1.0.0 + +2006-11-09 John (J5) Palmieri + + * AUTHORS: added Peter and Tor of windows porting fame + +2006-11-08 Havoc Pennington + + * doc/dbus-specification.xml: add a note about protocol stability + + * doc/TODO: Remove "important for 1.0" section, replace with + "important for 1.2" section + +2006-11-08 John (J5) Palmieri + + * README: remove some of the out of date flags + + * doc/TODO: Remove todo items which are done + +2006-11-08 John (J5) Palmieri + + * tools/dbus-monitor.c: Handle sigint so we flush stdout + (Patch from Olli Salli ) + +2006-11-08 John (J5) Palmieri + + * tools/dbus-monitor.1: update the manpage for dbus-monitor + (Patch from Olli Salli ) + +2006-11-08 John (J5) Palmieri + + * AUTHORS: Update with all people listed in the ChangeLog + +2006-11-08 John (J5) Palmieri + + * tools/dbus-monitor.c: add profiling tools to dbus-monitor + (Patch from Olli Salli ) + +2006-11-07 Havoc Pennington + + * HACKING: Update release instructions to include stuff about + stable releases, branching, etc. May not be totally correct, + please fix if needed, but keep instructions up-to-date so we do + each stable release consistently in the future. + +2006-11-07 Havoc Pennington + + * doc/dbus-specification.xml, doc/dbus-faq.xml, README: various + documentation updates. Bump faq/spec versions (not to 1.0; I don't + think the spec will be "finished"/1.0 when we ship the 1.0 library). + +2006-11-06 John (J5) Palmieri + + * bus/bus.c: Missed patch - pass in the context to the directory watch + +2006-11-02 John (J5) Palmieri + + * Released D-Bus 1.0 RC 3(0.95) + +2006-11-02 John (J5) Palmieri + + * bus/activation.c (bus_activation_new): don't fail if we can not read + the directory as it may not exist + +2006-11-02 John (J5) Palmieri + + * bus/config-parser.c (service_dirs_find_dir): use + _dbus_list_get_next_link so we don't get stuck in an infinite loop + (start_busconfig_child): move processing of standard_session_servicedirs + tags here because they have no content + (bus_config_parser_content): check we don't have content in + standard_session_servicedirs tag + +2006-11-02 John (J5) Palmieri + + * tools/Makefile.am: Make sure the /var/lib/dbus directory is created + Packagers need to own this directory + +2006-11-02 John (J5) Palmieri + + * tools/run-with-tmp-session-bus.sh: fixed script to replace the + tag with a tag that + points to the test service directory + +2006-11-02 John (J5) Palmieri + + * configure.in: Add a check for DIR *dirp->dd_fd + + * dbus/dbus-sysdeps-util-unix: if HAVE_DDFD is defined use + DIR *dirp->dd_fd else use DIR *dirp->__dd_fd. This takes care + of both Solaris and Irix + +2006-11-01 Havoc Pennington + + * bus/dbus-daemon.1.in: document standard_session_servicedirs + +2006-11-01 John (J5) Palmieri + + * configure.in: expose DBUS_DATADIR + + * bus/config-parser.c: add the standard_session_servicedirs element + to the parser + (bus_config_parser_content): process the standard_session_servicedirs + element by getting the standard directories from sysdeps and merging + them into the service directory list + (test_default_session_servicedirs): make sure we get what we expect + + * bus/session.conf.in: replace the servicedir tag with the + standard_session_servicedirs tag + + * dbus/dbus-list.h: remove the typedef of DBusList and place it in + dbus-sysdeps.h to avoid circular header dependencies + + * dbus/dbus-sysdeps.h: add the typedef of DBusList + + * dbus/dbus-sysdeps-unix.c (split_paths_and_append): utility function + which takes a string of directories delimited by colons, parses them + out, appends a suffix and puts them in a list ignoring empty elements + (_dbus_get_standard_session_servicedirs): returns the standard + directories for a session bus to look for service activation files + on Unix which includes the XDG_DATA_HOME, XDG_DATA_DIRS and + DBUS_DATADIR directories + + * test/data/valid-config-files/many-rules.conf: add the + standard_session_servicedirs tag to the valid config file tests + +2006-10-30 Havoc Pennington + + * tools/dbus-launch.1, doc/TODO: capture intent to change the + command line options of dbus-launch a bit post 1.0 + +2006-10-27 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_open_private): document + how to choose shared vs. private connections + +2006-10-27 Havoc Pennington + + * dbus/dbus-test.c: enclose more of the file in the + DBUS_BUILD_TESTS check. + + * dbus/dbus-sysdeps-pthread.c (PTHREAD_CHECK): fix for + DBUS_DISABLE_ASSERT case. + + * dbus/dbus-connection.c (dbus_connection_get_unix_user): document + that it only works on the server side + + * dbus/dbus-bus.c: add a global lock covering the BusData we + attach to each connection + (internal_bus_get): lock our access to the BusData + (dbus_bus_register): lock the entire registration process + with _DBUS_LOCK(bus_datas). If we get the lock and + registration is already complete, silently return (vs. previous + behavior of aborting). + (dbus_bus_set_unique_name): lock the BusData + (dbus_bus_get_unique_name): lock the BusData + +2006-10-27 John (J5) Palmieri + + * bus/config-parser.c (service_dirs_find_dir, + service_dirs_append_unique_or_free, + service_dirs_append_link_unique_or_free): New static methods + for only appending unique service directory names into + the service directory list + (merge_included, bus_config_parser_content): Only add unique + service directory names into the list + +2006-10-27 Havoc Pennington + + * dbus/dbus-sysdeps-pthread.c: make the "count" and "holder" + variables volatile, suggested by Thiago. Document struct fields. + (PTHREAD_CHECK): remove pthread error checking if assertions are + disabled, should reduce the no-assertions case to the bare + minimum code. + +2006-10-26 Havoc Pennington + + * dbus/dbus-sysdeps-pthread.c (_dbus_pthread_mutex_lock): change + to be recursive + (_dbus_pthread_mutex_unlock): make it recursive + (_dbus_pthread_condvar_wait): save/restore the recursion count + (_dbus_pthread_condvar_wait_timeout): save/restore the recursion count + +2006-10-26 Havoc Pennington + + * doc/dbus-specification.xml: clarify the UUID text slightly + + * dbus/dbus-sysdeps-pthread.c: check for and mostly abort on + pthread errors. Add DBusMutexPThread and DBusCondVarPThread + in preparation for being able to extend them for e.g. recursive + mutexes. + +2006-10-26 Havoc Pennington + + * dbus/dbus-threads.[hc]: Documentation improvements. Clarify how + condition variables relate to recursive mutexes. + + * dbus/dbus-sysdeps-pthread.c, dbus/dbus-sysdeps-win-thread.c, + dbus/dbus-threads.c: Split the platforms-specific thread + implementations into their own files. + + * dbus/dbus-sysdeps-pthread.c + (_dbus_pthread_condvar_wait_timeout): invert the return value, it + was backward. Not that anything uses it. + +2006-10-26 John (J5) Palmieri + + * dbus-sysdeps-unix.c (_dbus_set_local_creds): Clean up the + LOCAL_CREDS vs CMSGCRED stuff a bit. Prefer CMSGCRED. This + needs to be cleaned up more. + + * doc/TODO: Add a todo that *BSD hackers should look at cleaning + up the CREDS issue. + +2006-10-26 John (J5) Palmieri + + * configure.in, dbus-1.pc.in: Check to see if thread methods + are in glibc or libpthread and add -lpthread to the link stage + if it is the latter + +2006-10-26 Thiago Macieira + + * dbus/dbus-connection.c (_dbus_connection_open_internal): Fix + bug 8780: the connection lock is only required while recording + the shared connection, so protect only that code + section. Don't require connection_lookup_shared to return a + locked connection. + +2006-10-26 Thiago Macieira + + * tools/dbus-launch-x11.c (get_session_file, init_x_atoms): + check if get_machine_uuid() returns NULL before proceeding any + further: we can't init the X atoms or create a session file + name if there is no machine ID. + This solves a crash reported by some users if + --exit-with-session was used without --autolaunch= + +2006-10-26 John (J5) Palmieri + + * tools/dbus-launch.c (main): run the dbus-daemon in the builddir + if tests are enabled and the DBUS_USE_TEST_BINARY env variable is set + + * tools/run-with-tmp-session-bus.sh: set DBUS_USE_TEST_BINARY + before we run dbus-launch + + * configure.in: define TEST_BUS_BINARY to be the full path to + dbus-daemon in the build root + +2006-10-25 Sjoerd Simons + + * dbus/Makefile.am: + * tools/Makefile.am: + * toos/dbus-uuidgen.1: + Move the machine-id file to /var/lib/dbus + +2006-10-24 David Zeuthen + + * dbus/dbus-threads.c (init_uninitialized_locks): Fix typo so it's + _dbus_assert (thread_init_generation != _dbus_current_generation) + not _dbus_assert (thread_init_generation == _dbus_current_generation) + +2006-10-24 Thiago Macieira + + * dbus/dbus-sysdeps.h: + * dbus/dbus-sysdeps-unix.c: Add function + _dbus_make_file_world_readable that chmods a file to 0644. + + * dbus/dbus-sysdeps-unix.c (_dbus_get_autolaunch_address): + Avoid writing to the static "argv" array, thereby avoiding a + COW on the child process. + + * dbus/dbus-internals.c (_dbus_create_uuid_file_exclusively): + call _dbus_make_file_world_readable on the created file. + +2006-10-23 David Zeuthen + + * dbus/dbus-memory.c: Use atomic variable to protect + n_blocks_outstanding otherwise OOM will be reported using SMP on + some arches + + * bus/dispatch.c: Add missing end of line characters + + * bus/desktop-file.c (parse_section_start, parse_key_value) + (bus_desktop_file_load): Propertly handle OOM + + * dbus/dbus-threads.c (init_uninitialized_locks): Check that + thread_init_generation equals _dbus_current_generation, not 0 + +2006-10-22 Havoc Pennington + + * dbus/dbus-connection-internal.h: move prototype of + _dbus_bus_notify_shared_connection_disconnected_unlocked() here so + it isn't in a public header and doesn't end up in the DBusBus + group in Doxygen + +2006-10-21 Havoc Pennington + + * Makefile.am (EXTRA_DIST): dist cleanup-man-pages.sh so it's in + the tarball if packagers want to run it + + * cleanup-man-pages.sh: Add a script which munges all the internal + API man pages out of the Doxygen output. This reduces the size of + the installed man pages from 7 to 2 megs, and avoids + namespace-polluting pages. Right now (like Doxygen) this script + isn't in the build, it's something packagers can do manually. + +2006-10-21 Havoc Pennington + + * dbus/dbus-connection.h: don't include the watch/timeout + functions in connection section + +2006-10-21 Havoc Pennington + + * Documentation! Whee! Doxygen now 100% silent. If you make it + angry again, you will be punished. + +2006-10-21 Havoc Pennington + + * More documentation - all public API now documented according to + Doxygen + +2006-10-21 Havoc Pennington + + * Document a bunch of undocumented stuff + +2006-10-21 Havoc Pennington + + * Clean up Doxygen group markers for public API so Doxygen finds + everything (not comprehensively fixed for private API). + Means all remaining Doxygen warnings are just about missing docs + and thus pretty simple to resolve. + +2006-10-21 Havoc Pennington + + * dbus/dbus-macros.h: add DBUS_GNUC_DEPRECATED macro + + * dbus/dbus-message.h: mark dbus_message_iter_get_array_len() + as DBUS_GNUC_DEPRECATED + +2006-10-21 Havoc Pennington + + * Move all private API into the private Doxygen group sections of + the files, so they don't show up in the public API docs + +2006-10-21 Havoc Pennington + + * dbus/dbus-message.h: put #ifndef DBUS_DISABLE_DEPRECATED around + dbus_message_iter_get_array_len(). + + * throughout: documentation improvements. + +2006-10-20 Havoc Pennington + + * doc/TODO: remove the int64 thing from 1.0 since it doesn't + matter, and the message-loader-breaker thing since nobody is going + to do it. Add an item to 1.0 about supporting recursive locks + in dbus_threads_init_default() though, since it should be easy. + + * dbus/dbus-connection.c (_dbus_connection_read_write_dispatch): + Fix this in the !dispatch case to avoid busy-looping after + disconnection + + * More misc docs improvements + +2006-10-19 Havoc Pennington + + * more Doxygen-related fixes (lots of moving things from the + public to internal section in dbus-connection.c) + +2006-10-19 Havoc Pennington + + * Fix a pile of Doxygen warnings and missing docs + +2006-10-19 John (J5) Palmieri + + * bus/dir-watch-default.c, bus/dir-watch-dnotify.c, + bus/dir-watch-kqueue.c (bus_watch_directory): Pass in a BusContext + instead of a void *. kqueue uses this to get the context's loop + while the other modules ignore the parameter. This allows us to + avoid platform conditionals + + * bus/bus.c (process_config_postinit): Pass in the context to the + watch + +2006-10-19 John (J5) Palmieri + + * bus/messagebus.in, bus/rc.messagebus.in: run dbus-uuidgen --ensure + when starting the system bus + +2006-10-18 John (J5) Palmieri + + * configure.in: More fixups for cross compile (Patch from + Marco Pracucci ) + +2006-10-17 Havoc Pennington + + * tools/dbus-send.c (main): don't close shared connection, fix + from Timo Hoenig + +2006-10-17 Havoc Pennington + + * configure.in (CPPFLAGS): don't do -DDBUS_API_SUBJECT_TO_CHANGE here + + * dbus/dbus.h: drop the DBUS_API_SUBJECT_TO_CHANGE requirement, + since realistically it doesn't look like we'll be changing it + anymore. + +2006-10-17 Havoc Pennington + + * dbus/dbus-internals.c (_dbus_warn_check_failed): new function to + be used for return_if_fail type warnings; prefixes the pid, and + fatal by default. + +2006-10-14 John (J5) Palmieri + + * configure.in: Released 1.0 RC 2(0.94) + Add check for -fPIC and enable it if available + +2006-10-14 John (J5) Palmieri + + * doc/TODO: Remove the check TODO item + +2006-10-13 John (J5) Palmieri + + * dbus-transport-socket.c (exchange_credentials): + Print out more detailed errors if reading or sending + credentials fail (Patch from Julio M. Merino Vidal + ) + +2006-10-13 John (J5) Palmieri + + * configure.in: when checking for posix getpwnam_r assume true + for cross compiles + +2006-10-13 John (J5) Palmieri + + * configure.in: Check for gethostbyname first before we check for it + in libnsl. On gnu systems it is implemeneted + +2006-10-13 Havoc Pennington + + * dbus/dbus-connection.c + (dbus_connection_send_with_reply_and_block): fix to handle closed + connections, from Tambet Ingo bug #8631 + +2006-10-11 John (J5) Palmieri + + * configure.in: use AC_TRY_COMPILE for dirfd instead of AC_TRY_RUN + +2006-10-11 John (J5) Palmieri + + * test/name-test/Makefile.am: don't link against both libdbus and + libdbus-convenience + +2006-10-11 John (J5) Palmieri + + * configure.in: check for dirfd even if it is a macro + (Patch from Timothy Redaelli ) + +2006-10-08 John (J5) Palmieri + + * configure.in: define _POSIX_PTHREAD_SEMANTICS on solaris + avoid using dirfd on systems that don't have dirfd + (Patch by Brian Cameron ) + +2006-10-02 John (J5) Palmieir + + * dbus/dbus-sysdeps.c (_dbus_abort): Remove from + #ifndef DBUS_DISABLE_ASSERTS macro to fix distcheck + + * dbus/dbus-sysdeps-unix.c (_dbus_print_backtrace): Remove from + #if !defined (DBUS_DISABLE_ASSERT) || defined(DBUS_BUILD_TESTS) + macro because _dbus_abort calls it + + * tools/Makefile.am: Add dbus-launch.h to the source list so distcheck + works + +2006-10-02 John (J5) Palmieir + + * dbus/dbus-sysdeps-util-unix.c (dirent_buf_size): Add check for + MAXNAMELEN for Mac OSX. (Patch from Jonas B ) + +2006-10-02 Thiago Macieira + + * tools/dbus-launch.c (main): make it complain and abort + execution in case an unknown option is given. Also, process + the '--' argument as the end of arguments. + +2006-10-01 Havoc Pennington + + * tools/dbus-launch.c (print_variables): if no syntax is given, + don't print something that's sort-of-half-sh-syntax, just print + a plain key-value pairs thing. + + * tools/dbus-launch-x11.c: use machine ID rather than hostname for + the local machine representation (but still have the hostname in + the display). Remove the hostname from the display if it is + localhost. Change session files to be named + ~/.dbus/session-bus/machine-display. Change X atoms to be + underscore-prefixed so nobody whines about ICCCM compliance. + Otherwise name them the same as the env variables. + Change session file format to include key-value pairs and an + explanatory comment. Keys are the same as the env variables. + (set_address_in_x11): X property format can't depend on + sizeof(pid_t) on a particular machine, fix to always be 32 bits + + * tools/dbus-launch.c: make --autolaunch take a machine id + argument. If --autolaunch is used with a program to run, complain + for now (but add a FIXME). Also, don't look for existing bus if + there's a program to run (but add a FIXME). + + * dbus/dbus-sysdeps-unix.c (_dbus_get_autolaunch_address): pass + machine uuid to dbus-launch (avoids linking dbus-launch to libdbus + just to get this, and avoids duplicating uuid-reading code). + + * tools/dbus-launch.1: clarify various things + +2006-10-01 Havoc Pennington + + * test/test-service.c (path_message_func): remove broken extra + unref that was hidden by the bugs in dbus-connection.c/dbus-bus.c + + * test/test-shell-service.c (path_message_func): same fix + + * dbus/dbus-connection.c + (_dbus_connection_get_dispatch_status_unlocked): break up the + function a little for clarity and fix the notification of + dbus-bus.c to not require dispatch to be complete + + * dbus/dbus-connection.c (dbus_connection_unref): improve the + warning when you try to finalize an open connection. + +2006-10-01 Havoc Pennington + + * dbus/dbus-bus.c + (internal_bus_get): only weak ref the connection; this means + _dbus_bus_notify_shared_connection_disconnected_unlocked can be + called safely in any context + (_dbus_bus_notify_shared_connection_disconnected_unlocked): don't + unref + + * dbus/dbus-connection.c + (_dbus_connection_get_dispatch_status_unlocked): move + _dbus_bus_notify_shared_connection_disconnected_unlocked here + when queuing Disconnected instead of when the Disconnected message + arrives, so dbus_bus_get() won't return closed connections. + +2006-10-01 Havoc Pennington + + * dbus/dbus-connection.c (_dbus_connection_close_if_only_one_ref): + Add a hack to make DBusNewConnectionFunction work right. + + * dbus/dbus-server-socket.c (handle_new_client_fd_and_unlock): use + the hack here. Also, fix the todo about refcount leak. + + * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new): + and use the hack here + + * dbus/dbus-connection.c: Kill the "shared" flag vs. the + "shareable" flag; this was completely broken, since it meant + dbus_connection_open() returned a connection of unknown + shared-ness. Now, we always hold a ref on anything opened + as shareable. + + Move the call to notify dbus-bus.c into + connection_forget_shared_unlocked, so libdbus consistently forgets + all its knowledge of a connection at once. This exposed numerous + places where things were totally broken if we dropped a ref inside + get_dispatch_status_unlocked where + connection_forget_shared_unlocked was previously, so move + connection_forget_shared_unlocked into + _dbus_connection_update_dispatch_status_and_unlock. Also move the + exit_on_disconnect here. + + (shared_connections_shutdown): this assumed weak refs to the + shared connections; since we have strong refs now, the assertion + was failing and stuff was left in the hash. Fix it to close + still-open shared connections. + + * bus/dispatch.c: fixup to use dbus_connection_open_private on the + debug pipe connections + + * dbus/dbus-connection.c (dbus_connection_dispatch): only notify + dbus-bus.c if the closed connection is in fact shared + (_dbus_connection_close_possibly_shared): rename from + _dbus_connection_close_internal + (dbus_connection_close, dbus_connection_open, + dbus_connection_open_private): Improve docs to explain the deal + with when you should close or unref or both + + * dbus/dbus-bus.c + (_dbus_bus_notify_shared_connection_disconnected_unlocked): rename + from _dbus_bus_check_connection_and_unref_unlocked and modify to + loop over all connections + + * test/test-utils.c (test_connection_shutdown): don't try to close + shared connections. + + * test/name-test/test-threads-init.c (main): fix warnings in here + + * dbus/dbus-sysdeps.c (_dbus_abort): support DBUS_BLOCK_ON_ABORT + env variable to cause blocking waiting for gdb; drop + DBUS_PRINT_BACKTRACE and just call _dbus_print_backtrace() + unconditionally. + + * configure.in: add -export-dynamic to libtool flags if assertions enabled + so _dbus_print_backtrace works. + + * dbus/dbus-sysdeps-unix.c (_dbus_print_backtrace): use fprintf + instead of _dbus_verbose to print the backtrace, and diagnose lack + of -rdynamic/-export-dynamic + +2006-09-30 Havoc Pennington + + * dbus/dbus-bus.c (dbus_bus_get_private, dbus_bus_get) + (internal_bus_get): fix screwy code formatting. whoever committed + that was not paying attention! + +2006-09-30 Havoc Pennington + + * configure.in (LT_CURRENT, LT_AGE): increment current and age to + reflect addition of interfaces. + + * doc/dbus-specification.xml: describe a new + org.freedesktop.DBus.Peer.GetMachineId method + + * dbus/dbus-string.c (_dbus_string_skip_white_reverse): new function + (_dbus_string_skip_white, _dbus_string_skip_blank): use new + DBUS_IS_ASCII_BLANK, DBUS_IS_ASCII_WHITE macros and fix assertion + at end of skip_white + (_dbus_string_chop_white): new function + + * bus/connection.c (bus_connections_setup_connection): call + dbus_connection_set_route_peer_messages. + + * dbus/dbus-connection.c + (_dbus_connection_peer_filter_unlocked_no_update): modify to + support a GetMachineId method. + + Also, support a new flag to let the bus pass peer methods through + to apps on the bus, which can be set with + dbus_connection_set_route_peer_messages. + + Finally, handle and return an error for anything unknown on the + Peer interface, which will allow us to extend the Peer interface + in the future without fear that we're now intercepting something + apps were wanting to see. + + * tools/dbus-uuidgen.c: a thin wrapper around the functions in + dbus/dbus-uuidgen.c + + * dbus/dbus-uuidgen.c: implement the bulk of the dbus-uuidgen + binary here, since most of the code is already in libdbus + + * dbus/dbus-sysdeps.c (_dbus_read_local_machine_uuid): read the + uuid from the system config file + + * dbus/dbus-internals.c (_dbus_generate_uuid, _dbus_uuid_encode) + (_dbus_read_uuid_file_without_creating) + (_dbus_create_uuid_file_exclusively, _dbus_read_uuid_file): new + uuid-related functions, partly factored out from dbus-server.c + + * dbus/dbus-sysdeps.c (_dbus_error_from_errno): convert EEXIST to + DBUS_ERROR_FILE_EXISTS instead of EEXIST + + * dbus/dbus-protocol.h (DBUS_ERROR_FILE_EXISTS): add file exists error + + * tools/dbus-cleanup-sockets.1: explain what the point of this + thing is a bit more + + * autogen.sh (run_configure): add --config-cache to default + configure args + + * dbus/dbus-internals.h (_DBUS_ASSERT_ERROR_IS_SET): disable the + error set/clear assertions when DBUS_DISABLE_CHECKS is defined + + * tools/dbus-launch.c (main): if xdisplay hasn't been opened, + don't try to save address, fixes crash in make check + +2006-09-30 Thiago Macieira + + * configure.in: add DBUS_BINDIR as a #define to C source code. + + * tools/dbus-launch.c + * tools/dbus-launch.h + * tools/dbus-launch-x11.c: + * tools/dbus-launch.1: Add the --autolaunch option to + dbus-launch, which makes it scan for an existing session + started with --autolaunch. With that option, it also creates + an X11 window and saves the bus address and PID to it. + + * dbus/dbus-sysdeps.h: + * dbus/dbus-sysdeps-unix.c (_dbus_get_autolaunch_address): Add + a function that runs "dbus-launch --autolaunch" to retrieve + the running D-Bus session address (or start one if none was running) + + * dbus/dbus-transport.c: Add the handler for the "autolaunch:" + address protocol, which tries to get the running session from + dbus-launch. + + * dbus/dbus-bus.c: + * dbus/dbus-internals.h: Make "autolaunch:" be the default + D-Bus session bus address. + + * dbus/dbus-connection.c: Fix horrible typo in error message. + +2006-09-18 John (J5) Palmieri + + * tools/Makefile.am: use @EXPANDED_DATADIR@ instead of @DATADIRNAME@ + +2006-09-17 Havoc Pennington + + * dbus/dbus-transport.c (_dbus_transport_get_is_authenticated): + fix so that if unix_user_function is set on windows, we still + do the default check that the auth identity matches the bus identity + +2006-09-16 Havoc Pennington + + * dbus/dbus-transport.c (_dbus_transport_open): modify to delegate + to _dbus_transport_open_platform_specific, + _dbus_transport_open_socket, + and _dbus_transport_open_debug_pipe + + * dbus/dbus-transport-protected.h: add _dbus_transport_open_platform_specific + +2006-09-16 Havoc Pennington + + Attempt auditing public API to remove all cases where a Unix + function returns weird emulated goo to Windows. This probably + breaks the bus daemon on Windows, to fix it again we may + need to stop processing unix-specific config options on Windows, + and may need to add Windows-specific public API or config options. + + * configure.in (LT_CURRENT, LT_AGE): increment current and age, + to reflect added interfaces; should not break soname. + + * dbus/dbus-transport.c (_dbus_transport_get_is_authenticated): do + not invoke unix user function on Windows. Kind of a hacky fix, but + we don't want a "unix uid" leaking out on Windows. + + * dbus/dbus-connection.c (dbus_connection_get_socket): add new API + to get the socket fd on Windows or UNIX + (dbus_connection_get_unix_fd): make this always fail on Windows + +2006-09-16 Havoc Pennington + + * dbus/dbus-server.c (dbus_server_listen): change how this works + to be able to delegate to a set of handlers that can succeed, + fail, or choose not to handle. Allows us to have + dbus_server_listen_platform_specific. + + * dbus/dbus-server-socket.c (_dbus_server_new_for_tcp_socket): + factor out the tcp socket stuff to be used on windows, leaving + unix domain socket only in dbus-socket-unix.c + + * dbus/dbus-transport-socket.c + (_dbus_transport_new_for_tcp_socket): factor out the tcp socket + stuff to be used on windows, leaving unix domain socket only + in dbus-transport-unix.c + + * dbus/dbus-connection.c (dbus_connection_get_unix_user): insert + temporary hack to be sure this fails on windows + (dbus_connection_get_unix_process_id): ditto + +2006-09-16 Havoc Pennington + + * dbus/dbus-sysdeps-unix.c (_dbus_open_tcp_socket) + (_dbus_open_unix_socket, _dbus_open_socket): change API for + _dbus_open_socket so the domain/type/protocol from system headers + are not required. This is kind of pointless though unless we move + part of _dbus_connect_tcp_socket into sysdeps.c instead of + sysdeps-unix.c, which would mean adding a wrapper around + bind/listen/etc. + Also, add DBusError to the socket-opening functions so they + don't require use of errno. + +2006-09-16 Havoc Pennington + + * dbus/dbus-sysdeps-unix.h: small change to Peter's patch to make + dbus-sysdeps-unix-util.c build, add unix-specific sysdeps header. + + * dbus/dbus-sysdeps.h, dbus-sysdeps-unix.c: patch from Peter + Kümmel bug #8249 to make the sysdeps.h read/write/open/close + functions specifically for sockets only, and move generic + read/write/open/close into unix-specific code. + +2006-09-14 Havoc Pennington + + * dbus/dbus-transport-unix.c (unix_do_iteration): fix a valgrind + complaint about accessing revents when poll returns 0, from Julian Seward. + +2006-09-14 John (J5) Palmieri + + * Released 1.0 RC 1 (0.93) + +2006-09-14 John (J5) Palmieri + + * dbus/dbus-sysdeps-util-unix.c (_dbus_write_pid_file): + use _dbus_close instead of close + +2006-09-14 John (J5) Palmieri + + * dbus/dbus-sysdeps.c: Add support for LOCAL_CREDS socket + credentials. Fixes "external" authentication under e.g. NetBSD + which does not support any other socket credentials mechanism. + (Patch from Julio M. Merino Vidal ) + +2006-09-14 John (J5) Palmieri + + * dbus/dbus-threads.c: Allow recursive mutex's to be passed into + dbus_threads_init and be used by the dbus mutex functions to + avoid deadlocks. + + * doc/TODO: Remove recursive mutex dbus_connection_dispatch TODO item + +2006-09-13 John (J5) Palmieri + + * dbus/dbus-sysdeps-util-unix.c (_dbus_directory_get_next_file): + use threadsafe readdir_r instead of readdir + +2006-09-13 John (J5) Palmieri + + * dbus-threads.c (dbus_threads_init_default): New method for + initializing the internal thread implementation (Patch from + Alexander Larsson ) + +2006-09-11 John (J5) Palmieri + + * remove a bunch of todo items from the 1.0 list + +2006-09-11 John (J5) Palmieri + + * bus/activation.c, bus/desktop-file.c: Distinguish between OOM and + key not found + +2006-09-11 John (J5) Palmieri + + * dbus/dbus-internal.c: Add dbus_is_verbose so we can have more + complex debugging code + + * dbus/dbus-marshal-basic.c (_dbus_marshal_read_fixed_multi): Move + between the test suite ifdefs + (_dbus_verbose_bytes): return if verbosity is not enabled + +2006-09-11 John (J5) Palmieri + + * dbus/dbus-marshal-recursive-util.c, dbus/dbus-marshal-recursive.c: + remove DBusMark + +2006-09-10 Havoc Pennington + + patch mostly by Peter Kümmel, bug #8211 + + * dbus/dbus-sysdeps-unix.c: new file, which splits out + unix-specific stuff in dbus-sysdeps.c + + * dbus/dbus-sysdeps.c: don't include any UNIX-only headers, + and move unix-specific stuff to dbus-sysdeps-unix.c + + * configure.in: check HAVE_ERRNO_H + +2006-09-08 John (J5) Palmieri + + * bus/test-main.c (main): Initialize threading during tests + + * dbus/dbus-connection.c (_dbus_connection_new_for_transport): + Unlock connection on error + (generate_local_error_message): static method for generating + an error message when we don't have a message to reply to + (_dbus_connection_block_pending_call): Send a disconnect error + instead of just a timeout (NULL) when the bus gets disconnected + while blocking for a reply. + +2006-09-08 John (J5) Palmieri + + * dbus/dbus-connection.c (dbus_connection_dispatch): Properly remove + filters (Patch from Kimmo Hämäläinen + ) + +2006-09-07 John (J5) Palmieri + + * dbus/dbus-connection-internal.h: Add prototype for + _dbus_connection_test_get_locks to remove warning + +2006-09-07 John (J5) Palmieri + + * dbus/dbus-spawn.c (_dbus_spawn_async_with_babysitter): Make sure we + close child_err_report_pipe[WRITE_END] on exec (Patch from + Kimmo Hämäläinen ) + +2006-09-07 John (J5) Palmieri + + * Clean up close calls to use _dbus_close (Patch from + Kimmo Hämäläinen ) + +2006-09-06 John (J5) Palmieri + + * doc/TODO: + - Remove pending call locking todo item + - dbus_connection_open now holds hard ref. Remove todo item + - do proper locking on _dbus_bus_check_connection_and_unref + and handle DBUS_BUS_STARTER. Remove todo item + - Warn on closing of a shared connection. Remove todo item + + * bus/bus.c, bus/connection.c, bus/dispatch.c, dbus/dbus-bus.c, + dbus/dbus-connection.c: Use the dbus_connection_close_internal + so we don't get the warning when closing shared connections + + * test/test-service.c, test/test-shell-service.c: Applications + don't close shared connections themselves so we unref instead of + close + + * test/test-utils.c (test_connection_shutdown): Close the connection + + * dbus/dbus-bus.c (_dbus_bus_check_connection_and_unref): Changed to + _dbus_bus_check_connection_and_unref_unlocked since we only call this + method on a locked connection. + Make sure we call _dbus_connection_unref_unlocked instead of + dbus_connection_unref also. + Handle DBUS_BUS_STARTER correctly + + * dbus/dbus-connection.c (connection_record_shared_unlocked): + Mark as shared and hard ref the connection + (connection_forget_shared_unlocked): Remove the hard ref from the + connection + (_dbus_connection_close_internal_and_unlock): New internal function + which takes a locked connection and unlocks it after closing it + (_dbus_connection_close_internal): New internal function which acts + like the origonal dbus_connection_close method by grabbing a connection + lock and calling _dbus_connection_close_internal_and_unlock + (dbus_connection_close): Public close method, warns when the app + trys to close a shared connection + +2006-09-06 John (J5) Palmieri + + * bus/driver.c: + (bus_driver_generate_introspect_string): New method for populating + a DBusString with the introspect data + (bus_driver_handle_introspect): Move introspect generation code to + bus_driver_generate_introspect_string + + * bus/main.c: + (introspect): New function which prints out the intropect data and + exits + (main): Add a --introspect switch + +2006-09-06 John (J5) Palmieri + + * doc/TODO: Removed dtd publishing item. + It seems the dtd has already been added at + http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd + +2006-09-05 John (J5) Palmieri + + * doc/TODO, various source files: Audited todo's and FIXME's and + prepended the ones we should be looking at with 1.0. Those + prepended with 1.0? need clerification or might not be needed + for 1.0 + +2006-09-05 John (J5) Palmieri + + * dbus/dbus-pending-call.c: Add some checks so we don't crash on + NULL in the public API (Patch from Kimmo Hämäläinen + ) + +2006-09-05 John (J5) Palmieri + + * configure.in: Fix for OS-X compile time endian issues (patch from + Benjamin Reed ) + +2006-09-05 John (J5) Palmieri + + * configure.in: Check for no-common compiler flag (OS-X fix from + Benjamin Reed ) + +2006-09-01 John (J5) Palmieri + + * tools/dbus-launch.c: Add a sigterm handler (patch from Frederic Crozat + ) + +2006-08-29 Havoc Pennington + + * test/test-service.c (path_message_func): fix lack of return value + + * dbus/dbus-sysdeps.c (_dbus_printf_string_upper_bound): fix + formatting, remove #ifdef, and fix docs. #ifdef doesn't make + any more sense than on anything else in this file. + (_dbus_get_tmpdir): add const to return value, and keep the + results of the various getenv around in a static variable. + +2006-08-29 Havoc Pennington + + * dbus/dbus-sysdeps-util.c, dbus/dbus-sysdeps-util-unix.c: change + from Ralf Habacker to move UNIX-specific sysdeps into a separate file. + +2006-08-25 John (J5) Palmieri + + * test/Makefile.am: change find to use syntax that works with non + gnu versions of find + +2006-08-25 John (J5) Palmieri + + * dbus/dbus-transport.c: fix invalid deref when checking if + a vtable method exists (Patch from Christian Ehrlicher + ) + +2006-08-25 John (J5) Palmieri + + * configure.in, dbus/Makefile.am, test/name-test/run-test.sh, + test/name-test/Makefile.am: Fixed some issues with getting get dbus + to build with builddir != srcdir (Taken from a patch by Bernard Leak + ) + +2006-08-25 John (J5) Palmieri + + * configure.in: Fix DBUS_DAEMONDIR to use EXPANDED_BINDIR for the + default case + +2006-08-25 John (J5) Palmieri + + * configure.ac, bus/Makefile.am: Generalize kqueue support so that + it works on any system providing this interface, not only FreeBSD. + For example, NetBSD. (Patch by Julio M. Merino Vidal ) + +2006-08-20 Havoc Pennington + + * doc/dbus-faq.xml, doc/dbus-tutorial.xml: some improvements to + the docs + +2006-08-18 John (J5) Palmieri + + * Released 0.92 + +2006-08-18 John (J5) Palmieri + + * dbus/dbus-threads.c (dbus_threads_init): change the documentation + to reflect the init late change + + * bus/bus.c (bus_context_new): Check user before we fork so we can + print out an error message a user will be able to see + +2006-08-18 John (J5) Palmieri + + Patch provided by Ralf Habacker (ralf dot habacker at freenet dot de) + + * dbus/dbus-sysdeps.c, dbus/dbus-threads.c, dbus/dbus-internals.h: + Add two more global locks for use on windows platforms. These are + unused on non-windows platforms but are not ifdefed out to avoid + potential bugs (i.e. the few bytes lost does not warrent the extra + maintanence and complexity that having seperate sets of locks would + cause) + +2006-08-18 John (J5) Palmieri + + * bus/services.c (bus_registry_acquire_service): Return an error + when an application tries to register the org.freedesktop.DBus Bus Name + + * bus/services.c (bus_registry_release_service): Return an error + when an application tries to release the org.freedesktop.DBus Bus Name + +2006-08-17 Alp Toker + + * doc/dbus-specification.xml: Fix some minor typos. + +2006-08-17 John (J5) Palmieri + + * configure.in: use $with_init_scripts instead of $operating_system + to determine where to store the pid since the init scripts manipulate + the pid file (patch from Marcelo Ricardo Leitner + . + +2006-08-16 John (J5) Palmieri + + * dbus/dbus-threads.c: Add static DBusList *uninitialized_mutex_list and + static DBusList *uninitialized_condvar_list to support new late + initialization threading model. In this model threads can be initialized + even after the D-Bus API has been used but still needs to be initialized + before the second thread has been started. Mutexes and condvar addresses + are stored in the two static lists and are replaced with actuall locks + when threads are initalized. + (_dbus_mutex_new_at_location): New method for creating a mutex and placing + the location into the static list + (_dbus_mutex_free_at_location): New method for removing a mutex location + from the static list and freeing the mutex + (_dbus_condvar_new_at_location): New method for creating a conditional + variable and placing the location into the static list + (_dbus_condvar_free_at_location): New method for removing a conditional + variable location from the static list and freeing the conditional variable + (init_uninitialized_locks): Atomic method which goes through the static + lists of mutex and condvar location and updates them with actuall locks + (init_global_locks): changed to init_locks + + * dbus/dbus-connection.c: + (_dbus_connection_test_get_locks): New method for tests to check connections + (_dbus_connection_new_for_transport): Use the new at_location mutex and + condvar API + (dbus_connection_allocate_data_slot): Pass in the global lock address + to _dbus_data_slot_allocator_alloc + + * dbus/dbus-dataslot.c: + (_dbus_data_slot_allocator_alloc): Use the address of the mutex + instead of the mutex itself + + * dbus/dbus-message.c: + (dbus_message_allocate_data_slot): Pass in the global lock address + to _dbus_data_slot_allocator_alloc + + * dbus/dbus-pending-call.c: + (dbus_pending_call_allocate_data_slot): Pass in the global lock address + to _dbus_data_slot_allocator_alloc + + * dbus/dbus-server.c: + (_dbus_server_init_base): Use the new at_location mutex API + (dbus_server_allocate_data_slot): Pass in the global lock address + to _dbus_data_slot_allocator_alloc + + * test/name-test/test-threads-init.c: New test case for late thread + initialization + +2006-08-14 John (J5) Palmieri + + * dbus/dbus-dataslot.c (_dbus_data_slot_allocator_alloc): + Change _dbus_abort to _dbus_assert_not_reached because _dbus_abort + causes compile problems when asserts are turned off + Keeping _dbus_warn for printing out the message so even if + asserts are turned off the user gets the messages that something is + wrong + +2006-08-14 John (J5) Palmieri + + Patches by Kjartan Maraas + + * bus/services.c (bus_service_list_queued_owners): + Add a pointer cast to fix compiler warning + + * dbus/dbus-dataslot.c (_dbus_data_slot_list_get): + return a NULL instead of FALSE since the return type + is not expecting a boolean + + * dbus/dbus-marshal-basic.c (_dbus_marshal_test): + Remove unused variable + + * dbus/dbus-marshal-recursive-util.c (node_new): + return a NULL instead of FALSE since the return type + is not expecting a boolean + + * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new): + Send a NULL into _dbus_transport_new_for_fd instead of a FALSE + because we are expecting a pointer not a boolean + + * dbus/dbus-sysdeps-util.c (_dbus_get_tmpdir): + add void as the parameter so some compilers + don't complain + + * dbus/dbus-transport-unix.c (_dbus_transport_new_for_domain_socket, + _dbus_transport_new_for_tcp_socket): + Send a NULL into _dbus_transport_new_for_fd instead of a FALSE + because we are expecting a pointer not a boolean + + * test/shell-test.c (test_command_line): + cast the second argument to _dbus_list_append to avoid compiler + warnings + + * test/test-names.c (main): remove unused variable + + * test/test-service.c (check_hello_from_self_reply): + Initialize echo_message and echo_reply to NULL + + * test/test-shell-service.c (handle_echo): + Remove unused variable and cast the third parameter passed to + dbus_connection_get_object_path_data to avoid compiler warrnings + + * test/name-test/test-names.c (clear_message_queue): + Remove unused function + + * test/name-test/test-pending-call-dispatch.c: + Fix format string in printf + + +2006-08-14 John (J5) Palmieri + + * dbus/dbus-bus.c: + * test/name-test/test-names.c: + Remove test method dbus_bus_connection_get_unique_name because + we already have public method dbus_bus_get_unique_name that + does the exact same thing + +2006-08-10 John (J5) Palmieri + + * dbus/dbus-signature.c: + fix typos in Julio's previous patch which cause make check to fail + +2006-08-10 John (J5) Palmieri + + * dbus/dbus-address.c (_dbus_address_test): Revert leaking strcmp. + In any case it was wrong since this is a test checking to see if + address parsing is correct. There was no need to get the true + tmp directory. + +2006-08-10 John (J5) Palmieri + + * dbus/dbus-macros.h: Revert the addition of stddef.h + as we should not be adding it to library headers + +2006-08-10 John (J5) Palmieri + + * dbus/dbus-signature.c: + Fix the unit tests so that they work if assertions are not enabled. + (patch from Julio M. Merino Vidal ) + +2006-08-10 John (J5) Palmieri + + * tools/run-with-tmp-session-bus.sh: + * test/name-test/run-test.sh: + Remove bashisms (patch from Julio M. Merino Vidal + ) + +2006-08-10 John (J5) Palmieri + + * configure.in: add a version (>= 2.6.0) check for libxml2 + +2006-08-10 John (J5) Palmieri + + * configure.in: make sure the compiler supports -Wfloat-equal + + * bus/dir-watch-dnotify.c: move functional code after + variable declerations (C99 fix) (patches from Jens Granseuer + + +2006-08-10 John (J5) Palmieri + + * dbus/dbus-macros.h: + add #include so that Sun compilers don't complain about + the defining NULL + +2006-08-10 John (J5) Palmieri + + * dbus/dbus-sysdeps.c: + * dbus/dbus-address.c: + * bus/activation.c: + * test/shell-test.c: + don't hardcode tmp directory (patch from Dave Meikle + ) + +2006-08-09 John (J5) Palmieri + + * dbus/dbus-dataslot.c (_dbus_data_slot_allocator_alloc): + Change an assert to a detailed warning and abort. + When allocator->lock != mutex it indicates that the user has failed + to initalize threads before using the D-Bus library. This warning + helps the user identify the issue and fix their app. + +2006-08-08 John (J5) Palmieri + + These are all patches from Kjartan Maraas + with cleanups of bugs found from Coverity reports: + + * dbus/dbus-sysdeps-util.c (_dbus_write_pid_file): + close the file on error to avoid a leak + + * bus/expirelist.c (bus_expire_list_test): + Check for NULL on dbus_new0 + + * bus/activation.c (update_directory): + remove dead code + + * bus/config-parser.c (merge_service_context_hash, start_selinux_child): + Fix some leaks + + * bus/bus.c (process_config_every_time): + Fixed a leak + + * bus/desktop-file.c (parse_key_value): + Fixed leak + + * bus/selinux.c (bus_selinux_id_table_insert): + Fixed leak + +2006-08-08 John (J5) Palmieri + + * dbus/dbus-object-tree.c (_dbus_object_subtree_new): + remove dead code + +2006-08-08 John (J5) Palmieri + + * tools/run-with-tmp-session-bus.sh: use #!/bin/sh instead of + #!/bin/bash + +2006-08-08 John (J5) Palmieri + + * Doxyfile.in: fix the INPUT line so we can generate docs + when sourcedir != builddir (patch from Cygwin Ports maintainer + + +2006-08-08 John (J5) Palmieri + + * dbus/dbus-sysdeps.h: + * dbus/dbus-sysdeps.c: + * dbus/dbus-string.c: + s/_dbus_printf_length/_dbus_printf_string_upper_bound to comform with + GLib's function which does the same thing + + * configure.in: + * bus/Makefile.am: + * bus/dir-watch-default.c: + * bus/dir-watch-dnotify.c: + * bus/dir-watch-kqueue.c: + Add kqueue directory watching for freebsd and split the directory + watching code into seperate files per method/arch + (patches from Timothy Redaelli ) + +2006-08-08 John (J5) Palmieri + + * configure.in: + * tools/Makefile.am: + * tools/dbus-launch.c: + * bus/Makefile.am: + allow --with-dbus-daemondir switch to be used to make the + daemon install to a seperate bindir like /usr/libexec + (patch from Brian Cameron + + * bus/Makefile.am (install-data-hook): removed the slash after + $(DESTDIR) so we don't get the double slash which does not work + in windows (patch from Andras Porjesz + ) + +2006-08-08 John (J5) Palmieri + + * dbus/dbus-sysdeps.h: + * dbus/dbus-sysdeps.c: + add _dbus_printf_length (patch from Peter Kümmel + ) + +2006-08-08 John (J5) Palmieri + + * dbus/dbus-internals.c: unistd.h is not used + (_dbus_verbose_real): only enable verbose printing + if DBUS_VERBOSE environment var is set to '1' + (patch from Peter Kümmel ) + +2006-08-08 John (J5) Palmieri + + * configure.in: add a GCC flag check for -Wdeclaration-after-statement + so we still compile on older gcc (patch from Frederic Peters + + +2006-08-04 Havoc Pennington + + * configure.in: add -Wdeclaration-after-statement + + * dbus/dbus-connection.c: change all the pending call stuff to + reflect the fact that pending call operations use the connection + lock + + * dbus/dbus-pending-call.c: add locking here + + * dbus/dbus-errors.c (struct DBusRealError): don't make the name + field const consistent with how message field is done + +2006-08-03 John (J5) Palmieri + + * s/D-BUS/D-Bus/g + +2006-08-03 John (J5) Palmieri + + * dbus/dbus-object-tree.c: Patch by Benjamin Otte + - fix invalid + read/write reported by valgrind + +2006-07-24 John (J5) Palmieri + + * Released 0.91 + +2006-07-22 John (J5) Palmieri + + * dbus/dbus-connection.c: + (_dbus_connection_attach_pending_call_unlocked): + (connection_timeout_and_complete_all_pending_calls_unlocked): + Make sure we set timeout_added on pending calls to FALSE when + we remove the timeout from the connection + +2006-07-21 John (J5) Palmieri + + * Removed some extra bindings stuff lingering around (thanks timo) + * dbus-pendingcall.c (_dbus_pending_call_new): + s/dbus_connection_ref/_dbus_connection_ref_unlocked fixes assertion + when we tried to take a lock on an already locked connection + +2006-07-17 John (J5) Palmieri + + * Released 0.90 + +2006-07-17 Havoc Pennington + + * dbus/dbus-marshal-basic.c (_dbus_type_to_string): support 64-bit + ints, reported by Owen Taylor + +2006-07-17 John (J5) Palmieri + + * doc/TODO: + * dbus/dbus-bus.c: + * dbus-errors.c: + * dbus/dbus-marshal-validate.c: + Removed TODO items which were fixed or are no longer relevent + +2006-07-17 John (J5) Palmieri + + * dbus-qt4-1.pc.in, dbus-sharp.pc.in: + Remove stray files from the stripped bindings + +2006-07-16 Havoc Pennington + + * dbus/dbus-pending-call.c (_dbus_pending_call_set_timeout_error): + Improve the error message on reply timeout + +2006-07-14 John (J5) Palmieri + + * Remove all bindings + +2006-07-13 John (J5) Palmieri + + * dbus-connection.c (dbus_connection_send_with_reply): return TRUE + and set pending_reply out arg to NULL is connection is disconnected + (connection_timeout_and_complete_all_pending_calls_unlocked): New + static method for cleaning up pending calls on disconnect + (_dbus_connection_get_dispatch_status_unlocked): If we have pending + calls queued timeouts on disconnect + + * dbus/dbus-pending-call.c (_dbus_pending_call_set_connection): + Remove + +2006-07-13 Carlos Garcia Campos + + * bus/activation.[ch] (bus_activation_list_services): new function to + get the list of services that can be activated + + * bus/dispatch.c: test coverage for the new bus method + ListActivatableNames + + * bus/driver.c: new bus method ListActivatableNames to get the list of + services that can be activated + + * doc/dbus-specification.xml: ListActivatableNames method documentation + +2006-07-12 John (J5) Palmieri + * dbus/Makefile.am: add dbus-pending-call-internal.h to the list of + source files + +2006-07-12 John (J5) Palmieri + * dbus/dbus-message-factory.c: + Fix index into an array (patch by Peter Kümmel ) + +2006-07-12 John (J5) Palmieri + * dbus/dbus-connection-internal.h: + * dbus/dbus-connection.c: + * file dbus/dbus-pending-call.c: + * dbus/dbus-pending-call.h: + Make DBusPendingCall an opaque type even to D-Bus internals + +2006-07-07 John (J5) Palmieri + + * dbus/dbus-connection.h: remove connection_disconnect and replace with + connection_close + + * dbus/dbus-connection.c: include dbus-bus.h + (_dbus_connection_read_write_dispatch): make static + +2006-07-07 John (J5) Palmieri + + * dbus/dbus-connection.c (dbus_connection_close): removed deprecated + function + (dbus_connection_dispatch): On disconnect unref any shared connections + + * dbus/dbus-bus.c (_dbus_bus_check_connection_and_unref): new function + for cleaning up shared connections on disconnect + (internal_bus_get): get a hard refrence to shared connections when + they are created + + * doc/TODO: Remove items which are no longer relevent or have been fixed + Split 1.0 todo items with a 0.90 freeze todo list + +2006-06-14 Ross Burton + + * glib/dbus-gobject.c: + Free a leaking GArray (surely not!) in dbus_g_method_return. + +2006-06-14 Ross Burton + + * tools/Makefile.am: + * tools/dbus-monitor.c: + Don't use the GLib bindings in dbus-monitor (patch from Ralf + Habacker). + +2006-06-14 Ross Burton + + * tools/dbus-print-message.c: + Also print the object path when outputting signals or method calls. + +2006-06-13 Thiago Macieira + + * qt/src/Makefile.am: install the qdbus.h header. + This allows people to actually use the installed code. + +2006-06-12 Ross Burton + + * glib/dbus-gproxy.c: + Don't leak a GArray when firing signals (thank Rob Taylor for review). + +2006-06-12 Thiago Macieira + + * Released 0.62 + +2006-06-12 Thiago Macieira + + * dbus/dbus-arch-deps.h.in: Remove spurious semi-colons that + break pedantic builds. Closes bug 6043 (patch approved by + Havoc back in February). + +2006-06-12 Thiago Macieira + + * qt/src/qdbusintegrator.cpp: Fix bug in parsing async methods + that took a QDBusMessage parameter. + * qt/src/qdbusbus.h: Add a default flag for RequestName. + * qt/tools/dbus.cpp: Don't use automatic call because we might + be calling an async method: request a reply. + +2006-06-11 Thiago Macieira + + * test/qt/*: Update the testcases, including testing the new + functionality of sending null QByteArray and QString over the + bus. Add new headertest test and restore the old + qdbusxmlparser test. + +2006-06-11 Thiago Macieira + + * qt/tools/dbuscpp2xml.cpp: Compile on Windows. + * qt/tools/dbusidl2cpp.cpp: Add missing newline. + + * qt/examples/Makefile.am: + * qt/examples/chat.h: Use UI-generated files with the ui_*.h + form. + + * qt/src/qdbusmarshall.cpp: Allow sending of QString() and + QByteArray() (nulls) over the bus. + * qt/src/qdbusabstractinterface.cpp: Use the correct variable, + the one that has the signature suffix stripped. + * qt/src/qdbusreply.h: Make some methods const. + +2006-06-09 Thiago Macieira + + Patch from Timo Hoenig . + + * qt/dbus/Makefile.am: New file. Fix "make dist", add all headers + required during build to EXTRA_DIST. + * qt/src/Makefile.am: Fix "make dist", add 'qdbus.h' to EXTRA_DIST. + * qt/Makefile.am: Fix "make dist", add 'dbus' to DIST_SUBDIRS. + * configure.in: Fix "make dist", take care that the Makefile for + qt/dbus is being generated. + +2006-06-07 John (J5) Palmieri + + * bus/bus.c: Fix eavesdropping on method calls + +2006-06-07 John (J5) Palmieri + + * configure.in: + * dbus/dbus-userdb-util.c: + Add Solaris console owner patch from Artem Kachitchkine + +2006-06-07 Thiago Macieira + + * qt/Makfile.am: + * qt/src/Makefile.am: Fix the EXTRA_DIST after the + reorganisation. Thanks to Timo Hoenig for pointing this out. + +2006-06-06 Robert McQueen + + * glib/dbus-gtype-specialized.c: Fix obvious leak of GArray in every + call to dbus_g_type_get_struct. + +2006-06-06 Robert McQueen + + * glib/dbus-gvalue-utils.c: Fix the failing test where static string + pointers were put into a GPtrArray-based specialised collection, and + then freed along with the array. GValues which you add into + collections or maps which have the NOCOPY flag set are assumed to not + belong to the caller, so rather than the existing pointer-stealing + semantics, they are copied instead. Given that the main consumers of + this abstraction are the bindings themselves, I don't think this is + too bad, but others should watch their choice of take vs set_static. + +2006-06-06 Robert McQueen + + * glib/dbus-gvalue-utils.c: Spotted a warning about the return value + of g_slist_prepend not being used. Fixed copying of slist-based + specialised collections, then wrote a test case and found that it was + all broken. Went on to fix iterating and appending too. Good thing + nobody uses this code yet. + +2006-06-06 Robert McQueen + + * glib/dbus-gvalue-utils.c: Remove duplicated code by having all of + the iterators use gvalue_take_ptrarray_value (the GValues themselves + are discarded without unsetting, so it makes no difference whether + we take or set_static). Remove cases for G_TYPE_POINTER because + there really is nothing useful we can do with them in our + specialised types - we *need* boxed copy/free functions at the very + least. + +2006-06-05 Thiago Macieira + + * qt/dbus: Add directory. I had forgotten to add this + yesterday after the move... + + * qt/examples/Makefile.am: + * qt/examples/dbus.cpp: Moved to qt/tools/dbus.cpp. + + * qt/tools/Makefile.am: + * qt/tools/dbus.cpp: Moved from qt/examples/dbus.cpp. + Added feature to get and set properties. + Added validation of service, object path and interface names. + + * qt/tools/dbusidl2cpp.cpp: Two new features: + 1) Allow specifying both the header and the source file names, + by separating them with a colon. + 2) Don't write an interface output if the -p switch wasn't + given, but the -a was. + + * qt/src/*: Fix usage of Iterators and ConstIterators. + Fix shadowing of variables by other variables (-Wshadow). + Fix keyword-cleanliness in headers. + Fix ASCII-cast (QLatin1String, QLatin1Char). + Fix validation of member names. + Add extra checking of introspection data during XML parsing. + Various bug fixes. + +2006-06-04 Thiago Macieira + + * dbus/Makefile.am: + * dbus/qdbus.h: Remove unnecessary file. This is mirrored into + qt/dbus/qdbus.h now. + +2006-06-04 Thiago Macieira + + * configure.in: Make --disable-qt actually do + something. Patch inspired by Zack Rusin. + +2006-06-04 Thiago Macieira + + * qt/: Update to Subversion r548032. + This includes a big reorganisation of the files inside the + subdir. + +2006-05-30 Sjoerd Simons + + * dbus/dbus-sysdeps.c: Make tcp socket connection error somewhat more + clear: + "Failed to connect to socket : " instead of + "Failed to connect to socket : :" + + * dbus/dbus-transport-unix.c: Fix crash when no host option is given + for a tcp transport. + +2006-05-29 Thiago Macieira + + * qt/*: Update the QtDBus bindings up to revision 546310 in + Subversion. + This adds the dbuscpp2xml tool, that parses a C++ header and + outputs a D-BUS Introspection XML. + +2006-05-21 Havoc Pennington + + * glib/dbus-gproxy.c: Put in a pile of assertions that the proxy name + is not NULL when it shouldn't be. Also a couple of possible fixes + for #4637 though I don't understand why the bug happens, to be + honest... also the object constructor has an assert name != NULL + and the name is only currently NULL for peer-to-peer proxies that + I don't think anyone uses? So it should be asserting. + Anyway, for now at least see if we get an earlier assertion failure. + + * glib/dbus-gvalue-utils.c: Put in a couple of assertions for + apparently broken code to be sure the tests fail and someone + will fix them... + +2006-05-07 Thiago Macieira + + * qt/qdbusmarshall.cpp: Fix a problem of demarshalling lists + and arrays when they had a single element: has_next returns + false, even before you read the element. So, instead, check + the array length. + +2006-05-06 Thiago Macieira + + * qt/qdbusmessage.cpp: + * qt/qdbustypehelper_p.h: + * qt/qdbusintegrator.cpp: gcc 3.4 doesn't like Q_FOREACH when + the list is a const-reference + +2006-05-03 John (J5) Palmieri + + * Adding old doc patch that never got applied + + * dbus/bus.c (dbus_bus_add_match): Add documentation + + * doc/dbus-specification.xml: Add documentation for the match rules + and the AddMatch and RemoveMatch methods + +2006-05-02 Thiago Macieira + + * qt/dbusidl2cpp.cpp: There's no callAsync. Use the correct + call (r535506) + + * qt/dbusidl2cpp.cpp: + * qt/qdbusabstractadaptor.cpp: + * qt/qdbusabstractadaptor.h: Make QDBusAdaptorConnector be a + sibling of the QDBusAbstractAdaptor objects instead of the + parent. (r535848) + + * qt/dbusidl2cpp.cpp: + * qt/qdbusabstractinterface.cpp: + * qt/qdbusabstractinterface.h: + * qt/qdbusabstractinterface_p.h: + * qt/qdbusinterface.cpp: Make properties in interfaces + actually work. The code that was generated would not compile, + due to moc calls to functions that did not exist. They now + shall. (r536571) + +2006-04-30 Thiago Macieira + + * Makefile.am: + * configure.in: + * dbus-qt4-1.pc.in: Add a pkg-config file for libdbus-qt4-1. + Thanks to Brad Hards for providing the patch + +2006-04-29 Thiago Macieira + + * qt/dbusidl2cpp.cpp: There's no callAsync. Use the correct + call. (r535506) + +2006-04-29 Thiago Macieira + + * qt/examples/dbus.cpp: Enhance error messages and use + QDBusInterfacePtr. + +2006-04-29 Thiago Macieira + + * qt/qdbusinterface.h: Rename QDBusRef to QDBusInterfacePtr + and disable the copy operators. (r533772, r534746) + + * qt/qdbuserror.h: Remove the automatic cast to bool. (r533929) + + * qt/qdbusabstractinterface.cpp: + * qt/qdbusabstractinterface.h: Change the default call mode to + not use the event loop. Add convenience call() methods that + take a CallMode parameter. (r534042) + + * qt/qdbusconnection.h: Change the default call mode to not + use the event loop. (r534042) + + * qt/qdbusinterface.cpp: + * qt/qdbusinterface.h: Add a method to tell us if the + interface is valid (since we don't return a null pointer + anymore) (r534099) + + * qt/qdbusinterface_p.h: Don't crash if metaObject is 0 + (r534101) + + * qt/qdbusinternalfilters.cpp: Decouple the introspection + function in two so taht we get the chance to introspect + without having a QDBusMessage (r534102) + + * qt/qdbusbus.h: + * qt/qdbusconnection.cpp: + * qt/qdbusconnection_p.h: + * qt/qdbusintegrator.cpp: Keep a list of our own names to + avoid a round-trip to the server when attempting to introspect + one of our own objects. Also make sure the filter functions + match the empty interface as well. (r534108) + Don't keep the connection names. Instead, trust the unique + connection name (r534111) + Remove event loop usage (r534112) + +2006-04-29 Thiago Macieira + + * qt/qdbusintegrator.cpp: Fix assertion failure spotted by + Brad Hards. + +2006-04-28 Robert McQueen + + * glib/dbus-gproxy.c: Fix properties so that they can be given in + any order, making it easier for people who inherit from this + object. + +2006-04-28 Robert McQueen + + * glib/dbus-gvalue-utils.c: Patch from Jakub Stachowski to fix leaking + of memory from within pointer arrays and lists. Fixes bug #6300. + +2006-04-28 Robert McQueen + + * glib/dbus-gvalue.c: Patch from Jakub Stachowski to fix a leak in + generating struct signatures. Fixes bug #6083. + +2006-04-28 Robert McQueen + + * qt/Makefile.am: Tweak CLEANFILES from qdbusconnection.moc + to qdbusconnection_p.moc. + +2006-04-24 John (J5) Palmieri + + * README, INSTALL: Doc fixes + Patch from Brad Hards + +2006-04-23 Thiago Macieira + + * qt/examples/dbus.cpp: Use the new merged-interface mode for + the dynamic meta object. No need to guess which interface to + call. + +2006-04-23 Thiago Macieira + + * qt/qdbusconnection_p.h: + * qt/qdbusmetaobject.cpp: + * qt/qdbusmetaobject_p.h: + * qt/qdbusintegrator.cpp: Use the new merged-interface mode + for the dynamic meta object. No need to guess which + interface to call. + * qt/qdbusabstractinterface_p.h: + * qt/qdbusconnection.cpp: + * qt/qdbusintegrator.cpp: + * qt/qdbusinterface.cpp: + * qt/qdbusinterface.h: Make findInterface always return a non-null pointer. + Add a QDBusRef that looks and behaves like DCOPRef. + +2006-04-23 Thiago Macieira + + * dbus/dbus-connection.c: Interfaces are optional in method + calls, so don't give up if the interface parameter is NULL. + Patch reviewed by Havoc Pennington. + +2006-04-23 Thiago Macieira + + * qt/qdbusreply.h: Add default constructor and operator= + (r532625) + * qt/qdbustypehelper_p.h: Use a clean namespace: no foreach() + in public headers (r532952) + * qt/qdbusabstractinterface.cpp: + * qt/qdbusabstractinterface_p.h: Add the AutoDetect mode and + make it the default (r532951) + +2006-04-19 John (J5) Palmieri + + * dbus/dbus-connection.c: Fix asserts + Patch from Tim Moloney + +2006-04-19 John (J5) Palmieri + + * mono/Connection.cs, mono/Message.cs: Check Target type + Patch from Aaron Bockover (abockover at novell.com) + +2006-04-13 Thiago Macieira + + * INSTALL: fine-tune the requirements for the Qt4 binding. + +2006-04-16 Daniel P. Berrange + + * tools/dbus-print-message.c: Added support for printing of all + remaining data types. Fixed logic for indentation of compound + data types. + +2006-04-15 Daniel P. Berrange + + * INSTALL: fill out content of file providing DBus specific + build installations, followed by generic Auto* INSTALL file + content + +2006-04-13 Thiago Macieira + + * qt/qdbusintegrator.cpp: Work around g++ 3.3 bug. + Patch by Stefan Eilers. (r529537) + +2006-04-13 Thiago Macieira + + * qt/qdbusinternalfilters.cpp: Don't show the parent's + contents (r528208) + +2006-04-10 Thiago Macieira + + * qt/Makefile.am: fix the dependency for + qdbusconnection_p.moc. It's included in qdbusintegrator.cpp, + not in qdbusconnection.cpp. + Thanks to Jakub Stachowski for + spotting this. + +2006-04-10 Thiago Macieira + + * qt/examples/listnames.cpp: + * qt/examples/Makefile.am: Three ways to list the names on the + bus. + +2006-04-10 Thiago Macieira + + * test/qt/tst_hal.cpp: Remove the waiting, since it's not + needed anymore. Requires Qt 4.1.3 to work properly. (r528148) + +2006-04-10 Thiago Macieira + + Merge from Subversion: + * qt/qt-dbus.qdocconf: Update Trolltech's webpage link to + something that exists (r526315) + * qt/qdbusinternalfilters.cpp: Correctly detect non-scriptable + slots/signals (r526316) + * qt/qdbusinternalfilters.cpp: Fix the setProperty call and + also return an unknown-method error if the parameters don't + match for org.freedesktop.DBus.Properties. (r526842) + * qt/examples/dbus.cpp: Allow passing of QVariants (r526843) + * qt/qdbusintegrator.cpp: Restore the proper order of + delivery: don't make method returns be delivered on priority + (r528150) + +2006-03-28 Thiago Macieira + + * configure.in qt/Makefile.am: add qt/examples + * qt/examples: Add QtDBus example programs: + - hello: Hello, World + - ping: Simple method-calling program + - pong: Simple object-exporting program (not using adaptors) + - complexping: Interactive method-calling program + (also gets and sets properties). + - complexpong: Sample program exporting methods, signals and + properties, using adaptors. + - dbus: Simple implementation of a generic method-calling + program, similar to 'dbus-send', but with semantics + similar to 'dcop'. + - chat: Simplistic chat program, implemented using signals + and the system bus. Looks like IRC. + +2006-03-28 Thiago Macieira + + * configure.in: Detect QtGui (necessary for one of the + example programs). Note: this increases the minimum required + version of Qt to 4.1.3. + +2006-03-28 Thiago Macieira + + * test/qt/*: Sync with KDE Subversion revision 523647. + Update the testcases to the new API. Remove testcases for + classes that are no longer public or have been removed. + +2006-03-28 Thiago Macieira + + * qt/*: + * dbus/qdbus.h: Sync with KDE Subversion revision + 523647. Hopefully, this will be the last of the + source-incompatible changes. Documentation has been improved; + support for QList has been added; QDBusObject is + gone; QDBus(Abstract)Interface is now a QObject with + auto-generated meta-object; QDBusIntrospection is marked + private, since QMetaObject can be used now; lots of bugfixes. + +2006-03-16 John (J5) Palmieri + + Patch from Milosz Derezynski + + * configure.in: + Output the service directory in the configure summary + + * dbus-1.pc.in: + Add session_bus_services_dir + +2006-03-10 Ross Burton + + * tools/dbus-print-message.c: + Add support for object paths and signatures. + +2006-03-06 Sjoerd Simons + + * bus/bus.c: (bus_context_reload_config): Flush the user database cache on + config reload. + * bus/dbus-daemon.1.in: Also note that SIGHUP flushes the user/group + information caches + * dbus/dbus-hash.c: (_dbus_hash_table_remove_all): + * dbus/dbus-hash.h: Add function to remove all entries from a hash table + * dbus/dbus-userdb.c: (_dbus_user_database_flush): + * dbus/dbus-userdb.h: Add function to flush all user/group information + caches. + +2006-03-06 Thiago Macieira + + * qt/dbusidl2cpp.cpp: + * qt/Makefile.am: add the dbusidl2cpp tool, the replacement + for dcopidl2cpp, found in the KDE installations (or the more + modern kalyptus): generate Qt4 C++ code for the input XML + introspection. Currently no IDL parsing. + +2006-03-06 Thiago Macieira + + * test/qt/*: Update the self-tests. + +2006-03-06 Thiago Macieira + + * qt/*: + * dbus/qdbus.h: Sync with KDE Subversion revision 516237. This + represents the first feature-complete version of the Qt4 + bindings since I took ove maintainership. + +2006-03-06 Thiago Macieira + + * qt/Doxyfile: Adding a Doxyfile for the Qt4 bindings + dir. This is C++, so we can't use the DBus ones. + +2006-03-02 John (J5) Palmieri + + * python/dbus_bindings.pyx: Remove refrence to sys/cdefs.h + (Patch from Artem Kachitchkine ) + +2006-03-02 John (J5) Palmieri + + * dbus/dbus-connection.c: + (_dbus_connection_block_pending_call): + Check to see if our data has already been read off the connection + by another blocking pending call before we block in poll. + (check_for_reply_and_update_dispatch_unlocked): + Code taken from _dbus_connection_block_pending_call - checks for + an already read reply and updates the dispatch if there is one. + + * test/name-test/test-pending-call-dispatch.c: + New test for making sure we don't get stuck polling a + dbus connection which has no data on the socket when + blocking out of order on two or more pending calls. + +2006-02-28 Thiago Macieira + + * qt/Makefile.am: Patch by Sjoerd Simons. More .moc issues: + make/automake don't detect that we're talking about the same + .lo file if I specify the full path to the source files. + +2006-02-26 Havoc Pennington + + * bus/dbus-daemon.1.in: improve the language in a couple spots I noticed + + * dbus/dbus-bus.c (internal_bus_get): in the error message if the + session bus variable is unset, suggest "man dbus-launch" and "man + dbus-daemon" to figure out how to fix the problem + +2006-02-25 Havoc Pennington + + * glib/dbus-glib-tool.c (usage): fix up the usage message, someone + should make this thing use the new glib options parser + +2006-02-25 Thiago Macieira + + * qt/Makefile.am: Patch by Sjoerd Simons. Fix the path to the + .lo files taking moc sources. + +2006-02-25 Havoc Pennington + + * dbus/dbus.h, dbus/Makefile.am: add dbus-signature.h to dbus.h + and install it as a public header + +2006-02-24 John (J5) Palmieri + + * Released 0.61 + +2006-02-24 John (J5) Palmieri + + * proxies.py: Fix the callchain + +2006-02-24 John (J5) Palmieri + + * patch from Sjoerd Simons : + + * dbus/dbus-sysdeps-util.c (_dbus_group_info_free): Moved to + dbus/dbus-sysdeps.c + + * dbus/dbus-userdb.c (_dbus_group_info_free_allocated): Don't + call _dbus_group_info_free_allocated which causes infinite loop, + correctly call _dbus_group_info_free + +2006-02-20 Thiago Macieira + + * qt/qdbusinterface_p.h: + * qt/qdbusinterface.cpp: Use the standard + org.freedesktop.DBus.Method.NoReply annotation for the "async" + calls instead of creating one for us. + + * qt/qdbusconnection_p.h: + * qt/qdbusintegrator.cpp: Remove debugging code. + + * qt/qdbusintegrator.cpp: + * qt/qdbusmessage.cpp: + * qt/qdbusmessage_p.h: + * qt/qdbusmessage.h: Change the behaviour of automatic + reply-sending: now a reply is always sent, unless the caller + didn't request one or if the user slot has already sent one. + +2006-02-16 Robert McQueen + + * configure.in: Patch from Debian packages by Sjoerd Simons + to add --with-qt-moc and --with-qt3-moc + arguments so it's possible to build both bindings in the + same tree. + + * qt/Makefile.am: Fix truncated value so that make dist works. + +2006-02-16 Robert McQueen + + * acinclude.m4, configure.in: Patch from Brad Hards + to avoid warnings from autoconf 1.9 by + improving quoting, re-ordering a few checks, and a few other + aesthetic tidy-ups. + +2006-02-16 Robert McQueen + + * dbus/dbus-message.c (dbus_message_iter_get_fixed_array): + Patch from Rob Taylor to correct a bogus + assertion that the next element to read from the iter is fixed in + size. This is not the case when you are at the end of the iter, + because the next element type is INVALID. + + * dbus/dbus-string.c (_dbus_string_init_const_len): Correct a + a bogus assert which means that you may not initialise a 0-length + string unless you provide a non-NULL pointer. This prevented + you from marshalling messages containing zero-length arrays in + some cases. + + * glib/dbus-gvalue.c (demarshal_collection_array): Another patch + from Rob to correct bogus asserts when trying to demarshal an + array and get_fixed_array got you 0 elements. Append nothing to + the GArray in this case. + + * test/glib/test-dbus-glib.c: Add a test case for round-tripping + an empty array via the glib bindings. Without all of the above + patches, this new test fails. + +2006-02-16 Robert McQueen + + * glib/dbus-gmain.c: Make the previous commit compile. + + * python/_dbus.py, python/matchrules.py: Patch from Ole Andre + Ravnaas to allow you to + specify sender_keyword="foo", path_keyword="bar" when adding + a signal listener, so that you can bind to signals generically + but still do something useful in your callback. + + * python/dbus_bindings.pyx: Demarshal the byte type as unsigned + chars so that they're not cast to chars and made negative. Thanks + to Jakub Stachowski for reporting this and testing the fix. + +2006-02-15 John (J5) Palmieri + + * dbus/dbus-glib.h: + * glib/dbus-gmain.h: + (dbus_g_connection_open): new method for openning + a connection to an arbitrary address in the glib bindings + + * ChangeLog: checkin last entry which doesn't seem to be commited + +2006-02-13 John (J5) Palmieri + + * tools/dbus-launch.c: Fixed sh syntax output + +2006-02-13 Robert McQueen + + * glib/dbus-binding-tool-glib.c, glib/dbus-gmain.c, + glib/dbus-gsignature.c, glib/dbus-gtype-specialized.c, + glib/dbus-gtype-specialized.h, glib/dbus-gvalue-utils.c, + glib/dbus-gvalue-utils.h, glib/dbus-gvalue.c: + Patch from Rob Taylor to add a big + missing piece of the glib bindings jigsaw puzzle. This modifies + the existing specialised types to have N type parameters (rather + than the current 1 or 2 for arrays and dictionaries respectively). + You can then use this to get a glib type to represent any arbitrary + D-Bus struct type using dbus_g_type_get_struct. The only + implementation of these types is with GValueArrays as before, + but it's now possible to store these in arrays, emit them in + signals, etc. + +2006-02-10 John (J5) Palmieri + + * dbus/dbus-signature.c (dbus_signature_iter_recurse): Correctly + deal with nested arrays (Bug #5823) Patch by Thiago Macieira + + +2006-02-10 John (J5) Palmieri + + * mono/doc/Makefile.am: Fix parallel make problem with mono-doc + (Bug #4213) Patch from Doug Goldstein + +2006-02-10 John (J5) Palmieri + + * bus/connection.c (bus_connections_expect_reply): Make + pending reply limit not common to all connections (Bug #5416) + Patch from Kimmo Hämäläinen + +2006-02-10 John (J5) Palmieri + + * tools/dbus-launch.c: Fixed csh syntax output (Bug #5720) + +2006-02-10 John (J5) Palmieri + + * gcj/Makefile.am: point to correct jar command (Bug #4529) + patch from Doug Goldstein + +2006-02-09 Joe Shaw + + * mono/Arguments.cs: Fix a magic number in the mono bindings + that doesn't work on 64 bit arches. Patch from Peter Johanson. + +2006-01-27 Robert McQueen + + * glib/dbus-binding-tool-glib.[ch]: Patch based on Ricardo Kekki's + patch to use an annotation org.freedesktop.DBus.GLib.ClientCSymbol + when generating the client-side methods, instead of overloading + CSymbol which broke everything horribly. My apologies. + +2006-01-27 Robert McQueen + + * glib/dbus-gtype-specialized.[ch], glib/dbus-gvalue-utils.c: Patch + by me and Rob Taylor to add a simple_free function to D-Bus map + and collection types, which allows those types which can be freed + with a GDestroyNotify (such as GHashTables and GArrays, but not + GPtrArrays) to be stored as the values in hashtables. + + * test/glib/test-dbus-glib.c, test/glib/test-service-glib.{c,xml}: + Patch by Rob Taylor to add nested dicts to the glib tests to check + the above code works, and appears not to leak when called repeatedly. + +2006-01-27 Robert McQueen + + * glib/dbus-gvalue.c (demarshal_valuearray): Patch from Rob Taylor + to free a D-Bus allocated string with dbus_free () instead of + g_free (). + +2006-01-27 Iain Holmes + + * glib/dbus-gproxy.c (dbus_g_proxy_dispose): Protect the dispose + method from being called multiple times. + +2006-01-19 Robert McQueen + + * glib/dbus-binding-tool-glib.c: Patch from Rob Taylor + to add support for generating bindings + to arrays that are represented as GPtrArrays rather than GArrays (ie + size-variable things, such as strings, objects, structs, etc). + +2006-01-05 Robert McQueen + + * dbus/dbus-glib.h, glib/dbus-gproxy.c: Patch from Ricardo Kekki + to make it possible to inherit from + DBusGProxy, by splitting the DBusGProxy struct into a public part and + a private part, and moving the setting of the DBusGProxyManager into a + connection property, allowing proper GObject construction. + +2006-01-05 Robert McQueen + + * glib/dbus-binding-tool-glib.c: Patch from Ricardo Kekki + to make dbus-binding-tool heed C symbol name + annotations when generating glib client bindings. + +2005-12-19 John (J5) Palmieri + + * dbus/dbus-shared.h: Call it shared constants instead of shared macros + + * dbus/dbus-protocol.h: add DOxygen markup to quiet warnings + +2005-12-19 John (J5) Palmieri + + * dbus/dbus-shared.h: add DOxygen markup to quiet warnings + +2005-12-19 John (J5) Palmieri + + * dbus/dbus-macros.h: correct DOxygen end of section (s/}@/@}) + +2005-12-19 Ross Burton + + * doc/dbus-tutorial.xml: + Document the Glib client-side bindings, and list all possible annotations. + +2005-12-19 John (J5) Palmieri + + * dbus/bus.c (dbus_bus_release_name): Add documentation + +2005-12-06 Robert McQueen + + * python/service.py: s/sucessful/successful/ so we're allocating to + and reading from the same variable. Oops. + +2005-11-30 John (J5) Palmieri + + * Released 0.60 + +2005-11-30 John (J5) Palmieri + + * test/qt/Makefile.am: build from srcdir + + * qt/qtconnection.cpp (requestName): Changed PROHIBIT_REPLACE to ALLOW_REPLACE + Note - this code is wrong and needs to be fixed by the Qt binding + developers. The flags should be treated as bitfields and not enums. + + * qt/qtconnection.h: Change ProhibitReplace to AllowReplace + +2005-11-30 John (J5) Palmieri + + * dbus/dbus-list.c (_dbus_list_insert_after_link, _dbus_list_insert_after, + link_after): remove #ifdef DBUS_BUILD_TESTS since we use these methods + in production code + +2005-11-30 John (J5) Palmieri + + * dbus/dbus-connection.c (dbus_connection_read_write): Add new + method for getting messages off the bus in the absence of a + mainloop. This method is much like + dbus_connection_read_write_dispatch except it does not dispatch + the messages to a registered filter function. Instead it + allows a developer to process messages by directly popping + them off the bus. + +2005-11-30 John (J5) Palmieri + + * bus/desktop-file.c (parse_key_value): Ignore locales allowing + the parser to continue instead of returning error + (bus_desktop_file_load): Do not free parser data when + parse_section_start or parse_key_value fails because it was + already freed by parser_free (patch from Carlos Garcia Campos + ) + +2005-11-30 John (J5) Palmieri + + * dbus/dbus-auth.c, dbus/dbus-connection.c, dbus/dbus-keyring.c, + dbus/dbus-server-debug-pipe.c, glib/dbus-binding-tool-glib.c + glib/dbus-glib-tool.c, glib/dbus-gparser.c, glib/dbus-gproxy.c + test/test-segfault.c, test/test-utils.c, + test/glib/test-dbus-glib.c, tools/dbus-cleanup-sockets.c + tools/dbus-launch.c, tools/dbus-tree-view.c, tools/dbus-viewer.c: + Various cleanup of dead code and compiler warnings (patch from + Kjartan Maraas ) + +2005-11-30 John (J5) Palmieri + + * glib/dbus-gmain.c (connection_setup_add_watch): plugged a leak + (patch from Carlos Garnacho Parro + +2005-11-27 Robert McQueen + + * python/dbus_bindings.pyx: Repair my previous commit which reverted + part of the preceding one. Oops. Merge patch by Johan Hedberg + to fix marshalling of 16-bit integer values + on big-endian platforms. + + * test/python/test-client.py: Add some 16-bit integers to the test + values. + +2005-11-27 Carlos Garcia Campos + + * glib/dbus-gobject.c: Append a GValue instead of a basic type in + method return message for property getters + +2005-11-27 Robert McQueen + + * python/dbus_bindings.pyx: Fix a bug where doing a strict append + with type v of an instance of dbus.Variant(foo, type='x') caused + it to be boxed twice before sending over the bus. + + * python/dbus_bindings.pyx, python/service.py, + test/python/test-client.py: Update the constants for the new + request_name flags, and update comments/test cases now that queueing + is the default action. + +2005-11-22 John (J5) Palmieri + + * configure.in: + - Change version to 0.60 for impending release + - upped the sonames because of ABI and API breakage + +2005-11-22 John (J5) Palmieri + + * configure.in: Add test/name-test/Makefile to the generated + Makefile list + + * dbus/dbus-shared.h (#define DBUS_NAME_FLAG_ALLOW_REPLACEMENT): + New flag which replaces DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT + (#define DBUS_NAME_FLAG_DO_NOT_QUEUE): New flag for specifying + not to queue an ower if it can't be the primary owner + + * bus/bus.h: Add new internal BusOwner struct + + * bus/driver.c (bus_driver_handle_hello): Send flags (0 for default) + to bus_registry_ensure and don't set the prohibit_replacement flag + since they are now set per BusOwner and not per name. + (bus_driver_handle_list_queued_owners): bus method (ListQueuedOwners) + that returns the list of connections in a name's connection queue + + * bus/services.c (struct BusService): remove prohibit_replacement field + (struct BusOwner): new struct for keeping track of queued connections + and their associated flags for the queue + (struct BusRegistry): add a BusOwner memory pool + (bus_registry_new): initialize the BusOwner memory pool + (bus_registry_unref): free the BusOwner memory pool + (_bus_service_find_owner_link): new internal method for + searching the queue for a specific connection + (bus_owner_set_flags): new method for adding setting the flags on a + bus owner + (bus_owner_new): new method that creates a BusOwner object from the + pool and sets its flags + (bus_owner_ref, bus_owner_unref): ref counting for BusOwner objects + (bus_registry_ensure): Add the flags parameter + (bus_registry_acquire_service): Switch from using raw connections to + using the BusOwner struct + Add new state machine for dealing with the new set of flags + (bus_registry_set_service_context_table, struct OwnershipCancelData, + cancel_ownership, free_ownership_cancel_data, + add_cancel_ownership_to_transaction, struct OwnershipRestoreData, + restore_ownership, free_ownership_restore_data, + add_restore_ownership_to_transaction): Switch to using BusOwner + instead of raw connections + (bus_service_add_owner): Add flags parameter + Switch to using BusOwner instead of raw connections + Add state machine for dealing with the new set of flags + (bus_service_swap_owner): Swaps the first and second owners in the + queue. Used to make sure proper signals are sent when a service looses + or gains primary ownership. We never insert an owner at the top of the + queue. Instead we insert it in the second position and then swap. + (bus_service_remove_owner): Remove the owner from the queue sending + out the NameLost and NameOwnerChanged signals if the we were the + primary owner + (bus_service_get_primary_owners_connection): New method that extracts + the connection from the primary owner + (bus_service_get_primary_owner): Returns the BusOwner instead of the + connection + (bus_service_get_allow_replacement): Changed from the old + bus_service_get_prohibit_replacement method. Checks the flags of the + primary owner and returns if it can be replaced or not + (bus_service_set_prohibit_replacement): removed + (bus_service_has_owner): returns TRUE if and owner with + the specified connection exists in the queue + + * dbus/dbus-bus.c (dbus_bus_connection_get_unique_name): New helper + method that only compiles if tests are enabled. Allows us to get the + unique name of a connection so we can check it against the queue when + doing regression tests + + * bus/activation.c (bus_activation_send_pending_auto_activate), + bus/dispatch.c (bus_dispatch), + bus/driver.c (bus_driver_handle_get_service_owner, + bus_driver_handle_get_connection_unix_user, + bus_driver_handle_get_connection_unix_process_id, + bus_driver_handle_get_connection_selinux_security_context), + bus/signals.c (connection_is_primary_owner): + use bus_service_get_primary_owners_connection instead of + bus_service_get_primary_owner + + * dbus/dbus-sysdeps.c (_dbus_connect_unix_socket, + _dbus_listen_unix_socket): Calculate the length of the socket + path and use that instead of using a fixed length which was + causing socket names to contain many trailing Nul bytes. + + * dbus/dbus-glib-lowlevel.h, glib/dbus-gobject.c + (dbus_g_method_get_sender): New method for extracting the sender + from a DBusGMethodInvocation + (dbus_g_method_return_get_reply): changed name to + dbus_g_method_get_reply + (dbus_g_method_return_send_reply): changed name to + dbus_g_method_send reply + + * doc/dbus-specification.xml: New docs that describe how the new + queueing system works and talks about the changes to the how + we specify socket names + + * glib/examples/example-service.c, + glib/examples/example-signal-emitter.c, + glib/examples/statemachine/statemachine-server.c: + Changed the RequestName flags to the new system + + * test/name-test/ (test-names.c, run-test.sh, Makefile.am): New + regression test suite for testing various states of the new + queueing system + +2005-11-15 Robert McQueen + + * dbus/dbus-glib-lowlevel.h, glib/dbus-gobject.c: Patch from Rob + Taylor to add two methods, dbus_g_method_return_get_reply and + dbus_g_method_return_send_reply, to allow you to get the reply + message from a DBusGMethodInvocation, append arbitrary stuff to it, + and send it. The GLib bindings can't marshal a return value of + something like a(s) if the array is empty - ultimately they should be + made to heed the signature of the out arguments as the Python bindings + now can, but this is a workable interim solution which might have + other applications. + +2005-11-15 Robert McQueen + + * bus/driver.c, bus/services.c, bus/services.h: Add a ReleaseName + method to org.freedesktop.DBus to release a bus name or give up + waiting in the queue for it. + + * dbus/dbus-bus.c, dbus/dbus-bus.h, dbus/dbus-shared.h: Add a + dbus_bus_release_name method to send the ReleaseName method calls. + Add constants for the return values to dbus/dbus-shared.h. + + * doc/dbus-specification.xml: Document the new ReleaseName method + in the specification. + + * python/dbus_bindings.pyx: Add a low-level python binding for the + release name method. + + * python/exceptions.py, python/service.py: Make freeing BusName + objects release the name. Add a NameExistsException, and fix a + bug with creating UnknownMethodException. + + * test/python/test-client.py: Add tests for freeing BusName + objects causing names to be released. + +2005-11-14 Robert McQueen + + * python/service.py: Include the traceback in the error reply when we + send an exception over the bus. _BEST_ _PATCH_ _EVER_ + +2005-11-14 David Zeuthen + + Patch from Timo Hoenig . + + * bus/bus.c: I've recently investigated why the automatic reload + of configuration files does not work as expected. + + Currently, reloading configuration files does only work when + running dbus-daemon with --nodaemon. If we are running as daemon + we're hitting a dnotify bug once we fork the process. + + We're initializing the dnotify fds before calling fork(). Once + the child process forked it does still have the fds (and they + still show up in /proc/`pidof dbus-daemon`/fd/) but we're not + getting SIGIO as changes are made to the configuration files. + + The attached patch moves the initialization of the dnotify fds to + process_config_postinit(). This is safe for all current code + paths and solves the dnotify disfunction. If we're running + dbus-daemon as daemon the fds for dnotify are now being + initialized after fork() for the child process. + + * configure.in: The current configure.in check for dnotify probes + 'x$target_os' for being 'xlinux-gnu'. I've changed the check to + match for 'xlinux', too. Additionally I have adapted the configure + option's style to match with the others. + +2005-11-14 Robert McQueen + + * python/decorators.py, python/service.py: Add a new argument to the + dbus.service.method decorator called sender_keyword, which if set, + specifies the name of an argument which will be provided the bus + name of the method caller. + + * test/python/test-client.py, test/python/test-service.py: Add a + method and test to check the sender_keyword functionality. + +2005-11-07 John (J5) Palmieri + + * bus/driver.c (bus_driver_handle_reload_config): Make sure we send an + empty reply so blocking calls don't block forever (Patch from Sjoerd + Simons ) + + * AUTHORS: Add Robert McQueen for his work on the Python + Bindings and other parts of D-Bus + +2005-11-07 Robert McQueen + + * python/decorators.py: Change emit_signal function to use the + signature annotation of the signal when marhsalling the arguments from + the service. Fix a bug where the code checking signature length + against argument length referenced the wrong variable. + + * python/introspect_parser.py: Avoid adding the type signature of + signal arguments to any methods which occur after them in the + introspection data (!) by making the parser a little more careful + about its current state. + + * python/service.py: Remove debug prints from last commit (again :D). + + * test/python/test-client.py, test/python/test-service.py: Add test + signals with signature decorators to test the strict marshalling code + gives errors at the right time. Could do with checking the signals + actually get emitted too, given that the test does nothing with + signals at the moment... + +2005-11-07 Robert McQueen + + * python/_dbus.py: Add WeakReferenceDictionary cache of dbus.Bus + instances to stop madness of creating new instances representing + the same bus connection all the time, rendering any tracking of + match rules and bus names quite meaningless. Caught a bug where + the private argument to SessionBus() and friends was being passed + in as use_default_mainloop by mistake. Still some problems with + multiple dbus_binding.Connection instances representing the same + low-level connection (eg when you use both SessionBus() and + StarterBus() in same process), but it's a lot better now than it + was. + + * python/dbus_bindings.pyx: Add constants with the return values + for bus_request_name(). + + * python/service.py: Store bus name instances in a per-dbus.Bus cache + and retrieve the same instances for the same name, so deletion can be + done with refcounting. Also now throws some kind of error if you + don't actually get the name you requested, unlike previously... + + * test/python/test-client.py: Add tests for instance caching of buses + and bus name objects. + +2005-11-04 Robert McQueen + + * python/dbus_bindings.pyx, test/python/test-client.py: Fix + marshalling of boolean values. Add some booleans to the values in + the test client. + + * python/decorators.py, python/service.py: Add an 'async_callbacks' + argument to the dbus.service.method decorator, which allows you to + name arguments to take two callback functions for replying with + return values or an exception. + + * test/python/test-client.py, test/python/test-service.py: Add test + case using asynchronous method reply functions, both return values and + errors, and from within both the function itself and from a mainloop + callback. + + * python/decorators.py, python/service.py: Perform checking that the + number of method/signal arguments matches the number of types in the + signature at class loading time, not when you first introspect the + class. + + * python/service.py: Remove debug print left by the last commit. + +2005-11-03 Robert McQueen + + * python/service.py: Heavy refactoring of method invocation, with + hopefully no effect on functionality. Nuked _dispatch_dbus_method_call + in favour of a new _message_cb that uses seperate functions for + looking up the method to call, marshalling the return values, and + sending exceptions as errors, and is easier to follow as a + consequence. Fixes some corner cases about returning things that + don't match your declared out_signature, allows exceptions to define + _dbus_error_name and have it be sent over the bus as the error name, + and paves the way for cool stuff like heeding the message no reply + flag, asynchronous method implementations, informing the method of the + sender, and including backtraces in the error messages. + + * test/python/test-client.py: Catch and print exceptions thrown in the + async callback tests, rather than passing them to the low-level + bindings to be ignored in a noisy and frustrating manner. + +2005-11-03 Robert McQueen + + * python/_dbus.py, python/proxies.py, python/service.py: Add __repr__ + functions to dbus.Bus, dbus.service.BusName and dbus.service.Object, + tweak others to be consistent. + + * test/python/test-client.py: Tweak output of testInheritance. + +2005-10-29 Robert McQueen + + * python/service.py: Major changes to allow multiple inheritance + from classes that define D-Bus interfaces: + + 1. Create a new Interface class which is the parent class of + Object, and make the ObjectType metaclass into InterfaceType. + + 2. Patch written with Rob Taylor to replace use of method_vtable + with code that walks the class's __MRO__ (method resolution order) + to behave like Python does when invoking methods and allow + overriding as you'd expect. Code is quite tricky because + we have to find two methods, the one to invoke which has the + right name and isn't decorated with the /wrong/ interface, + and the one to pick up the signatures from which is decorated + with the right interface. + + The same caveats apply as to normal multiple inheritance - + this has undefined behaviour if you try and inherit from two + classes that define a method with the same name but are + decorated with different interfaces. You should decorate + your overriding method with the interface you want. + + 3. Replace grungy introspection XML generation code in the metaclass + with dictionaries that cope correctly with multiple inheritance + and the overriding of methods. This also uses the signature + decorations to provide correct introspection data, including + the debut appearance of the types of your return values. :D + + * test/python/test-client.py, test/python/test-service.py: Add a test + case to try invoking an method that overrides one inherited from a + D-Bus interface class. + +2005-10-29 Robert McQueen + + * python/dbus_bindings.pyx: Tweak 'raise AssertionError' to assert(). + Add checking for the end of struct character when marshalling a + struct in MessageIter.append_strict. + + * python/examples/example-service.py, + python/examples/gconf-proxy-service.py, + python/examples/gconf-proxy-service2.py: Update to use gobject + mainloop directly rather than appearing to depend on gtk. + + * python/test/test-client.py, python/test/test-server.py: Remove + obsolete and broken test scripts for old bindings. We have up to date + and working tests in test/python/. + +2005-10-29 Robert McQueen + + * python/decorators.py: Add optional arguments to the method and + signal decorators to allow you to specify the signature of arguments + and return values. Preserve the doc strings of signal functions in the + decorated version, for pydoc and friends. + + * python/dbus_bindings.pyx, python/proxies.py: Replace the + parse_signature_block function with an iterable dbus.Signature() + type. Fix a bug in MessageIter.append_strict where you could append + anything by claiming it was a string. + + * python/service.py: Use the out_signature decoration on methods to + marshal return values, meaning you no longer require dbus.Array() + or dbus.Dictionary() to indicate the type when returning empty + arrays or dictionaries. Fix a bug where exceptions which are defined + in __main__ are not turned into error replies. + + * test/python/test-client.py, test/python/test-service.py: Add test + for correct marshalling of return values according to out_signature. + Fix a bug in the async call test where the error_handler is missing a + self argument. + +2005-10-29 Robert McQueen + + * glib/Makefile.am, glib/examples/Makefile.am, + glib/examples/statemachine/Makefile.am: Merge patch from Ubuntu by + Daniel Stone to replace explicit calls to libtool with $(LIBTOOL). + + * test/python/.cvsignore: Add run-with-tmp-session-bus.conf. + + * tools/dbus-monitor.1, tools/dbus-monitor.c: Merge dbus-monitor patch + from Ubuntu by Daniel Silverstone to allow specifying match rules on + the command line. + +2005-10-27 Ross Burton + + * dbus/dbus-marshal-header.c: + Remove dead code. + + * glib/dbus-gobject.c: + Stop compiler warning. + +2005-10-25 Ross Burton + + * dbus/dbus-auth.c: + * dbus/dbus-server-unix.c: + * dbus/dbus-transport-unix.c: + * glib/dbus-gmain.c: + * glib/dbus-gobject.c: + Add some const keywords. + +2005-10-25 Ross Burton + + * doc/dbus-specification.xml: + Document the NoReply annotation. + + * glib/dbus-binding-tool-glib.h: + * glib/dbus-binding-tool-glib.c: + Respect the NoReply annotation. + +2005-10-24 Robert McQueen + + * python/dbus_bindings.pyx (String, MessageIter): make D-Bus strings + derive from unicode instead of str, and encode/decode UTF-8 when + marshalling/unmarshalling bus messages + + * python/introspect_parser.py: encode introspection data as UTF-8 + before passing the buffer into libxml2 + + * test/python/test-client.py: add unicode test strings + + * test/data/valid-service-files/.cvsignore, test/python/.cvsignore: + ignore generated python test files + +2005-10-17 John (J5) Palmieri + + * glib/dbus-gvalue-utils.c (hash_free_from_gtype): handle gdouble + and G_TYPE_VALUE_ARRAY (DBUS_TYPE_STRUCT) + (gvalue_from_hash_value, hash_value_from_gvalue): handle gdouble + + * glib/dbus-gvalue.c (dbus_gvalue_to_signature): add missing + DBUS_STRUCT_BEGIN_CHAR and DBUS_STRUCT_END_CHAR charaters + when constructing struct signatures + + * python/_dbus.py (Bus): handle private connections using the + private keyword in the constructor. defaults to private=False + (Bus::close): new method to close a connection to the bus + + * python/dbus_bindings.pyx (Connection::close): renamed method + was previously called disconnect + (bus_get): now supports getting a private connection + + * python/proxies.py (ProxyMethod::__call__): check if ignore_reply + keyword is set to True. if it is, execute the method without waiting + for a reply + (ProxyObject::_introspect_execute_queue): new method for executing + all the pending methods that were waiting for the introspect to + finish. this is called when introspect either succeeds or fails + (ProxyObject::_introspect_error_handler): call queued methods + +2005-10-14 John (J5) Palmieri + + * python/dbus_bindings.pyx (MessageIter::append_strict): check for + STRUCT_BEGIN not TYPE_STRUCT in indicate we are marshalling a struct + + * python/service.py (Object::_message_cb): handle exceptions correctly + by sending them over the wire to the calling app. This makes sure + the client returns immediately instead of waiting the 15 seconds to + timeout. + + * test/python/test-client.py (TestDBusBindings::testBenchmarkIntrospect): + Add a test to benchmark how long it takes to introspect a service and + call a method which returns a large element (pretty fast) + + * test/python/test-service.py (TestObject::GetComplexArray): new test + method which pushes a lot of data + +2005-10-13 John (J5) Palmieri + + * python/service.py(ObjectType::_reflect_on_signal, _reflect_on_method): + reclaim memory outside of the loop and use del istead of just setting + the key to None + +2005-10-13 John (J5) Palmieri + + * python/service.py (ObjectType::_reflect_on_signal): Always close + signal tag even when there are no arguments + +2005-10-13 John (J5) Palmieri + + * configure.in: Set mono, mono-docs and Qt3 to default + to no instead of auto when building. These bindings do not + have full time maintainers and will not be supported for the + 1.0 release. + +2005-10-12 John (J5) Palmieri + + patches from Michael Krivoruchko : + + * dbus/dbus-connection.c (_dbus_connection_queue_received_message_link, + _dbus_connection_message_sent, + _dbus_connection_send_preallocated_unlocked_no_update, + _dbus_connection_pop_message_link_unlocked): handle the case when path + is NULL when calling _dbus_verbose + + * configure.in: check for functions getpeerucred and getpeereid + + * dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): provides + support of auth EXTERNAL on Solaris 10+ (getpeerucred), FreeBSD 4.6+, + OpenBSD 3.0+ and FreeBSD 5.0+ as well as MacOSX 10.2+ (getpeereid). + Patch was only tested on Solaris 10 x86 so it might be issues + with other platforms (i.e. BSDs and MacOSX) + + +2005-10-05 John (J5) Palmieri + + * glib/dbus-gvalue.c (marshal_variant): call _dbus_gvalue_marshal + instead of marshal basic so we can handle recursive types in a variant + + * test/glib/test-dbus-glib.c: Add test for marshaling recurive types + in variants + + * test/glib/test-service-glib.c, test-service-glib.xml + (my_object_echo_variant [EchoVariant], + my_object_process_variant_of_array_of_ints123 + [ProcessVariantOfArrayOfInts123]): + Add two test methods + + * python/introspect_parser.py: New module for parsing introspect + data. + + * python/dbus_bindings.pyx: + (various places): when throwing errors fix to use errormsg instead + of message local variable because Pyrex can get confused with other + message variables (initial patch by Robert McQueen + ) + (MessageIter::parse_signature_block): new method for getting the next + block in a signiture. + (MessageIter::append_strict): new method for appending values strictly + using the passed in signature instead of guessing at the type + (MessageItter:: append_dict, append_struct, append_array): use + signatures to marshal children if the signature is available + + * python/exceptions.py (IntrospectionParserException): new exception + + * python/proxies.py (ProxyMethod::__call__): Marshal args with + introspected signatures if available, else we fall back to the + old way of doing things. + (ProxyObject::_introspect_reply_handler ): parse introspection data + + * python/service.py (ObjectType::_reflect_on_method): Properly + terminate if there are no args in the reflection data + + * test/python/test-client.py: add tests for talking with the GLib + test server. This gives us better coverage for introspection since + python to python will always generate arguments as variants. It also + allows us to test the robustness of the GLib bindings and interlanguage + communications. + + +2005-10-03 John (J5) Palmieri + + * bus/driver.c (bus_driver_handle_introspect): Add signals + to the introspect data. (patch from Daniel P. Berrange + ) + + * bus/dispatch.c (check_existent_ping): Add testcase for Ping + + * dbus/dbus-connection.c (_dbus_connection_peer_filter, + _dbus_connection_run_builtin_filters): Changed these to + be unlock_no_update functions and call + _dbus_connection_send_unlocked_no_update instead of + dbus_connection_send to avoid locking errors. + + * doc/TODO: Removed the make Ping test TODO + +2005-09-26 John (J5) Palmieri + + * dbus/Python.pyx: Fixed memory leaks when throwing errors. + We now copy the message from a DBusError and then free + the error object befor throwing the error + + * glib/dbus-glib-tool.c: removed extra comma at the end of the + DBusBindingOutputMode enum which was causing a warning. + #include so using time_t is explicitly defined + +2005-09-26 John (J5) Palmieri + + * Integrate patches from Lennart Poettering : + - dbus/dbus-bus.c + (internal_bus_get): new method that take over the heavy lifting + of dbus_bus_get and adds the ability to get a private connection + to the bus + (dbus_bus_get): wrapper to internal_bus_get that provides the same + interface as in previous versions + (dbus_bus_get_private): new method that is a wrapper to + internal_bus_get to get a private connection to the bus + + - dbus/dbus-bus.h + (dbus_bus_get_private): add as a public libdbus interface + + - dbus-1.pc.in: output system_bus_default_address and + sysconfdir variables so apps can use them when compiling + +2005-09-23 Harald Fernengel + * dbus/qt: New Qt bindings + +2005-09-12 Waldo Bastian + + * dbus/dbus-marshal-validate.c, + doc/dbus-specification.xml, test/Makefile.am, + test/test-names.c: allow hyphens in bus names. + +2005-09-11 Mark McLoughlin + + * test/data/auth/fallback.auth-script: we don't + retry the EXTERNAL method when we know its going + to fail anymore. + +2005-09-11 Mark McLoughlin + + * dbus/dbus-connection-internal.h: rename + (add|remove|toggle)_(watch|timeout) to unlocked() + + * dbus/dbus-connection.c: ditto. + + * dbus/dbus-timeout.c, dbus/dbus-transport-unix.c: + Update some callers for the renaming. + +2005-09-10 Mark McLoughlin + + * dbus/dbus-auth.c: (record_mechanisms): don't + retry the first auth mechanism because we know + we're just going to get rejected again. + + * dbus/dbus-keyring.c: (_dbus_keyring_reload): + Fix thinko ... and what a nasty little bugger to + track down you were ... + + * dbus/dbus-connection.c: + (_dbus_connection_add_watch), + (_dbus_connection_remove_watch): add note about + these needing the connection to be locked. + (_dbus_connection_get_dispatch_status_unlocked): + set status to DATA_REMAINS when we queue the + disconnected message. + + * bus/dispatch.c: + (bus_dispatch): fix warning. + (check_existent_service_no_auto_start): + Expect ChildSignaled error too. + (check_existent_hello_from_self): fix another + couple of warnings. + +2005-09-08 Joe Shaw + + Patches from James Willcox + + * mono/Makefile.am: Add Int16.cs and UInt16.cs + + * mono/DBusType/Array.cs: Handle multidimensional arrays, and + support array "out" parameters. + + * mono/DBusType/Int16.cs, mono/DBusType/UInt16.cs: New files, + for 16-bit int support. + +2005-09-06 John (J5) Palmieri + + * Released 0.50 + + * Patch from Steve Grubb: + - bus/activation.c (bus_activation_service_reload_test): clean up + some indentation + - dbus/dbus-keyring.c (_dbus_keyring_reload): fix conditional + - dbus/dbus-message-factory.c (generate_special): fix a couple of + buffer overflows in the test suite. This is non critical because + it can not be exploited and this code is only run when doing a + make check. + + * Patch from Yaakov Selkowitz: Build fixes for Cygwin + - configure.in: Don't check and link against kdecore, only qt headers + - dbus/Makefile.am: Add -no-undefined to libdbus_1_la_LDFLAGS + - gcj/org/freedesktop/dbus/Makefile.am: + add libdbus_gcj_1_la_LDFLAGS = -no-undefined + - glib/Makefile.am: Add -no-undefined to libdbus_glib_1_la_LDFLAGS + and $(DBUS_GLIB_LIBS) to dbus_binding_tool_LDADD + - qt/Makefile.am: Add -no-undefined to libdbus_qt_1_la_LDFLAGS + - tools/Makefile.am: Add platform extentions to binaries + (i.e. .exe on windows) + + * configure.in: + - Make it so if no suitable version of python is found we only + disable building python instead of exiting the configure script + - Require version 2.4 of glib for glib bindings + - Up version to 0.50 + + * python/__init__.py: Sync version with libdbus to (0,50,0) + +2005-09-05 Olivier Andrieu + + * dbus/dbus-object-tree.c (find_subtree_recurse): + a couple of optimizations (bug #710): + - do a binary search in the tree + - insert a new child at the right place directly, no need for + qsort anymore + - do the "double alloc" thing when allocating children + +2005-08-31 John (J5) Palmieri + + * python/Makefile.am: Break on pyrexc errors instead of ignoring them + + * python/dbus_bindings.pyx: Memory management foo + (global): remove hacky _user_data_references global list + (GIL_safe_cunregister_function_handler): userdata now stuffed into + tuples. Unref user_data + (GIL_safe_cmessage_function_handler): userdata now stuffed into tuples + (Connection::__del__): Remove and replace with __dealloc__ method + (Connection::add_filter): Stuff user_data into a tuple. Use Py_INCREF + to keep tuple from being deallocated instead of the global var hack + (Connection::register_object_path): Stuff user_data into a tuple. + Use Py_INCREF to keep tuple from being deallocated instead of the + global var hack + (Connection::register_fallback): Stuff user_data into a tuple. + Use Py_INCREF to keep tuple from being deallocated instead of the + global var hack + (GIL_safe_pending_call_notification): Don't unref the message + because it gets unreffed when going out of scope. Py_XDECREF + the user_data + (PendingCall::__del__): Remove and replace with __dealloc__ method + (PendingCall::set_notify): ref the pending call because we will + need it to stick around for when the notify callback gets called + (Message::__del__): Remove and replace with __dealloc__ method + + * python/dbus_glib_bindings.pyx (init_gthreads): Changed to + gthreads_init to match up with the dbus call + + * python/glib.py (init_threads): Changed to threads_init to match + up with gobject.threads_init(). init_threads is kept for backwards + compat but will most likely be deprecated in the future + + * test/python/test-client.py: + - revamp to use Python's unittest functionality + - add async call tests + - setup threads in glib and dbus so we make sure locks are working + +2005-08-30 John (J5) Palmieri + + * python/dbus_bindings.pyx + (_pending_call_notification, cunregister_function_handler, + cmessage_function_handler): All callback functions have been rearranged + to workaround a bug in Pyrex when working with the GIL which is Python's + global lock when dealing with threads. They have been split into + a wrapper function (which assumes the name of the old function) and + a _GIL_safe_ function which contains the functionality + of the old function. This ensures that Pyrex does not write code + the lock is released. + + +2005-08-30 John (J5) Palmieri + + * python/dbus_bindings.pyx (_pending_call_notification): Obtain the + GIL global lock when calling back into Python + +2005-08-29 John (J5) Palmieri + + * Release 0.36.2 + + * Add Havoc's patch that never got applied to HEAD (Bug #2436): + + * bus/policy.c (bus_policy_allow_user): change default "user is + allowed" to be "user has same uid as the bus itself"; any + allow/deny rules will override. + + * bus/session.conf.in: don't allow all users, since now by default + the user that ran the bus can connect. + +2005-08-26 Colin Walters + + * tools/dbus-print-message.c (print_message): Flush stdout + after printing a message, so that redirecting to a file, then + hitting Ctrl-C works. + +2005-08-25 John (J5) Palmieri + + * python/dbus_bindings.pyx: Tracked down a major memleak and fixed it + (EmptyMessage): new class that subclasses Message. This is a workaround + to a Pyrex bug that fails to call __del__ when the Message object goes out + of scope. For some reason subclassing Message fixes this bug + (Bus::send_with_reply_and_block): use EmptyMessage instead of Message + - s/Message(_create=0)/EmptyMessage everywhere else + + * test/python/test-{server|client}.py: add the python/.libs directory + to the lookup path so dbus_bindings and dbus_glib_bindings don't + get picked up from the system + +2005-08-25 Colin Walters + + * glib/dbus-gproxy.c (dbus_g_proxy_call): Doc update, thanks + to Ryan Lortie for the suggestion. + +2005-08-24 John (J5) Palmieri + + * test/python: Add python regression test + + * configure.in: Add test/python/Makefile + + * test/Makefile.am: Add the python directory to SUBDIRS + +2005-08-24 John (J5) Palmieri + + * Release 0.36.1 + + * python/_dbus.py: + (Interface::connect_to_signal): propigate keywords for match on args + (Bus::add_signal_receiver): Fix typo s/dbus_inteface/dbus_interface + + * python/proxies.py (ProxyObject::connect_to_signal): + propigate keywords for match on args + + * Makefile.am: point everything to pyexecdir since python borks + on multilib + +2005-08-23 John (J5) Palmieri + + * Release 0.36 + +2005-08-23 Colin Walters + + * test/glib/Makefile.am: Don't multiply-define EXTRA_DIST. + +2005-08-23 John (J5) Palmieri + + * python/dbus_glib_bindings.pyx: reorder imports and c definitions + to fix some wranings. We now use dbus_bindings.DBusConnection instead + of defining DBusConnection ourselves. + +2005-08-18 John (J5) Palmieri + + * python/dbus.pth: New path file to fix up problems when installing + c libraries to lib64 and python files to lib. + + * python/Makefile.am: install dbus.pth in the correct spot + +2005-08-17 John (J5) Palmieri + * ChangeLog: clean up my last entry a bit + + * doc/introspect.xsl: New stylesheet for converting introspection data + into browser renderable xhtml. Contributed by Lennart Poettering. + + * doc/introspect.dtd: Fixups in the introspect format from Lennart + Poettering. + + * doc/dbus-tutorial.xml: + - Add Colin Walter to the Authors section for authoring the GLib + section + - Add descriptions of the new signature and type functionality + in the Python complex type mapping section + - Add a sidenote on the new args matching functionality in + the Python bindings + - Fixed up some of the examples to use the gobject.MainLoop + instead of gtk.main + + * python/_dbus.py: + (Bus::_create_args_dict): New. Converts a hash of arg matches + to a more useable format + (Bus::add_signal_receiver): add a **keywords parameter for catching + arg match parameters + (Bus::remove_signal_receiver): add a **keywords parameter for catching + arg match parameters + + * python/matchrules.py: + (MatchTree::exec_matches): Check for arg matches + (SignalMatchRule::add_args_match): New method + (SignalMatchRule::execute): Added args_list parameter as an optimization + so we don't have to marshal the args more than once + (SignalMatchRule::match_args_from_list): New method that checks to see + if the rule's arg matches match an argument list. Only arguments + set in the rule are checked. + (SignalMatchRule::match_args_from_rule): New method that checks to see + if the rule's arg matches match another rule's. All args have to match + in order for this method to return true. If either rule has more args + then it is not a match. + (SignalMatchRule::is_match): Add args match + (SignalMatchRule::repr): Add args to the final output if they exist + +2005-08-17 Ross Burton + + * glib/dbus-gproxy.c: + (dbus_g_proxy_call_no_reply): unref the message once sent. + (dbus_g_proxy_call): protect against NULL proxy. + +2005-08-16 John (J5) Palmieri + + * python/__init__.py: Version updated (0, 43, 0) + + * python/dbus_bindings.pyx: + - Fixed type objects to have self passed into __init__ + - Added the Variant type + - Add the ability to specify types or signatures for Array, Variant + and Dictionary + (Connection::send_with_reply_handlers): return a PendingCall object + (_pending_call_notification): handle the case when an error is returned + without an error message in the body + (MessageIter::get_boolean): return True or False instead of an integer + (MessageIter::python_value_to_dbus_sig): add direct checking of types + and add checks for objects with embeded signatures or types (Array, + Variant and Dictionary) + (MessageIter::append_byte): handle case when the value is a dbus.Byte + (MessageIter::append_dict): handle embeded types or signatures + (MessageIter::append_array): handle embeded types or signatures + (MessageIter::append_variant): new method + + * python/proxies.py: + (DeferedMethod): New. Dummy executable object used when queuing calls + blocking on introspection data + (ProxyMethod::__call__): add the timeout keyword for specifying longer + or shorter timeouts for method calls + (ProxyObject): Add first pass at an introspection state machine + (ProxyObject::__init__): Add introspect keyword for turing off an on + introspection. + (ProxyObject::_Introspect): Internal Introspect call that bypasses + the usual mechanisms for sending messages. This is to avoid a deadlock + where the Intospect call would be queued waiting for the Introspect + call to finish ;-) + (ProxyObject::_introspect_reply_handler): New. This method is called + when introspection returns with no error + (ProxyObject::_introspect_error_handler): New. This method is called + when introspection encounters an error + (ProxyObject::__getattr__): Code to handle different introspection + states. Queue async calls or block blocking calls if we are + introspecting. Pass through as normal if we are not or are done with + introspecting. + + * python/service.py: Import signal and method from decorators.py + + * python/types.py: Add Variant type + +2005-08-16 Colin Walters + + * glib/dbus-gobject.c (dbus_set_g_error): Don't lose if the + DBusError message is NULL. + +2005-08-09 Havoc Pennington + + * dbus/dbus-errors.c: apply patch from Timo Teras to make a + malloc'd copy of the name parameter + +2005-08-09 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_set_reply_serial): print + warning if the reply serial is set to 0 + +2005-08-04 Colin Walters + + * glib/dbus-gvalue-utils.h (_dbus_g_type_specialized_builtins_init) + (dbus_g_type_is_fixed, dbus_g_type_fixed_get_size) + (dbus_gvalue_set_from_pointer, dbus_g_hash_table_value_foreach) + (dbus_g_hash_table_insert_values, dbus_g_hash_table_insert_steal_values) + (dbus_gtype_is_valid_hash_key, dbus_gtype_is_valid_hash_value) + (dbus_g_hash_func_from_gtype, dbus_g_hash_free_from_gtype) + (dbus_g_hash_equal_from_gtype, dbus_gvalue_stor, dbus_gvalue_take): + * glib/dbus-gvalue.h (dbus_g_value_types_init) + (dbus_gvalue_demarshal, dbus_gvalue_demarshal_variant) + (dbus_gvalue_demarshal_message, dbus_gvalue_marshal): + + Prefix name with _ to ensure they're not exported. All callers + updated. + + * glib/dbus-gvalue.c (typecode_to_gtype) + (dbus_typecode_maps_to_basic, basic_typecode_to_gtype) + (signature_iter_to_g_type_dict) + (signature_iter_to_g_type_array) + (dbus_gtype_from_signature_iter, dbus_gtype_from_signature) + (dbus_gtypes_from_arg_signature): + Move to dbus-gsignature.c. + + * glib/dbus-binding-tool-glib.c (dbus_binding_tool_output_glib_server): Call + dbus_g_type_specialized_builtins_init instead of dbus_g_value_types_init. + (dbus_binding_tool_output_glib_client): Ditto. + + * glib/Makefile.am (DBUS_GLIB_INTERNALS): Add dbus-gsignature.c + and dbus-gsignature.h + + * test/glib/test-service-glib.c (my_object_rec_arrays): Delete + unused variable. + +2005-08-03 Colin Walters + + * glib/dbus-gobject.c: Add tests on hardcoded object info; this should + catch any incompatible changes accidentally made. + +2005-08-03 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): fix + typo, from Julien Puydt + + * bus/connection.c (bus_connection_disconnected): we were always + doing a wait_for_memory due to a buggy loop, found by Timo Hoenig + +2005-08-01 Colin Walters + + Patch from Joe Markus Clarke: + + * glib/dbus-gidl.c (property_info_unref, arg_info_unref): Fix + use-after-free. + +2005-08-01 Colin Walters + + Patch from Joe Markus Clarke: + + * tools/dbus-send.c (main): + + Don't use C99 style initializers (bug #3933). + +2005-08-01 Colin Walters + + Patch from Joe Markus Clarke: + + * glib/dbus-gvalue.c (dbus_g_value_types_init): + * glib/dbus-gvalue-utils.c (dbus_g_type_specialized_builtins_init) + * glib/dbus-gobject.c (write_interface): + + Don't use C99 style initializers (bug #3933). + +2005-07-31 Havoc Pennington + + * tools/dbus-viewer.c (load_child_nodes): fix invocation of + dbus_g_proxy_call, fix from Piotr Zielinski bug #3920 + +2005-07-30 Havoc Pennington + + * fix a bunch of Doxygen warnings and mistakes + +2005-07-30 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_string_parse_uint): remove #ifdef + DBUS_BUILD_TESTS since it's now used in production code + +2005-07-29 Havoc Pennington + + * test/glib/test-profile.c (write_junk): initialize the junk + buffer so valgrind doesn't have a breakdown + +2005-07-29 Havoc Pennington + + * bus/signals.c (bus_signals_test): add match_rule_equal() tests + (match_rule_matches): remove unused arg + (test_matching): add tests for match_rule_matches() + + * bus/signals.c (bus_match_rule_parse_arg_match): add ability to + do arg0='foo' arg5='bar' in the match rules + (match_rule_matches): don't match if the arg0='foo' doesn't match. + + * dbus/dbus-protocol.h (DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER): add this + +2005-07-29 Ross Burton + + * dbus/dbus-connection.c: + Don't create a DBusCondVar which is never used. + +2005-07-27 Ross Burton + + * dbus/dbus-message.c: + Reduce the size of the maximum cached message to 10K. + +2005-07-25 Ross Burton + + * glib/dbus-gproxy.c: + Remove matches when all proxies are unregistered. + +2005-07-24 Colin Walters + + * glib/dbus-gvalue.c (signature_iter_to_g_type_array): Don't require + typedata; recursive arrays won't have it. + + * test/glib/test-dbus-glib.c: + * test/glib/test-service-glib.c: + * test/glib/test-service-glib.xml: Add recursive arrays tests. + +2005-07-20 John (J5) Palmieir + + * python/_dbus.py, _util.py, decorators.py, extract.py, matchrules.py. + proxies.py, service.py: Cleanup of code after running it through the + pyflakes code checker mostly dealing with undefined names. + (Bug #3828, Patch from Anthony Baxter ) + +2005-07-17 John (J5) Palmieri + + * NEWS: Update to 0.35.2 + +2005-07-17 John (J5) Palmieri + + * python/_dbus.py: Remove import of the dbus.services + module as it no longer exists (patch from Dimitur Kirov) + + * python/service.py (Object::__init__): Fixed typo + s/name/bus_name (patch from Dimitur Kirov) + + * python/examples/example-signal-emitter.py: import dbus.glib + to get the main loop and use glib mainloop instead of gtk so + X doesn't have to be running. + + * python/examples/example-signal-recipient.py: import dbus.glib + to get the main loop and use glib mainloop instead of gtk so + X doesn't have to be running. Import the decorators module + directly. + + * test/glib/Makefile.am: Added DIST_EXTRA files that distcheck + didn't pick up on but are needed to build + + * configure.in: upped version to 0.35.2 + + * bus/driver.c, bus/selinux.c, bus/selinux.h, dbus/dbus-protocol.h: + added Colin Walters' SELinux API rename patch from head + s/unix sercurity context/selinux security context/ + +2005-07-16 John (J5) Palmieri + + * python/Makefile.am: dbus_binding.pxd.in should be included + in EXTRA_DIST not dbus_binding.pxd + fix up $(srcdir) hopefully for the last time + + * NEWS: Update to 0.35.1 + +2005-07-16 Colin Walters + + * bus/driver.c (bus_driver_handle_get_connection_selinux_security_context): Renamed + from bus_driver_handle_get_connection_unix_security_context. Update for + error usage. + (message_handlers): Update for renames. + + * bus/selinux.c (bus_selinux_allows_send): Handle OOM on + _dbus_string_init failure correctly. + (bus_selinux_append_context): Convert SID to context. Append it + as a byte array. + (bus_selinux_shutdown): Handle the case where bus_selinux_full_init + hasn't been called. + + * bus/selinux.h: Update prototype. + + * dbus/dbus-protocol.h (DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN): Renamed + from DBUS_ERROR_UNIX_SECURITY_CONTEXT_UNKNOWN. + +2005-07-15 Colin Walters + + * doc/TODO: Add note about convenience wrappers. + +2005-07-15 John (J5) Palmieri + + * NEWS: Update to 0.35 + +2005-07-15 John (J5) Palmieri + + * glib/Makefile.am: Add make-dbus-glib-error-switch.sh to EXTRA_DIST + so distcheck doesn't fail + + * glib/examples/Makefile.am: Add example-service.xml and + example-signal-emitter.xml to EXTRA_DIST so distcheck doesn't fail + + * glib/examples/statemachine/Makefile.am: Add statemachine.xml and + statemachine-server.xml to EXTRA_DIST so distcheck doesn't fail + + * python/Makefile.am: Preprend $(srcdir)/ to source files so the + compiler looks in the right places during distcheck + +2005-07-15 John (J5) Palmieri + + * glib/example/Makefile.am: Fix a typo which cause make distcheck + to fail + +2005-07-15 John (J5) Palmieri + + * python/examples/example-service.py, + python/examples/example-signal-emitter.py: Fixed up examples + for API changes + +2005-07-15 John (J5) Palmieri + + * python/__init__.py: Upped to version (0,42,0) because of + the API change + +2005-07-15 John (J5) Palmieri + + * ChangeLog: fix date in last entry + + * configure.in, bus/system.conf.in: add the ability to configure + the system bus user at compiletime with the --with-dbus-user flag + (patch from Kristof Vansant) + +2005-07-15 John (J5) Palmieri + + * bus/dispatch.c, test/test-service.c: Add testcase + for sending messages to oneself (TODO item). + + * python/service.py (class Object): Swap ordering of bus_name + and object_path parameters to better support inheritance. + + * doc/dbus-tutorial.xml: change Python docs to reflect change + in parameter ordering and fix the inheritance section. + + * doc/TODO: remove sending message to oneself TODO item + +2005-07-15 Ross Burton + + * glib/dbus-gproxy.c: + Fix a leak when calling methods via the proxy. + +2005-07-15 Colin Walters + + * bus/selinux.c (bus_selinux_append_context): Wrap in + HAVE_SELINUX. + +2005-07-14 John (J5) Palmieri + + * python/_dbus.py (Bus::remove_signal_receiver): + don't add a callback to the match if none has been passed in + + * python/matchrules.py (SignalMatchTree::remove): if the rule + being matched does not have a callback treat it as a wildcard + fix matching logic + + * doc/dbus-tutorial.xml: Add Python tutorial + +2005-07-14 Colin Walters + + * bus/driver.c + (bus_driver_handle_get_connection_unix_security_context): New function. + (message_handlers): Add. + + * bus/selinux.c (bus_selinux_append_context): New function; appends + security context to message. + + * bus/selinux.h: Prototype. + + * dbus/dbus-protocol.h (DBUS_ERROR_UNIX_SECURITY_CONTEXT_UNKNOWN): New. + +2005-07-14 John (J5) Palmieri + + * bus/activation.c: clean up all tabs to be 8 spaces + (bus_activation_activate_service): make sure we clean up + if activation fails + + * bus/dispatch.c: clean up all tabs to be 8 spaces + (check_shell_fail_service_auto_start): New function + tests to make sure we get fail properly when trying to auto start a service + with a faulty command line + (check_shell_service_success_auto_start): New function tests to make sure + auto started services get the arguments on the command line + + * test/test-shell-service.c: Added service for testing auto-starting with + command line arguments + + * test/data/valid-service-files/debug-shell-echo-fail.service.in, + test/data/valid-service-files/debug-shell-echo-success.service.in: + Added service files for testing auto-starting with command line arguments + + * */.cvsignore: added a bunch of generated files to various .cvsignore files + +2005-07-14 Rodrigo Moya + + * dbus/dbus-shell.[ch]: copy/pasted code from GLib. + + * dbus/Makefile.am: added new files to build. + + * bus/activation.c (bus_activation_activate_service): support + activation commands with parameters. + + * test/shell-test.c: added test program for the shell parsing + code. + +2005-07-13 David Zeuthen + + * tools/dbus-send.c (append_arg, type_from_name): Also support 16 and + 64 bit signed and unsigned parameters + +2005-07-13 John (J5) Palmieri + + * python/.cvsignore: remove dbus_bindings.pyx, add dbus_bindings.pxd + + * python/service.py (class Name): renamed BusName to make it clearer + what the object is for (a name on the bus) + + * python/examples/example-service.py, + python/examples/example-signal-emitter.py: change the Name object to + BusName + +2005-07-12 Colin Walters + + Patch from Jim Gettys . + + * tools/dbus-launch.c: Include sys/select.h. + +2005-07-12 John (J5) Palmieri + * python/dbus_bindings.pyx.in: removed + + * python/dbus_bindings.pyx: Added. + - Fixed some memleaks (patch from + Sean Meiners ) + - Broke out the #include "dbus_h_wrapper.h" and put it in its + own pxd file (Pyrex definition) + - Broke out glib dependancies into its own pyx module + + * python/dbus_bindings.pdx: Added. + - Defines C class Connection for exporting to other modules + + * python/dbus_glib_bindings.pyx: Added. + - New module to handle lowlevel dbus-glib mainloop integration + + * python/glib.py: Added. + - Registers the glib mainloop when you import this module + + * python/services.py: Removed (renamed to service.py) + + * python/service.py: Added. + - (class Server): renamed Name + + * python/__init__.py: Bump ro version (0,41,0) + -don't import the decorators or service module + by default. These now reside in the dbus.service namespace + + * python/_dbus.py (Bus::__init__): Add code run the main loop + setup function on creation + + * python/examples/example-service.py, + python/examples/example-signal-emitter.py: update examples + + * python/examples/gconf-proxy-service.py, + python/examples/gconf-proxy-service2.py: TODO fix these up + + * doc/TODO: Addition + - Added a Python Bindings 1.0 section + - added "Add match on args or match on details to match rules" + + +2005-07-12 Colin Walters + + * glib/examples/statemachine/Makefile.am (statemachine-server-glue.h) + (statemachine-glue.h): + * glib/examples/Makefile.am (example-service-glue.h) + (example-signal-emitter-glue.h): + * glib/Makefile.am (dbus-glib-error-switch.h): + Add libtool --mode=execute so we use the built library instead + of any installed one. + +2005-07-11 Colin Walters + + * glib/dbus-gvalue.c (struct _DBusGValue): Delete. + (dbus_g_value_types_init): Remove assertion. + (dbus_g_value_get_g_type, dbus_g_value_open) + (dbus_g_value_iterator_get_values, dbus_g_value_get_signature) + (dbus_g_value_copy, dbus_g_value_free): Delete unimplemented + functions related to DBusGValue. Now we marshal/demarshal + structures as GValueArray. + (dbus_gtype_from_signature_iter): Return G_TYPE_VALUE_ARRAY for + structures. + (signature_iter_to_g_type_array): Don't call + signature_iter_to_g_type_struct. + (signature_iter_to_g_type_struct): Delete. + (dbus_gvalue_to_signature): Delete. + (dbus_gvalue_to_signature): New function with same name as other + one; we can convert structures to signatures. + (demarshal_valuearray): New function. + (get_type_demarshaller): Use it. + (demarshal_recurse): Delete. + (marshal_proxy): New function. + (marshal_map): Warn if we can't determine signature from type. + (marshal_collection_ptrarray): Ditto. + (marshal_collection_array): Ditto. + (get_type_marshaller): Use marshal_valuearray. + (marshal_recurse): Delete. + (_dbus_gvalue_test): Add some tests. + + * dbus/dbus-glib.h (struct _DBusGValueIterator): + (dbus_g_value_get_g_type, DBUS_TYPE_G_VALUE) + (dbus_g_value_open, dbus_g_value_iterator_get_value) + (dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse) + (dbus_g_value_free): Remove prototypes. + + * glib/dbus-binding-tool-glib.c (dbus_g_type_get_lookup_function): Handle + G_TYPE_VALUE_ARRAY. + + * glib/examples/example-service.c: + * glib/examples/example-client.c: Implement GetTuple. + + * test/glib/test-dbus-glib.c: + * test/glib/test-service-glib.c: + * test/glib/test-service-glib.xml: Add structure tests. + +2005-07-10 Colin Walters + + * doc/TODO: Knock off some GLib items with this patch. + + * glib/dbus-gvalue-utils.c (_dbus_gtype_can_signal_error) + (_dbus_gvalue_signals_error): New functions. + + * glib/dbus-gvalue-utils.h: Prototype them. + + * glib/dbus-gobject.c (arg_iterate): Update to handle return vals + and change to not output const/retval flags for input args. All + callers updated. + (invoke_object_method): Refactor to handle return values. Add + some more comments in various places. Remove debug g_print. + + * glib/dbus-binding-tool-glib.h (DBUS_GLIB_ANNOTATION_RETURNVAL): New. + + * glib/dbus-binding-tool-glib.c (dbus_g_type_get_marshal_name): + Handle G_TYPE_NONE. + (compute_gsignature): New function; refactored from code from + compute_marshaller and compute_marshaller_name. Enhance to + handle return values and async ops more cleanly. Update for + async ops returning NONE instead of BOOLEAN. + (compute_marshaller, compute_marshaller_name): Call compute_gsignature + and output appropriate string. + (generate_glue): Handle return value annotation. Also don't dump + constness flag for input arguments. + + * glib/Makefile.am (DBUS_GLIB_INTERNALS): New variable; contains + files shared between installed library and utilities. + (libdbus_glib_1_la_SOURCES): Move some stuf into DBUS_GLIB_INTERNALS. + (libdbus_gtool_la_SOURCES): Suck in DBUS_GLIB_INTERNALS so the + binding tool can access gtype utility functions. + + * test/glib/test-service-glib.c: + * test/glib/test-service-glib.xml: + * test/glib/test-dbus-glib.c: Add some tests for return values. + +2005-07-09 Colin Walters + + * glib/dbus-gparser.c (parse_annotation): Add annotations to + argument if available, not method. + + * glib/dbus-gobject.c (arg_iterate): More verbose warnings. + (invoke_object_method): First, remove some redundant + GValues (object_value, error_value) in favor of working on + array directly. Second, rework constness to be less buggy. + Now we iterate directly over the argument metadata instead + of parallel iterating over output signature and metadata. + + * glib/dbus-glib-tool.h: Add INVALID_ANNOTATION error. + + * glib/dbus-binding-tool-glib.c (generate_glue): Barf on const + annotation on input args. + +2005-07-09 Colin Walters + + * glib/dbus-binding-tool-glib.h (DBUS_GLIB_ANNOTATION_CONST): + Define. + + * glib/dbus-binding-tool-glib.c (generate_glue): Handle Const + annotation. + + * glib/dbus-gobject.c (arg_iterate): Update to parse constval too. + (method_dir_signature_from_object_info): Handle arg_iterate change. + (write_interface): Ditto. + (lookup_object_info): Don't barf if format_version is > 0. + (invoke_object_method): Handle arg constness. + + * glib/dbus-gidl.c (struct ArgInfo): Add annotations. + (arg_info_new): Create. + (arg_info_unref): Destroy. + (arg_info_get_annotations, arg_info_get_annotation) + (arg_info_add_annotation): New functions. + + * glib/dbus-gidl.h: Prototype them. + + * glib/dbus-gparser.c (parse_annotation): Allow annotations in + args, disallow them in properties. + (parse_annotation): Handle arg annotations. + + * test/glib/test-service-glib.xml: + * test/glib/test-service-glib.c: Update to make some methods + const. + +2005-07-08 Colin Walters + + * test/glib/test-service-glib.xml: + * test/glib/test-service-glib.c: + * test/glib/test-dbus-glib.c: Test a{sv}. + + * glib/examples/statemachine/statemachine.c: + * glib/examples/statemachine/statemachine-server.c: + * glib/examples/statemachine/statemachine-client.c: Fix some bugs, + add progress bar, etc. + + * glib/dbus-gvalue.c (register_array, register_dict): Delete; not + needed anymore due to generic array/map marshalling. + (dbus_g_value_types_init): Don't register basic arrays or the + string/string hash. + (dbus_gtype_from_signature_iter): Don't try to recurse into + variants. + (dbus_gtype_to_signature): Check collection/map before type + metadata. + (demarshal_garray_basic): Renamed to demarshal_collection_array. + (demarshal_ghashtable): Renamed to demarshal_map; fix to use new + generic map creation/append functions instead of hash table + specifically. + (get_type_demarshaller): Handle maps. + (demarshal_collection): Dispatch on collection type to either + demarshal_collection_ptrarray or demarshal_collection_array. + (get_type_marshaller): Handle maps. + (marshal_collection): Dispatch collection type to either + marshal_collection_ptrarray or marshal_collection_array. + (_dbus_gvalue_test): New test. + + * glib/dbus-gvalue-utils.c (unset_and_free_g_value): New function. + (hash_free_from_gtype): Use it to free GValues. + (hashtable_append): New function. + (ptrarray_append): Fix prototype. + (slist_append): Ditto. + (_dbus_gvalue_utils_test): Extend tests. + + * glib/dbus-gtype-specialized.c + (dbus_g_type_specialized_init_append): Renamed from + dbus_g_type_specialized_collection_init_append. Remove const from + value, since we steal it. + (dbus_g_type_specialized_map_append): New function. + + * glib/dbus-gtype-specialized.h: Update prototypes. + Add DBusGTypeSpecializedMapAppendFunc. + + * glib/dbus-gtest.c (dbus_glib_internal_do_not_use_run_tests): Run + _dbus_gvalue_test. + + * glib/dbus-gtest.h: Prototype it. + +2005-07-08 Ross Burton + + * dbus/dbus-glib.h: + Add DBysGAsyncData for the async bindings. + + * glib/dbus-binding-tool-glib.c: + Re-enable the async bindings. + + * test/glib/test-dbus-glib.c: + Add a test for the generated async bindings. + +2005-07-08 Colin Walters + + * doc/TODO: Update GLib todo bits, also add a post-1.0 TODO for a + connection concept. + +2005-07-08 Colin Walters + + * tools/Makefile.am: Kill of print-introspect in favor of using + dbus-send --print-reply=literal. + + * test/glib/test-service-glib.xml: + * test/glib/test-service-glib.c (my_object_get_objs): New test + for "ao". + + * test/glib/test-dbus-glib.c (echo_received_cb): Free echo data. + (main): Test GetObjs. + + * glib/examples/statemachine/Makefile.am: + * glib/examples/statemachine/sm-marshal.list: + * glib/examples/statemachine/statemachine-client.c: + * glib/examples/statemachine/statemachine-server.c: + * glib/examples/statemachine/statemachine-server.xml: + * glib/examples/statemachine/statemachine.c: + * glib/examples/statemachine/statemachine.h: + * glib/examples/statemachine/statemachine.xml: + + New example. + + * glib/examples/example-service.c (main): Move invocation + of dbus_g_object_type_install_info earlier, to emphasize it + should only be done once. + + * glib/examples/example-signal-emitter.c (main): Ditto. + + * glib/examples/Makefile.am (SUBDIRS): Include statemachine. + + * glib/dbus-gvalue.h (dbus_gtype_to_signature) + (dbus_gvalue_marshal): Update prototypes. + + * glib/dbus-gvalue.c: Update all marshalling functions to take + const GValue instead of GValue. + (signature_iter_to_g_type_array): Return a GPtrArray for nonfixed + types. + (dbus_gvalue_to_signature): Update for dbus_gtype_to_signature + change. + (dbus_gtype_to_signature): Handle generic collecitons and maps. + Return a newly-allocated string. + (demarshal_proxy, demarshal_object_path, demarshal_object) + (demarshal_strv, demarshal_ghashtable): Set error, don't assert if + we get the wrong types from message. + (get_type_demarshaller): New function, extracted from + dbus_gvalue_demarshal. + (demarshal_collection): New function, demarshals generic + collection. + (dbus_gvalue_demarshal): Just invoke result of + get_type_demarshaller. Throw error if we don't have one. + (marshal_garray_basic): Abort on OOM. + (get_type_marshaller): New function, extracted from + dbus_gvalue_marshal. + (collection_marshal_iterator, marshal_collection): New functions; + implements generic marshalling for an iteratable specialized + collection. + (dbus_gvalue_marshal): Just invoke result of get_type_marshaller. + + * glib/dbus-gvalue-utils.c (gvalue_from_ptrarray_value): Handle + G_TYPE_STRING. + (ptrarray_value_from_gvalue): Ditto. + (ptrarray_append, ptrarray_free): New functions. + (slist_constructor, slist_iterator, slist_copy_elt, slist_copy) + (slist_append, slist_end_append, slist_free): New functions. + (dbus_g_type_specialized_builtins_init): Add append fuctions + for GPtrArray and GSList. Register GSList. + (test_specialized_hash, _dbus_gvalue_utils_test): New functions. + + * glib/dbus-gtype-specialized.h (DBusGTypeSpecializedAppendContext): + New. + (dbus_g_type_specialized_collection_init_append) + (dbus_g_type_specialized_collection_append) + (dbus_g_type_specialized_collection_end_append): Prototype. + (DBusGTypeSpecializedCollectionVtable): Add append_func and + end_append_func. + + * glib/dbus-gtype-specialized.c (dbus_g_type_specialized_collection_init_append) + (dbus_g_type_specialized_collection_append) + (dbus_g_type_specialized_collection_end_append): New functions. + (dbus_g_type_map_value_iterate): Take const GValue. + (dbus_g_type_collection_value_iterate): Ditto. + + * glib/dbus-gtest.c (dbus_glib_internal_do_not_use_run_tests): Run + _dbus_gvalue_utils_test. + + * glib/dbus-gtest.h: Prototype it. + + * glib/dbus-gproxy.c (dbus_g_proxy_manager_filter): Avoid + using uninitialized owner_list. + (dbus_g_proxy_begin_call_internal): Move return_if_fail to + public API. + (dbus_g_proxy_end_call_internal): Update to use error set + from dbus_gvalue_demarshal instead of setting it here. + (dbus_g_proxy_begin_call): Move return_if_fail here. + + * glib/dbus-gobject.c (write_interface): Update for + dbus_gtype_to_signature returning new string. + + * configure.in: Add glib/examples/statemachine. + +2005-07-08 Joe Shaw + + * configure.in: Add a configure option, --with-console-auth-dir + + * dbus/dbus-sysdeps-util.c (_dbus_user_at_console): Use the + new setting. Patch from Kay Sievers. + +2005-07-06 Colin Walters + + * dbus/dbus-glib.h (DBusGPendingCall, DBusGPendingCallNotify) + (DBUS_TYPE_G_PENDING_CALL, dbus_g_pending_call_get_g_type) + (dbus_g_pending_call_ref, dbus_g_pending_call_unref): Delete. + (dbus_g_pending_call_set_notify, dbus_g_pending_call_cancel): + Delete in favor of dbus_g_proxy_begin_call and + dbus_g_proxy_cancel_call. + (DBusGProxyCall, DBusGProxyCallNotify): New. + (dbus_g_proxy_begin_call): Change prototype to take callback, user + data, and destroy function. This replaces + dbus_g_pending_call_set_notify. + (dbus_g_proxy_cancel_call): Prototype. + (DBusGAsyncData): Delete, shouldn't be needed anymore. + + * glib/dbus-gproxy.c (struct _DBusGProxy): Add call_id_counter and + pending_calls map. + (struct _DBusGProxyManager): Add bus_proxy member, which is an + internal proxy for calls to the bus. Remove + pending_nameowner_calls, now the internal proxy keeps track. + (dbus_g_proxy_manager_unref): Unref bus proxy, remove reference to + pending_nameowner_calls. + (got_name_owner_cb): Update prototype, and use + dbus_g_proxy_end_call. + (got_name_owner_cb): Remove reference to pending_nameowner_calls. + (dbus_g_proxy_manager_register): Delete directly libdbus code in + favor of using internal proxy. + (dbus_g_proxy_manager_unregister): Update to use + dbus_g_proxy_cancel_call for any pending GetNameOwner call. + (dbus_g_proxy_init): Initialize pending calls map. + (dbus_g_proxy_constructor): New. + (dbus_g_proxy_class_init): Add get/set property functions, + constructor, and add NAME, PATH, and INTERFACE properties. + (cancel_pending_call): New function. + (dbus_g_proxy_dispose): Iterate over any outstanding calls and + cancel them. + (dbus_g_proxy_set_property, dbus_g_proxy_get_property): New. + (GPendingNotifyClosure): New structure. + (d_pending_call_notify, d_pending_call_free): Moved here from + dbus-glib.c. + (DBUS_G_VALUE_ARRAY_COLLECT_ALL): Moved around to satisfy function + ordering. + (manager_begin_bus_call): New internal function for talking to + internal bus proxy. + (dbus_g_proxy_new): Construct object using GObjet properties. + (dbus_g_proxy_begin_call_internal): Update to take user data, etc. + Create closure of same, and insert call into map of pending calls. + (dbus_g_proxy_end_call_internal): Take call id instead of pending + call. Look up pending call in current set. Remove it when we've + completed. + (dbus_g_pending_call_end, dbus_g_proxy_end_call_internal): Delete. + (dbus_g_proxy_begin_call): Change API to take callback, user data, + and destroy function directly. + (dbus_g_proxy_end_call): Update to take DBusGProxyCall. + (dbus_g_proxy_call): Invoke with NULL callback. + (dbus_g_proxy_cancel_call): New function, replaces + dbus_g_pending_call_cancel. + + * glib/dbus-gparser.c (validate_signature): Fix call to + dbus_set_g_error. + + * glib/dbus-gobject.c (dbus_g_object_type_dbus_metadata_quark): + New quark for attaching metadata to GType. + (info_hash): Delete. + (lookup_object_info): Look up using quark. + (dbus_g_object_type_install_info): Check that a type is classed, + not that it's an object. Also just install type data using quark + instead of using global hash. + + * glib/dbus-glib.c (dbus_g_pending_call_ref) + (dbus_g_pending_call_unref, dbus_pending_call_get_g_type) + (GPendingNotifyClosure): Delete. + (d_pending_call_notify, d_pending_call_free): Move to dbus-gproxy.c. + (dbus_g_pending_call_set_notify, dbus_g_pending_call_cancel): Delete. + + * glib/dbus-binding-tool-glib.c (generate_client_glue): Disable async + client method generation until we can fix it... + + * tools/dbus-viewer.c (load_child_nodes): Use dbus_g_proxy_call. + (load_from_service_thread_func): Ditto. + + * tools/dbus-names-model.c (struct NamesModel): Hold + DBusGProxyCall. + (have_names_notify): Update prototype, use + dbus_g_proxy_cancel_call. + (names_model_reload): Update for new dbus_g_proxy_begin_call API. + + * tools/dbus-monitor.c (filter_func): Update for print_message + API change. + + * test/glib/test-dbus-glib.c: Add more tests for async + invocations. Update many begin_call/end_call pairs to just use + dbus_g_proxy_call. + + * tools/dbus-send.c (main): Add --print-reply=literal mode. This + allows us to dump print-introspect.c. + + * tools/dbus-print-message.h (print_message): Add literal argument + to print_message which is intended to allow printing arguments without + metadata like "string=". + + * tools/dbus-print-message.c (print_iter): Add literal argument. + (print_message): Allow printing string messages literally. + +2005-07-05 Colin Walters + + * glib/dbus-gproxy.c (marshal_dbus_message_to_g_marshaller): + Remove value refcount leak, original patch from Jorn Baayen + . Also remove useless extra value in favor + of prepending to value array directly. + +2005-07-02 Colin Walters + + * glib/dbus-gmain.c (_dbus_gmain_test): Fix test. + +2005-07-01 Colin Walters + + Patch from Jonathan Matthew + + * glib/dbus-gvalue.c (basic_typecode_to_gtype): Fix return type. + (dbus_g_value_types_init): Marshal G_TYPE_CHAR as DBUS_TYPE_BYTE, + G_TYPE_LONG as DBUS_TYPE_INT32, G_TYPE_ULONG as DBUS_TYPE_UINT32, + and G_TYPE_FLOAT as DBUS_TYPE_DOUBLE. + +2005-06-30 Colin Walters + + * test/glib/test-dbus-glib.c: + * test/glib/test-service-glib.c: + * test/glib/test-service-glib.xml: Update tests for new error + setting bits, also add async tests (patch from Ross Burton). + + * test/glib/Makefile.am (test_service_glib_LDADD): Add + DBUS_GLIB_THREADS_LIBS. + + * glib/dbus-gproxy.c (get_name_owner) + (dbus_g_pending_call_end_valist): Ditto. + + * glib/dbus-gobject.c (error_metadata): New mapping from GError + domain (GQuark) to DBusGErrorInfo. + (gerror_domaincode_to_dbus_error_name): Attempt to look up error + quark in error_metadata. Take message interface as default + error message interface. + (gerror_to_dbus_error_message): Pass message interface. + (dbus_set_g_error): Resurrected. + (dbus_g_error_info_free): New function. + (dbus_g_object_type_install_info): Use g_type_class_ref instead + of _peek to actually create the object class if it hasn't been + created yet. + (dbus_g_error_domain_register): New function. + + * glib/dbus-gmain.c (dbus_g_bus_get): Switch to dbus_set_g_error. + + * glib/dbus-gparser.c (validate_signature): Ditto. + + * dbus/dbus-glib.h (dbus_g_error_set): Delete. + (dbus_g_error_domain_register): Prototype. + + * glib/dbus-glib.c (dbus_g_error_set): Delete. + Update tests. + +2005-06-29 Colin Walters + + * dbus/dbus-glib.h: Delete DBUS_TYPE_G_PROXY_ARRAY. Add + DBUS_TYPE_G_OBJECT_PATH. + + * glib/dbus-gvalue.c (dbus_g_value_types_init): Remove marshallers + for G_TYPE_OBJECT and DBUS_TYPE_G_PROXY_ARRAY (the latter should + be handled more generically). Add DBUS_TYPE_G_OBJECT_PATH. + (dbus_g_object_path_get_g_type): New function. + (dbus_gtype_from_signature_iter): Map DBUS_TYPE_OBJECT_PATH + to DBUS_TYPE_G_OBJECT_PATH by default. + (demarshal_proxy): Remove unused name variable. + (demarshal_object_path, marshal_object_path): New functions. + (demarshal_proxy_array, marshal_proxy_array): Delete. + + * glib/dbus-binding-tool-glib.c (dbus_g_type_get_c_name): Map + DBUS_TYPE_G_OBJECT_PATH to char *. + (dbus_g_type_get_lookup_function): Map builtin + DBUS_TYPE_G_OBJECT_PATH. + + * test/glib/test-dbus-glib.c + * test/glib/test-service-glib.c (my_object_objpath): + Adapt tests to new object path marshalling. + +2005-06-29 John (J5) Palmieri + + * configure.in: force check for Python >= 2.4 + +2005-06-29 Colin Walters + + Patch from Ross Burton + + * glib/dbus-gobject.c (invoke_object_method): Unset object + value in all cases, not only in async case. + +2005-06-29 Colin Walters + + * glib/dbus-gproxy.c (struct _DBusGProxy): Add new member + name_call for keeping track of any outgoing GetNameOwner call. + Also add for_owner and associated. + (struct _DBusGProxyManager): Add owner_names, which is hash table + that maps a base name to a list of names it owns (that we're + interested in). Add pending_nameowner_calls which is a list of + all outstanding GetNameOwner; avoids us having to iterate over + every proxy. Add unassociated_proxies which keeps track of name + proxies with no associated name owner. + (dbus_g_proxy_manager_unref): Destroy owner_names. + (struct DBusGProxyNameOwnerInfo): New struct for keeping track of + name refcounts. + (find_name_in_info, name_owner_foreach) + (dbus_g_proxy_manager_lookup_name_owner, insert_nameinfo) + (dbus_g_proxy_manager_monitor_name_owner) + (dbus_g_proxy_manager_unmonitor_name_owner) + (unassociate_proxies, dbus_g_proxy_manager_replace_name_owner): + New functions; they manipulate the owner_names mapping. + (got_name_owner_cb): New function. + (get_name_owner): New function, extracted from + dbus_g_proxy_new_for_name_owner. + (dbus_g_proxy_manager_register): For now we need to keep track of + all NameOwnerChanged. Also if the proxy is for a name, if we + don't already know the name owner, queue a new GetNameOwner + request and add it to our list of unassociated proxies. Otherwise + inc the refcount. + (dbus_g_proxy_manager_unregister): If this proxy is for a name, + cancel any pending GetNameOwner call, etc. + (dbus_g_proxy_manager_filter): Handle NameOwnerChanged. Also use + the owner_names mapping to look up the current names for the + signal source, and dispatch to any proxies for that name. + (dbus_g_proxy_new): Initialize new members. + (dbus_g_proxy_new_for_name): Delete unused proxy variable. + (dbus_g_proxy_new_for_name_owner): Use get_name_owner. + (dbus_g_pending_call_end_valist): New function, extracted from + dbus_g_proxy_end_call_internal. Useful when we don't have a proxy + but want to use the GLib infrastructure. Also note how many + arguments in reply were over. + (dbus_g_pending_call_end): New function, just call + dbus_g_pending_call_end_valist. + (dbus_g_proxy_end_call_internal): Just call + dbus_g_pending_call_end_valist. + + * glib/dbus-gobject.c (_dbus_gobject_lookup_marshaller): Fix lookup + of builtin marshaller for STRING_STRING_STRING. + + * test/glib/test-dbus-glib.c: + * test/glib/test-service-glib.c: + * test/glib/test-service-glib.xml: + Extend tests to cover name proxies, destruction of owner proxies, + etc. + + * glib/examples/example-signal-recipient.c + (dbus_g_proxy_new_for_name_owner): Create a name proxy. + + * tools/dbus-send.c (main): Print D-BUS error name in addition + to message. + +2005-06-28 John (J5) Palmieri + + * python/dbus_bindings.pyx.in (cunregister_function_handler, + cmessage_function_handler): Patch from + Anthony Baxter fixes threading problems + by using the Py_GILState_Ensure/Release to synchronize with the + python runtime. + +2005-06-28 Ray Strode + + * dbus/dbus-spawn.c (_dbus_babysitter_unref): kill + babysitter helper process on last unref, bug #2813. + +2005-06-27 Colin Walters + + * test/glib/test-dbus-glib.c: + * test/glib/test-service-glib.c: + * test/glib/test-service-glib.xml: + Test hash table signal emitting. + + * glib/dbus-gobject.c (_dbus_gobject_lookup_marshaller): Convert + types to their fundamental basis types, since this is what + marshallers operate on. Also add an entry for VOID__BOXED. + (dbus_g_object_register_marshaller_array): Convert to fundamental. + +2005-06-26 Havoc Pennington + + * doc/dbus-tutorial.xml: fix names of interface/service/path, fix + from Don Park + +2005-06-26 Colin Walters + + * glib/dbus-glib.c (dbus_set_g_error): Delete. + (dbus_g_error_set): New public function from its ashes; used by + both service-side method implementation and GLib bindings + internals. + (dbus_g_error_has_name, dbus_g_error_get_name): New function. + (_dbus_glib_test): Add some tests. + + * test/glib/test-dbus-glib.c (main): Test dbus_g_error_has_name. + + * test/glib/test-service-glib.c (my_object_throw_error): Use + dbus_g_error_set. + + * glib/dbus-gobject.c (gerror_to_dbus_error_message): Handle + errors thrown by dbus_g_error_set. + + * glib/dbus-gmain.c (dbus_g_bus_get): Change to dbus_g_error_set. + + * glib/dbus-gparser.c (validate_signature): Ditto. + + * glib/dbus-gproxy.c (dbus_g_proxy_new_for_name_owner) + (dbus_g_proxy_end_call_internal): Ditto. + + * glib/Makefile.am: Generate dbus-glib-error-switch.h, which + converts DBUS_ERROR_x to DBUS_GERROR_x. + (libdbus_glib_1_la_SOURCES, BUILT_SOURCES, CLEANFILES): Add it. + + * doc/TODO: Remove error TODO. + + * doc/dbus-tutorial.xml: Update with documentation about error + handling. + + * dbus/make-dbus-glib-error-enum.sh: Tighten up regexp to make + sure we only change DBUS_ERROR to DBUS_GERROR, not all ERROR to + GERROR. Also add DBUS_GERROR_REMOTE_EXCEPTION. + +2005-06-22 Colin Walters + + Patch from Ross Burton + + * glib/dbus-gobject.c (dbus_g_method_return): Free out_sig. + +2005-06-20 Colin Walters + + * configure.in: Add glib/examples. + + * glib/Makefile.am: Add examples/ + + * glib/examples/.cvsignore + * glib/examples/Makefile.am + * glib/examples/example-client.c + * glib/examples/example-service.c + * glib/examples/example-service.xml + * glib/examples/example-signal-emitter.c + * glib/examples/example-signal-emitter.xml + * glib/examples/example-signal-recipient.c: + New files; GLib binding examples, ported from + python/examples. + +2005-06-20 Colin Walters + + * dbus/dbus-glib.h: + * glib/dbus-gproxy.c: Rename dbus_g_proxy_invoke to + dbus_g_proxy_call. + + * glib/dbus-binding-tool-glib.c: + * doc/dbus-tutorial.xml: + * test/glib/test-dbus-glib.c: Update for rename. + +2005-06-20 Colin Walters + + Patch suggested by Ross Burton + + * glib/dbus-gobject.c (export_signals): Free signal name. + (g_value_init): Use G_VALUE_NOCOPY_CONTENTS to plug + memory leak. Add a bit of documentation. + (dbus_g_method_return_error): Free context, and note we do + so. + +2005-06-18 Murray Cumming + + * dbus/dbus-glib.h: + * glib/dbus-gobject.c: + * glib/dbus-gproxy.c: + * glib/dbus-gvalue.c: Predeclare structs as + typedef struct _Something Something instead of + typedef struct Something Something, so we can + redeclare the prototypes. Other GNOME libraries + do this already. + +2005-06-17 Colin Walters + + * tools/dbus-names-model.c (have_names_notify): Fix call + to dbus_g_proxy_end_call. + +2005-06-17 Colin Walters + + * glib/dbus-gproxy.c (dbus_g_proxy_emit_remote_signal): Don't + spew warnings if we get malformed remote signals. + + * glib/dbus-gobject.c (propsig_iterate): New function. + (lookup_object_info): New function, extracted from + lookup_object_and_method. + (introspect_properties, introspect_signals): Delete; these + are merged into write_interface. + (write_interface): Write out signals and properties here; + dump the org.gtk.object stuff and use the interface given + in the introspection data blob. Also fix up property XML. + (lookup_values): New function. + (introspect_interfaces): Gather a mapping from interface to a + list of its methods, signals, and properties, then write out + each interface. + (lookup_object_and_method): Use lookup_object_info. + (struct DBusGSignalClosure): Add interface. + (dbus_g_signal_closure_new): Add interface. Don't dup signame; + we can just use the constant data. + (dbus_g_signal_closure_finalize): Don't free signal name. + (signal_emitter_marshaller): Use interface from signal closure. + (export_signals): Only export signals mentioned in introspection + blob. + (dbus_g_connection_register_g_object): Warn if we have no + introspection data for an object. + (funcsig_equal): Remove unused variable. + (dbus_g_object_register_marshaller): Take varargs instead of + list. + (dbus_g_object_register_marshaller_array): New function, + extracted from old dbus_g_object_register_marshaller. + + * glib/dbus-binding-tool-glib.c (struct DBusBindingToolCData): Add + signals and property data. + (write_quoted_string): New function, extracted from generate_glue. + (generate_glue): Write signals and properties to introspection + blob. + + * dbus/dbus-glib.h (struct DBusGObjectInfo): Include + exported_signals and exported_properties. + (dbus_g_object_register_marshaller): Update prototype. + (dbus_g_object_register_marshaller_array): Prototype. + + * test/glib/test-dbus-glib.c: Extend testing to cover new signals. + + * test/glib/test-service-glib.c: Add new test signals and method + to emit them. + + * test/glib/test-service-glib.xml: Add some test signals. + + * test/glib/Makefile.am (BUILT_SOURCES): Add my-object-marshal.c + and my-object-marshal.h + (test_service_glib_SOURCES, test_dbus_glib_SOURCES): Add + my-object-marshal.c. + (my-object-marshal.c, my-object-marshal.h): Implement. + + * test/glib/.cvsignore: Update. + + * doc/TODO: Remove two GLib TODO items fixed by this + patch. + +2005-06-16 Colin Walters + + * doc/TODO: Update for GLib bindings. + +2005-06-16 Colin Walters + + * glib/dbus-binding-tool-glib.c: + * glib/dbus-gobject.c: + * glib/dbus-gproxy.c: Add Nokia copyright; Patch + from Ross Burton, for his GLib bindings work. + +2005-06-16 Colin Walters + + * glib/dbus-gobject.c (funcsig_hash, funcsig_equal): Use n_params + to iterate instead of walking to G_TYPE_INVALID. + + Patch based on a patch from Ryan Gammon. + +2005-06-16 Colin Walters + + * bus/bus.c (bus_context_new): Set parser to NULL + after we unref it (Patch from Chris Boscolo, #2174). + +2005-06-16 Colin Walters + + * python/dbus_bindings.pyx.in: Import size_t, + __int64_t, __uint64_t, and __signed. + + * dbus/dbus-sysdeps.c (write_credentials_byte): + Define cmsg struct, output it. + (_dbus_read_credentials_unix_socket): + Use cmsg struct. + + Patch from Joe Markus Clarke for FreeBSD support. + +2005-06-16 Colin Walters + + * tools/dbus-send.c (append_array): Use strtok. + (append_dict): New function. + (type_from_name): New function, extracted from main. + (main): Handle sending dicts. + + * tools/dbus-print-message.c (print_iter): Print dict + entries. + +2005-06-16 Colin Walters + + * glib/dbus-gvalue.c (marshal_basic): Marshal NULL string + values as the empty string (#2948). + +2005-06-16 Colin Walters + + * dbus/Makefile.am: + * mono/doc/Makefile.am: + * test/glib/Makefile.am: + + Fix srcdir != builddir issues (Patch from Chris Wilson, #3477) + +2005-06-16 Colin Walters + + * dbus/dbus-marshal-header.c (_dbus_header_load): Set + header byte order from expected byte order (Patch from Chris Wilson, #3475). + + * dbus/dbus-marshal-byteswap.c (byteswap_body_helper): + Increment pointer after swapping fixed array. Add assertion + for array length. + +2005-06-15 Colin Walters + + * dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): + Fix call to dbus_set_error. (Patch from Michael Banck, #3461) + +2005-06-15 John (J5) Palmieri + + * NEWS: Update to 0.34 + +2005-06-15 David Zeuthen + + * configure.in (LT_CURRENT): Revert back to 1 as the library + hasn't changed and we've certainly not committed to protocol + stability yet. All this does is to break ABI. See commit note + from hp@redhat.com 2005-05-05 for details. + +2005-06-15 John (J5) Palmieri + + * dbus/dbus-connection.c (_dbus_connection_peer_filter): New method + (_dbus_connection_run_builtin_filters): New method + (dbus_connection_dispatch): Run the builtin filters which in turn + runs the peer filter which handles Ping messages. + + * doc/TODO: + - Ping isn't handled: This patch fixes it + + - Add a test case for the Ping message: added TODO item + +2005-06-15 John (J5) Palmieri + + * dbus/dbus-message.c: + (dbus_message_has_path): New method + (dbus_message_has_interface): New method + (dbus_message_has_member): New method + + * dbus/dbus/dbus-sysdeps.c (_dbus_check_dir_is_private_to_user): + New method + + * dbus/dbus-keyring.c (_dbus_keyring_reload): Check to see that + the keyring directory is private to the user + + * doc/TODO: + - The convenience functions in dbus-bus.h should perhaps have + the signatures that they would have if they were autogenerated + stubs. e.g. the acquire service function. We should also evaluate + which of these functions to include, in light of the fact that + GLib/Qt native stubs will probably also exist.: Punted + + - add dbus_message_has_path(), maybe has_member/interface: + fixed in this patch + + - in dbus-keyring.c, enforce that the keyring dir is not + world readable/writable: Fixed in this patch + +2005-06-15 John (J5) Palmieri + + * dbus/dbus-marshal-validate.h: Added a new validation + error code DBUS_VALIDITY_UNKNOWN_OOM_ERROR = -4 for + out of memory errors when validating signitures + + * dbus/dbus-marshal-header.c: use DBUS_VALIDITY_UNKNOWN_OOM_ERROR + in places where we previously used DBUS_VALID and a FALSE return + value to indicate OOM + + * dbus/dbus-marshal-validate.c (_dbus_validate_signature_with_reason): + Use a stack to track the number of elements inside containers. The + stack values are then used to validate that dict entries have only two + elements within them. + (validate_body_helper): check the reason for failure when validating + varients + + * dbus/dbus-message.c (load_message): use + DBUS_VALIDITY_UNKNOWN_OOM_ERROR in places where we previously used + DBUS_VALID and a FALSE return value to indicate OOM + + * doc/TODO: remove "- validate dict entry number of fields" as this + patch fixes it + +2005-06-14 David Zeuthen + + * bus/bus.c (process_config_every_time): Drop existing conf-dir + watches (if applicable) and add new watches + + * bus/main.c (signal_handler): Handle SIGIO if using D_NOTIFY + (main): Setup SIGIO signal handler if using D_NOTIFY + + * bus/config-parser.h: Add prototype bus_config_parser_get_conf_dirs + + * bus/config-parser.c (struct BusConfigParser): Add conf_dirs list + (merge_included): Also merge conf_dirs list + (bus_config_parser_unref): Clear conf_dirs list + (include_dir): Add directory to conf_dirs list + (bus_config_parser_get_conf_dirs): New function + + * bus/dir-watch.[ch]: New files + + * bus/Makefile.am (BUS_SOURCES): Add dir-watch.[ch] + + * configure.in: Add checks for D_NOTIFY on Linux + +2005-06-14 Colin Walters + + * glib/dbus-binding-tool-glib.c: + * glib/dbus-gobject.c: + * glib/dbus-gvalue.c: Fix indentation and brace style. + +2005-06-14 Ross Burton . + + * glib/dbus-glib.h: Make DBusGMethodInvocation + a private structure. Rearrange prototypes a bit. + + * glib/dbus-gproxy.c (dbus_g_proxy_invoke): Add + documentation for first_arg_type. + + * glib/dbus-gobject.c: Move DBusGMethodInvocation + here, add documentation. Move dbus_g_method_return + and dbus_g_method_return_error into public API + section. + +2005-06-14 Colin Walters + + * glib/dbus-gobject.c (_dbus_gobject_lookup_marshaller): + Add missing return statements, noticed by Ross Burton. + +2005-06-13 Ross Burton . + + * glib/dbus-gobject.c: Handle errors on message + demarshalling by sending error message back. + * glib/dbus-gvalue.c: Initialize return variables. + +2005-06-13 Colin Walters + + * glib/Makefile.am: Fix thinko in last patch. + +2005-06-13 Colin Walters + + * glib/Makefile.am: Move dbus-gtype-specialized.c + and dbus-gtype-specialized.h into a _HEADERS variable, + install them. + +2005-06-12 Colin Walters + + Async signals and various bugfixes and testing by + Ross Burton . + + * glib/dbus-gvalue.h: (struct DBusBasicGValue): Delete. + (dbus_gvalue_genmarshal_name_from_type) + (dbus_gvalue_ctype_from_type): Moved to dbus-binding-tool-glib.c. + (dbus_gtype_to_dbus_type): Renamed to dbus_gtype_from_signature. + (dbus_g_value_types_init, dbus_gtype_from_signature) + (dbus_gtype_from_signature_iter, dbus_gtype_to_signature) + (dbus_gtypes_from_arg_signature): New function prototypes. + (dbus_gvalue_demarshal): Take context and error arguments. + (dbus_gvalue_demarshal_variant): New function. + (dbus_gvalue_demarshal_message): New function. + (dbus_gvalue_store): Delete. + + * glib/dbus-gvalue.c: + + File has been almost entirely rewritten; now we special-case + more types such as DBUS_TYPE_SIGNATURE, handle arrays and + hash tables correctly, etc. Full support for recursive values + is not yet complete. + + * glib/dbus-gproxy.c (dbus_g_proxy_class_init): Change last + argument of signal to G_TYPE_POINTER since we now pass a + structure. + (lookup_g_marshaller): Delete in favor of + _dbus_gobject_lookup_marshaller. + (marshal_dbus_message_to_g_marshaller): Use + _dbus_gobject_lookup_marshaller and dbus_gvalue_demarshal_message + to handle remote signal callbacks. + (dbus_g_proxy_new_from_proxy): New function; creates a new + DBusGProxy by copying an existing one. + (dbus_g_proxy_get_interface, dbus_g_proxy_set_interface) + (dbus_g_proxy_get_path): New functions. + (dbus_g_proxy_marshal_args_to_message): New function; + factored out of existing code. + (DBUS_G_VALUE_ARRAY_COLLECT_ALL): Collect all arguments + from a varargs array. + (dbus_g_proxy_begin_call_internal): New function. + (dbus_g_proxy_end_call_internal): New function. + (dbus_g_proxy_begin_call): Take GTypes instead of DBus types + as arguments; simply invoke dbus_g_proxy_begin_call_internal + after collecting args into value array. + (dbus_g_proxy_end_call): Take GTypes instead of DBus types; + invoke dbus_g_proxy_end_call_internal. + (dbus_g_proxy_invoke): Simply invoke begin_call_interanl and + end_call_internal. + (dbus_g_proxy_call_no_reply): Take GTypes instead of DBus + types. + (array_free_all): New function. + (dbus_g_proxy_add_signal): Take GTypes. + + * glib/dbus-gobject.h: + (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. + (_dbus_gobject_get_path, _dbus_gobject_lookup_marshaller): + Prototype. + + * glib/dbus-gobject.c: Add a global marshal_table hash which + stores mappings from type signatures to marshallers. Change lots + of invocations of dbus_gtype_to_dbus_type to + dbus_gtype_to_signature. + (_dbus_glib_marshal_dbus_message_to_gvalue_array): Delete. + (introspect_signals): Fix test for query.return_type. + (set_object_property): Update invocation of dbus_gvalue_demarshal. + (invoke_object_method): Many changes. Handle asynchronous + invocations. Convert arguments with + dbus_gvalue_demarshal_message. Handle errors. Use + DBusSignatureIter instead of strlen on args. Handle all arguments + generically. Special-case variants. + (dbus_g_method_return, dbus_g_method_return_error): New function. + (DBusGSignalClosure): New structure, closes over signal + information. + (dbus_g_signal_closure_new): New function. + (dbus_g_signal_closure_finalize): New function. + (signal_emitter_marshaller): New function; is special marshaller + which emits signals on bus. + (export_signals): New function; introspects object signals and + connects to them. + (dbus_g_object_type_install_info): Take GType instead of + GObjectClass. + (dbus_g_connection_register_g_object): Invoke export_signals. + (dbus_g_connection_lookup_g_object): New function. + (DBusGFuncSignature) New structure; used for mapping type + signatures to marshallers. + (funcsig_hash): New function; hashes DBusGFuncSignature. + (funcsig_equal): New function; compares DBusGFuncSignature. + (_dbus_gobject_lookup_marshaller): New function. + (dbus_g_object_register_marshaller): New function; used to + register a marshaller at runtime for a particular signature. + + * glib/dbus-gmain.c (_dbus_gmain_test): Add various tests. + + * glib/dbus-binding-tool-glib.h: Add DBUS_GLIB_ANNOTATION_ASYNC + which notes a server method implementation should be + asynchronous. + + * glib/dbus-binding-tool-glib.c + (dbus_binding_tool_output_glib_server): Call + dbus_g_value_types_init. + (write_formal_parameters): Use dbus_gtype_from_signature. Handle + variants specially. + (dbus_g_type_get_lookup_function): Turn GType into an invocation + of a lookup function. + (write_args_for_direction): Use dbus_g_type_get_lookup_function. + (write_untyped_out_args): New method; write output arguments. + (write_formal_declarations_for_direction): Function for + writing prototypes. + (write_formal_parameters_for_direction): Function for + writing implementations. + (write_typed_args_for_direction): Function for writing + arguments prefixed with GTypes. + (write_async_method_client): Write out async version + of method. + + * glib/dbus-binding-tool-glib.c: Include dbus-gvalue-utils.h. + (dbus_g_type_get_marshal_name): Move mapping from GType + to marshal name into here. + (dbus_g_type_get_c_name): Move into here. + (compute_marshaller): Convert signature to type with + dbus_gtype_from_signature, use dbus_g_type_get_marshal_name. + (compute_marshaller_name): Ditto. + (compute_marshaller): Handle async signal annotations. + (gather_marshallers): Return if we don't have a known + prefix. + (generate_glue): Collect introspection blob here, and + write all of the blob at the end. This allows an object + with multiple interfaces to work. + Mark async methods in introspection blob. + + * glib/Makefile.am (libdbus_glib_1_la_SOURCES): Add + dbus-gtype-specialized.c, dbus-gtype-specialized.h, + dbus-gvalue-utils.h, dbus-gvalue-utils.c. + + * dbus/dbus-glib.h: Don't include dbus-protocol.h; this + avoids people accidentally using DBUS_TYPE_* which should + not be necessary anymore. + Do include dbus-gtype-specialized.h, which are utilities + for GLib container types. + Add various #defines for types such as + DBUS_TYPE_G_BOOLEAN_ARRAY. + (DBusGValueIterator, DBusGValue): Define, not fully used + yet. + (dbus_g_value_get_g_type): Type for recursive value. + (dbus_g_value_open, dbus_g_value_iterator_get_value) + (dbus_g_value_iterator_get_values, dbus_g_value_iterator_recurse) + (dbus_g_value_free): Prototypes. + (dbus_g_object_register_marshaller, dbus_g_proxy_new_from_proxy): Prototype. + (dbus_g_proxy_set_interface): Prototype. + (dbus_g_proxy_begin_call, dbus_g_proxy_end_call) + (dbus_g_proxy_call_no_reply): Take GLib types instead of DBus + types. + (dbus_g_proxy_get_path, dbus_g_proxy_get_interface): + Accessors. + (DBusGAsyncData, DBusGMethodInvocation): Structures for + doing async invocations. + (dbus_g_method_return, dbus_g_method_return_error): + Prototypes. + * doc/dbus-tutorial.xml: Update GLib section. + + * tools/dbus-viewer.c (load_child_nodes): Update + for new invocation type of dbus_g_proxy_end_call. + (load_from_service_thread_func): Ditto. + + * tools/print-introspect.c (main): Ditto. + + * tools/dbus-names-model.c (have_names_notify) + (names_model_reload, names_model_set_connection) + Use GTypes. + + * python/Makefile.am (INCLUDES): Define DBUS_COMPILATION, + needed since Python bindings use GLib bindings. + + * test/glib/Makefile.am (INCLUDES): Define DBUS_COMPILATION. + Add --prefix argument. + + * tools/Makefile.am: Define DBUS_COMPILATION. Remove + unneeded --ignore-unsupported arg. + + * test/glib/test-service-glib.c: + * test/glib/test-service-glib.xml: + * test/glib/test-dbus-glib.c: Add many more tests. + +2005-06-06 David Zeuthen + + * doc/TODO: Add item about need to remove deprecated functions. + + * dbus/dbus-connection.h: Add prototype for dbus_connection_disconnect + + * dbus/dbus-connection.c (dbus_connection_disconnect): New function + to repair the ABI which was broken with the last commit. + +2005-06-02 John (J5) Palmieri + + * dbus/dbus-connection.c, dbus/dbus-connection.h + (dbus_connection_disconnect): renamed to dbus_connection_close + for API symmetry with dbus_connection_open + (_dbus_connection_open_internal): + s/dbus_connection_disconnect/dbus_connection_close + + * dbus/dbus-bus.c (dbus_bus_get): + s/dbus_connection_disconnect/dbus_connection_close + + * bus/connection.c (bus_connections_unref, + bus_connections_setup_connection, bus_connections_expire_incomplete): + s/dbus_connection_disconnect/dbus_connection_close + + * bus/dispatch.c (bus_dispatch, kill_client_connection, + kill_client_connection_unchecked, check_hello_connection): + s/dbus_connection_disconnect/dbus_connection_close + + * bus/bus.c (new_connection_callback): + s/dbus_connection_disconnect/dbus_connection_close + + * tools/dbus-send.c (main): + s/dbus_connection_disconnect/dbus_connection_close + + * test/glib/test-profile.c (no_bus_thread_func, with_bus_thread_func): + s/dbus_connection_disconnect/dbus_connection_close + + * test/test-service.c (path_message_func, filter_func): + s/dbus_connection_disconnect/dbus_connection_close + + * doc/TODO: remove connection_open/connection_disconnect lacks symmetry item that was just fixed + +2005-05-25 Colin Walters + + * dbus/dbus-protocol.h: Move various bus service #defines such + as DBUS_SERVICE_DBUS and DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT to + dbus/dbus-shared.h. + * dbus/dbus-shared.h: Various defines moved here. + * dbus/dbus-marshal-header.c: Include dbus-shared.h. + +2005-05-25 John (J5) Palmieri + + * python/__init__.py: Python bindings deserve a minor version + update. Upped to (0, 40, 2) + +2005-05-24 John (J5) Palmieri + + * python/decorators.py: add explicitly_pass_message decorator + for passing in the dbus message as keyword for edge case signal + handling + + * python/matchrules.py (SignalMatchRule.__repr__): fix output + to conform with what dbus expects for match rules + (SignalMatchRule.execute): add the dbus message as a keyword + if the signal handler has requested it + + * python/examples/example/signal-recipient.py: added some more + examples on how to hook up to signals + +2005-05-23 John (J5) Palmieri + + * python/decorators.py: import dbus_bindings + + * python/matchrules.py (SignalMatchRule, SignalMatchTree, + SignalMatchNode): new classes that implement wildcard signal + callback matching using a tree lookup. Heavily modified from a + patch sent by Celso Pinto (fd.o bug #3241) + + * _dbus.py (add_signal_receiver, remove_signal_receiver, _signal_func): + use new match classes to handle signals. + +2005-05-19 John (J5) Palmieri + + * python/dbus_bindings.pyx.in: s/TYPE_PATH/TYPE_OBJECT_PATH + +2005-05-18 Havoc Pennington + + * configure.in: use GLIB_GNU_GETTEXT to get INTLLIBS and require + gettext. Not really worth requiring yet perhaps, but any + production quality 1.0 would require it so we should go ahead and + get things set up. We do have a couple token calls to + bindtextdomain in the code already. + +2005-05-16 John (J5) Palmieri + + * glib/dbus-gmain.c (io_handler_dispatch): fix deadlock + when using recursive g_main_loops + + * python/_dbus.py (class Bus): add the ProxyObjectClass + alias for ProxyObject to make it easier for the Twisted + networking framework to integrate dbus. + + * python/proxies.py (class ProxyObject): add the ProxyMethodClass + alias for ProxyMethod to make it easier for the Twisted + networking framework to integrate dbus. + +2005-05-11 Ross Burton + + * glib/dbus-glib-tool.c: Add --prefix argument. + * glib/dbus-binding-tool-glib.h: Add prefix argument. + * glib/dbus-binding-tool-glib.c (compute_marshaller_name): + Add prefix argument. + (generate_glue): Pass prefix argument down. + (dbus_binding_tool_output_glib_server): Pass prefix to + glib-genmarshal. + +2005-05-11 Colin Walters + + * tools/dbus-send.c (append_array): New function. + (append_arg): Broken out from main. + (main): Add cheesy hack to send arrays and variants. + (usage): Update. + * tools/dbus-print-message.c (print_iter): Broken out + from main. + +2005-05-11 Colin Walters + + * dbus/dbus-signature.c (dbus_signature_iter_get_signature): + New function, returns signature string for signature iter. + * dbus/dbus-signature.h: Prototype it. + * dbus/dbus-message.c (dbus_message_iter_get_signature): + New function, returns signature string for message iter. + (dbus_message_iter_get_array_len): New function, returns + length of array. + (dbus_message_iter_get_fixed_array): Fix assertion; this + function should be used when the iter is pointing to the + contents of an array + * dbus/dbus-message.h: Prototypes. + * dbus/dbus-marshal-recursive.c (_dbus_type_reader_get_array_length): + New function; returns length of an array. + * dbus/dbus-marshal-recursive.h: Prototype it. + +2005-05-11 Colin Walters + + * dbus/dbus-sysdeps-util.c : Fix + compilation error. + +2005-05-08 Havoc Pennington + + * dbus/dbus-sysdeps-util.c (_dbus_become_daemon): write the + daemon's pid, not the parent's pid, to the file descriptor. + Reported by Taj Morton. + +2005-05-05 Havoc Pennington + + * configure.in (LT_*): add notes on how the libtool versioning + works to save thinking. Increment soname to indicate protocol + breakage (though really the library interface hasn't changed I + guess) + + * dbus/dbus-transport.c (_dbus_transport_get_is_authenticated): + verify the GUID received from server matches what we were + expecting, if we had an expectation + + * dbus/dbus-auth.c (send_ok): send GUID along with the OK command + (_dbus_auth_get_guid_from_server): new function + (send_begin): parse the OK args + + * doc/dbus-specification.xml: add GUID to the auth protocol + +2005-05-05 John (J5) Palmieri + + * Fix my name in previous changelog ;) + + * python/proxies.py (ProxyObject.__getattr__): add further patch + from Anthony Baxter to throw an AttributeError when python + __special__ functions are called instead of marshling them over + the bus (Bug#1685 comment 3). + +2005-05-04 John (J5) Palmieri + + * python/Makefile.am: changed to use pyexecdir for the binding + shared libraries (Bug#2494) + + * python/exceptions.py: bring exceptions over from the bindings + so they can be used in applications (Bug#2036) + Make all exceptions derive from DBusException + + * python/_dbus.py, python/proxies.py: implement __repr__ in a couple + of classes so that print obj doesn't throw an exception (Bug #1685) + +2005-05-03 Ross Burton + + * glib/dbus-gobject.c (dbus_g_connection_register_g_object): + Return if we get an error during registration. Set up a + weak reference on object to unregister if object is destroyed. + (unregister_gobject): New function. + +2005-05-01 John (J5) Palmieri + + * python/dbus_bindings.pyx.in: + - added new type classes for hinting to the marashaler what type + to send over the wire + - added int16 and uint16 marshalers + - Fixed a bug in the type constants that caused int32 to go out + as uint16 over the wire + * python/dbus.py: split up into different files and renamed _dbus.py + * python/__init__.py, python/_util.py, python/decorators.py, + python/exceptions.py, python/proxies.py, python/services.py, + python/types.py: new files split off from dbus.py + * python/Makefile.am: Add new files, remove dbus.py and + install all python files to /dbus + * python/examples/*: Added #!/usr/bin/env python to the top of + every example. Patch provided by Tatavarty Kalyan + +2005-04-25 John (J5) Palmieri + + * NEWS: Update to 0.33 + +2005-04-25 John (J5) Palmieri + + * python/dbus_bindings.pyx.in (send_with_reply_handlers): New send + method for doing async calls + (_pending_call_notification): New C function for handling pendning call + callbacks + (set_notify): New method for setting pending call notification + + * python/dbus.py: new version tuple "version" is set at (0, 40, 0) + Async capabilities added to remote method calls + (Sender): class removed + (RemoteService): class removed + (ObjectTree): class removed for now + (RemoteObject): Renamed to ProxyObject + (RemoteMethod): Renamed to ProxyMethod + (method): Decorator added for decorating python methods as dbus methods + (signal): Decorator added for decorating python methods as signal emitters + (ObjectType): Metaclass added for generating introspection data and the + method callback vtable + (Interface): Wrapper class added to wrap objects in a dbus interface + (Object): Uses ObjectType as its metaclass and exports Introspect + of the org.freedesktop.DBus.Introspectable interface + (ValidationException, UnknownMethodException): new exceptions + + * python/examples/*: Modified to fit with the new bindings + +2005-04-23 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_append_args): fix doc comment, + reported by Tony Houghton + + * test/test-service.c (main): test + dbus_connection_get_object_path_data() + + * dbus/dbus-object-tree.c (find_handler): be sure we always init + the exact_match + (_dbus_object_tree_get_user_data_unlocked): new function used by + dbus_connection_get_object_path_data() + (do_register): add assertion test for get_user_data_unlocked + (object_tree_test_iteration): more tests + + * dbus/dbus-connection.c (dbus_connection_get_object_path_data): + new function from Dan Reed to let you get the user data from + dbus_connection_register_object_path() + +2005-04-23 John (J5) Palmieri + + * dbus/dbus-marshal-recursive-util.c: Fixed buffer overflow + in numerous places that did not account for the NULL terminator + (signature_from_seed): changed the manual string copy loop to + just use strcpy instead + make check should now pass + +2005-04-19 John (J5) Palmieri + + * dbus/dbus-marshal-header.c (_dbus_header_create): Fix assert + so that it allows messages that are not signals to pass in + NULL as the interface. + +2005-04-18 David Zeuthen + + * glib/dbus-gmain.c (io_handler_destroy_source): + (timeout_handler_destroy_source, connection_setup_free): + Also unref the source to avoid memory leaks. + +2005-04-13 David Zeuthen + + * bus/config-parser.c (bus_config_parser_new): Bump this to a + more reasonable, yet still totally arbitrary, value :-). + +2005-04-13 David Zeuthen + + * doc/TODO: Added an "important for 1.0" item about selinux + allow/deny messages + +2005-04-13 David Zeuthen + + * bus/selinux.c: Add c-file-style to top of file + (log_audit_callback): Don't free the data here anymore + (bus_selinux_check): Don't take spid and tpid since appending + that to auxdata may OOM. + (bus_selinux_allows_acquire_service): Handle OOM and signal back + to the caller if we are OOM by taking an error object. + (bus_selinux_allows_send): -do- + + * bus/selinux.h: Fix prototypes for bus_selinux_allows_acquire_service + and bus_selinux_allows_send + + * bus/bus.c (bus_context_check_security_policy): Pass error and + pass on OOM thrown by bus_selinux_allows_send() + + * bus/services.c (bus_registry_acquire_service): Pass error and + pass on OOM thrown by bus_selinux_allows_acquire_service() + +2005-04-13 Havoc Pennington + + * glib/dbus-gmain.c (message_queue_dispatch): only dispatch one + message at a time to avoid monopolizing the main loop, bug + #2953 from Benjamin Otte + +2005-04-09 Havoc Pennington + + * dbus/dbus-string.c (copy): change a memcpy to memmove due to + possible overlap, fix from Daniel Reed + (fixup_alignment): fix signedness warnings + (_dbus_string_append_unichar): ditto + +2005-04-09 Havoc Pennington + + * dbus/dbus-message-util.c (_dbus_message_test): fix signedness warning + + * glib/dbus-glib-tool.c (main): fix warning + + * glib/dbus-binding-tool-glib.c (generate_glue): fix warning + + * dbus/dbus-connection.c (dbus_connection_read_write_dispatch): + add a new function that can be used in simple applications that + don't have a main loop and are willing to block + +2005-04-05 David Zeuthen + + Fix https://bugs.freedesktop.org/show_bug.cgi?id=2889 + + * glib/dbus-gmain.c: + (io_handler_destroy_source): Remove from list of IO handlers + of the ConnectionSetup object + (timeout_handler_destroy_source): -do- for timeout handlers + (io_handler_source_finalized): Don't remove from list since + we now do that in io_handler_destroy_source(). Renamed from + io_handler_source_destroyed + (timeout_handler_source_destroyed): -do- for timeout handlers + (connection_setup_free): It is now safe to iterate over all + IO and timeout handlers as the _destroy_source removes them + from the list synchronously + +2005-03-30 Havoc Pennington + + * configure.in: change check to gtk 2.4 + + * tools/dbus-viewer.c (name_combo_changed_callback): remove + gtk_combo_box_get_active_text() usage to decrement GTK requirement + to 2.4 + +2005-03-29 John (J5) Palmieri + + * News: Update 0.32 + + * HACKING: Fixed realease instructions. configure.in should be updated to + the next release by the person who made the last release. + +2005-03-29 John (J5) Palmieri + + * python/lvalue_cast_post_process.py - removed. Patch has been + submitted to Pyrex maintainers that fixes gcc4.0 errors + + * python/Makefile.am: removed refrences to lvalue_cast_post_process.py + +2005-03-24 Daniel Reed + + * tools/Makefile.am: Make print-introspect and + dbus-bus-introspect.xml building conditional on HAVE_GLIB. + +2005-03-22 John (J5) Palmieri + + * tools/Makefile.am: Patch by Colin Walters that fixes distcheck + + * dbus/dbus-userdb.c, dbus/dbus-userdb-util.c: Add patch we have + had in Red Hat packages for a while but for some reason never + got merged upstream + (_dbus_is_a_number): New checks if a string + can be converted to a number and does the conversion if it can + (_dbus_user_database_lookup): Add check to see if the given username + is a udi. This allows udi's to be used instead of usernames in the + config file. + (_dbus_user_database_lookup_group): Add check to see if the given groupname + is a gdi. This allows gdi's to be used instead of groupnames in the + config file. + +2005-03-21 John (J5) Palmieri + + * python/lvalue_cast_post_process.py - added post processor to fix Pyrex + code so that it compiles with gcc4.0 + + * python/Makefile.am: Added lvalue_cast_post_process.py to EXTRA_DIST + run dbus_bindings.c through lvalue_cast_post_process.py and copy the + results back to dbus_binding.c + +2005-03-20 Colin Walters + + Patch suggested by Inguva Rajasekhar . + + * configure.in: Require GTK+ 2.6. + +2005-03-20 Colin Walters + + * Makefile.am (SUBDIRS, DIST_SUBDIRS): Build tools before test. + +2005-03-17 Tom Parker + + * dbus/dbus-userdb.c (_dbus_user_database_lookup): Don't + print DBUS_UID_UNSET; instead print passed username. Also + be sure to actually use gid looked up in cache. + + * dbus/dbus-userdb-util.c (_dbus_user_database_lookup_group): Ditto + for DBUS_GID_UNSET and groupname. + +2005-03-17 Colin Walters + + * bus/print-introspect.c: Move to tools/. + * bus/run-with-tmp-session-bus.sh: Ditto. + + * glib/Makefile.am (dbus-glib-bindings.h): Move + generation to tools/Makefile.am. + + * test/glib/run-test.sh: Update to handle move + of run-with-tmp-session-bus.sh. + + * test/glib/test-service-glib.c: Update to handle + move of dbus-glib-bindings.h. + + * tools/print-introspect.c: Moved here + from bus/, and ported to GLib bindings. + + * tools/run-with-tmp-session-bus.sh: Moved here + from bus/. + + * tools/Makefile.am: Generate dbus-glib-bindings.h + and dbus-bus-introspect.xml here. + + * tools/.cvsignore, glib/.cvsignore, bus/.cvsignore: + Update. + +2005-03-17 Colin Walters + + * bus/driver.c (write_args_for_direction): Use + _dbus_string_get_const_data to retrieve string; + _dbus_string_get_const_data_len doesn't actually return + a NULL-terminated substring. + + * test/glib/test-service-glib.c: Include dbus-glib-bindings.h. + (main): Change to use org_freedesktop_DBus_request_name + instead of using g_proxy_begin_call/end_call. + +2005-03-15 Joe Shaw + + * mono/ProxyBuilder.cs (BuildFinalizer): Fix some invalid IL when + generating the finalizer. Fixes from Ben Maurer. + +2005-03-12 Joe Shaw + + * mono/BusDriver.cs: Update method names: ListServices + becomes ListNames; GetOwner becomes GetNameOwner. + + * mono/ProxyBuilder.cs (BuildFinalizer): Need to load arg 0 + onto the eval stack when removing the delegate. + +2005-03-12 Joe Shaw + + * mono/dbus-sharp.dll.config.in: Don't hardcode 0 for + LT_CURRENT. Set it to the autoconf variable. + + * mono/ProxyBuilder.cs: Add a finalizer to the generated proxy + classes that disconnects the signal handler delegate from the + service object. Fixes a big leak of proxy objects on the + client side of things. Patch from Ben Maurer + + +2005-03-12 Colin Walters + + * bus/driver.c (write_args_for_direction): New function, + parses a type signature into arguments and outputs to + XML. + (bus_driver_handle_introspect): Use it instead of + hardcoding XML for certain signatures. + + * bus/Makefile.am (dbus-bus-introspect.xml): Add + dependency on dbus-daemon. + + * glib/dbus-glib-tool.c (main): Parse ignore_unsupported + argument, pass it to dbus_binding_tool_output_glib_client. + + * glib/dbus-binding-tool-glib.c + (generate_client_glue): Protect against multiple inclusion. + (dbus_binding_tool_output_glib_client): Add + G_BEGIN_DECLS/G_END_DECLS. + + * glib/dbus-binding-tool-glib.c (compute_client_method_name): + Change to just take iface prefix directly. + (write_formal_parameters): Clarify error message. + (check_supported_parameters): New function; checks to see type + signatures of method parameters are supported. + (generate_client_glue): Handle ignore_unsupported flag. + (dbus_binding_tool_output_glib_client): Handle ignore_unsupported + parameter. + + * glib/Makefile.am (dbus-glib-bindings.h): Pass + --ignore-unsupported by default until glib bindings + support arrays. + +2005-03-11 Colin Walters + + * glib/Makefile.am: Generate dbus-glib-bindings.h and + install it. + + * bus/print-introspect.c: New file; prints introspection + data for a given name and object path. + + * bus/run-with-tmp-session-bus.sh: New file, refactored + from test/glib/run-test.sh. Creates a temporary session + bus and runs another program. + + * test/glib/run-test.sh: Refactor to invoke + run-with-tmp-session-bus.sh. + + * bus/driver.c (bus_driver_handle_introspect): Fix to print new + introspection format. Also change to use DBUS_TYPE_x_AS_STRING + macros instead of hardcoding. + + * glib/.cvsignore, bus/.cvsignore, test/glib/.cvsignore: Update. + +2005-03-11 Joe Shaw + + * dbus/dbus-connection.c (dbus_connection_send_with_reply): Remove + this unref; it doesn't match up evenly in some codepaths. + (_dbus_connection_block_pending_call): Unref at every exitpoint; + this evenly matches with the ref near the top of this function. + +2005-03-09 Joe Shaw + + * dbus/dbus-object-tree.c + (_dbus_object_tree_unregister_and_unlock): If checks are enabled + and we try to unregister a path that's not registered, still go + through the process of unlocking and don't just return. + +2005-03-09 Colin Walters + + * glib/dbus-gproxy.c (dbus_g_proxy_invoke): New method; calls + to this are generated for client-side wrappers. Invokes a + D-BUS method and returns reply values. + + * glib/dbus-binding-tool-glib.c (write_args_sig_for_direction): New + function; writes signature string for argument direction. + (write_args_for_direction): Change to pass input values directly + instead of via address, and fix indentation. + (generate_client_glue): Change to invoke dbus_g_proxy_invoke. Also + make generated wrappers inlineable. + + * dbus/dbus-message.c (dbus_message_iter_get_fixed_array): Add + note about using dbus_type_is_fixed. + + * dbus/dbus-marshal-basic.c (_dbus_type_is_fixed): Moved to + dbus/dbus-signature.c as dbus_type_is_fixed. + + All callers updated. + + * dbus/dbus-signature.c (dbus_type_is_fixed): Moved here + from dbus/dbus-marshal-basic.c:_dbus_type_is_fixed. + + * dbus/dbus-signature.h: Prototype. + + * glib/dbus-binding-tool-glib.c (compute_marshaller_name): Fix + error printf code. + + * test/glib/test-dbus-glib.c (main): Be sure to clear error as + appropriate instead of just freeing it. + (main): Free returned strings using g_free. + + * test/glib/Makefile.am (test-service-glib-glue.h) + (test-service-glib-bindings.h): Add dependency on dbus-binding-tool. + + * glib/dbus-gvalue.c (MAP_BASIC): Refactored from MAP_BASIC_INIT; + simply maps a simple D-BUS type to GType. + (dbus_dbus_type_to_gtype): Function which maps D-BUS type to + GType. + (dbus_gvalue_init): Just invoke dbus_dbus_type_to_gtype and + initialize the value with it. + (dbus_gvalue_binding_type_from_type): Unused, delete. + (dbus_gvalue_demarshal): Switch to hardcoding demarshalling for + various types instead of unmarshalling to value data directly. + Remove can_convert boolean. + (dbus_gvalue_marshal): Remove duplicate initialization; switch to + returning directly instead of using can_convert boolean. + (dbus_gvalue_store): New function; not related to D-BUS per-se. + Stores a GValue in a pointer to a value of its corresponding C + type. + + * glib/dbus-gvalue.h: Remove dbus_gvalue_binding_type_from_type, + add dbus_gvalue_store. + +2005-03-08 Joe Shaw + + Fix a bunch of lifecycle and memory management problems + in the mono bindings. + + * mono/Arguments.cs (Arguments): Implement IDisposable + + * mono/Bus.cs (Bus): Don't allow public instantiation. This is + strictly a static class. + + * mono/Connection.cs: Move the DBusObjectPathVTable and associated + delegates into this file. + (Connection): Implement IDisposable. + (Dispose): Disconnect the connection and set the raw connection + pointer to IntPtr.Zero. + (~Connection): Call Dispose(). + (RegisterObjectPath): Added. Manages the registration of object + paths so we can cleanly disconnect them at dispose/finalize time. + (UnregisterObjectPath): Ditto. + (set_RawConnection): Unregister all of the object paths when + changing the underlying DBusConnection. Add them back onto the + new connection, if any. + + * mono/Handler.cs: Don't implement IDisposable; it doesn't use any + more unmanaged resources anymore, so it's not necessary. Move all + the DBusObjectPathVTable stuff out of here. + (Handler): Save references to our delegates so that they don't get + finalized. Call Connection.RegisterObjectPath() instead of + dbus_connection_register_object_path() directly. + (Message_Called): Dispose the message after we're finished with + it. + + * mono/Message.cs (Message): Implement IDisposable. + (Dispose): Dispose the Arguments, and set the RawMessage to + IntPtr.Zero. + (SendWithReplyAndBlock): We own the ref to the reply that comes + back from dbus_connection_send_with_reply_and_block() so add a + comment about that and unref it after we've constructed a managed + MethodReturn class around it. Fixes a big, big leak. + + * mono/ProxyBuilder.cs: Reflect into Message to get the Dispose + method. + (BuildSignalHandler): After we've sent the Signal message, dispose + of it. + (BuildMethod): Dispose of the method call and reply messages after + we've sent the message and extracted the data we want from the + reply. + + * mono/Service.cs (UnregisterObject): Don't call handler.Dispose() + anymore. + (Service_FilterCalled): Dispose of the message after we're + finished with it. + +2005-03-08 Joe Shaw + + * dbus/dbus-connection.c (dbus_connection_send_with_reply): + After we attach our pending call to the connection, unref + it. Fixes a leak. + + * mono/Connection.cs (set_RawConnection): Disconnect our + filter and match callbacks from the old connection and + reconnect them to the new connection, if any. + + * mono/DBusType/Array.cs: "Code" is a static member, so + don't use "this" to refer to it. Fix for stricter checking + in Mono 1.1.4. + + * mono/DBusType/ObjectPath.cs (Append): Don't leak the + object path that we pass into unmanaged code. + + * mono/DBusType/String.cs (Append): Don't leak the string + that we pass into unmanged code. + +2005-03-07 John (J5) Palmieri + * NEWS: Update for 0.31 + + * configure.in: Release 0.31 + add LT_CURRENT, LT_REVISION, LT_AGE for easy soname bumping + + * qt/Makefile.am: fixed build + + * dbus/Makefile.am: soname bump for libdbus + + * glib/Makefile.am: soname bump for libdbus-glib + +2005-03-05 Havoc Pennington + + * dbus/dbus-sysdeps.c: + (pseudorandom_generate_random_bytes_buffer): fix to have no return + value + (_dbus_generate_random_bytes_buffer): fix return value + + * dbus/dbus-sysdeps-util.c: s/GETPWNAME/GETPWNAM/ so configure + checks actually work, from Tom Parker + +2005-03-01 Colin Walters + + * test/glib/test-dbus-glib.c (lose, lose_gerror): Utility + functions copied from dbus-glib-tool.c. + (main): Convert lots of error code to use them. + Also add some testing for introspection bits. + +2005-03-01 Colin Walters + + * doc/TODO: Remove introspection signature TODO. + +2005-02-27 Colin Walters + + * glib/dbus-gidl.c (property_info_get_type, arg_info_get_type): + Change return value to const char * instead of int so we can do + full signatures. + (struct PropertyInfo, struct ArgInfo): Store char *. + (property_info_new, arg_info_new): Update parameters, strdup. + (property_info_unref, arg_info_unref): Free. + + * glib/dbus-gidl.h: Update prototypes. + + * glib/dbus-gparser.c (basic_type_from_string): Delete. + (validate_signature): New function, just validates signature and + sets GError. + (parse_property, parse_arg): Invoke validate_signature. Store + signature instead of just type code. + + * glib/dbus-gvalue.c (base_type_from_signature): New utility + function to return a primary type for a signature, dropping + information about types in container types. + (dbus_gvalue_genmarshal_name_from_type) + (dbus_gvalue_binding_type_from_type) + (dbus_gvalue_ctype_from_type): Update to take full signature + instead of type code. + (dbus_gtype_to_dbus_type): Moved here from glib/dbus-gobject.c. + + * glib/dbus-gvalue.h: Update prototypes for above. + + * glib/dbus-gobject.c (gtype_to_dbus_type): Moved to + glib/dbus-gvalue.c as dbus_gtype_to_dbus_type. + (introspect_properties, introspect_signals, write_interface): + Update to handle signatures, and remove usage of + _dbus_gutils_type_to_string. + (handle_introspect): Print out type codes instead of e.g. "string" + in hardcoded introspection XML; also use x_AS_STRING constants + instead of hardcoding in string. + + * glib/dbus-glib-tool.c (pretty_print): Handle signature change + to string. Remove usage of _dbus_gutils_type_to_string. + + * glib/dbus-gutils.c (_dbus_gutils_type_to_string): Delete. + + * glib/dbus-gutils.h (_dbus_gutils_type_to_string): Update for + deletion. + + * glib/dbus-binding-tool-glib.c (compute_marshaller) + (compute_marshaller_name, generate_glue): Handle signature change + to string. + (write_formal_parameters, write_args_for_direction): Ditto, and + remove FIXME. + + * tools/dbus-tree-view.c (type_to_string): Delete. + (info_set_func_text): Update to print full signatures. + + * test/glib/test-service-glib.xml: Change types to new + introspection format. + +2005-02-26 Havoc Pennington + + * doc/TODO: remove the "guid" item + + * test/glib/test-profile.c (no_bus_thread_func): use open_private + (with_bus_thread_func): use open_private + + * dbus/dbus-connection.c (dbus_connection_open_private): new + function that works like the old dbus_connection_open() + (dbus_connection_open): now returns an existing connection if + possible + + * dbus/dbus-server-unix.c (handle_new_client_fd_and_unlock): pass + through the GUID to the transport + + * dbus/dbus-server.c (_dbus_server_init_base): keep around the + GUID in hex-encoded form. + + * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new): + pass GUID argument in to the transport + + * dbus/dbus-transport-unix.c (_dbus_transport_new_for_fd): add + guid argument + + * dbus/dbus-transport.c (_dbus_transport_init_base): add guid argument + + * dbus/dbus-auth.c (_dbus_auth_server_new): add guid argument + +2005-02-25 Havoc Pennington + + * doc/dbus-specification.xml: document the GUID thing + + * dbus/dbus-server.c (_dbus_server_init_base): initialize a + globally unique ID for the server, and put a "guid=hexencoded" + field in the address + + * dbus/dbus-bus.c: fix missing #include of dbus-threads-internal.h + + * dbus/dbus-message.c: ditto + + * dbus/dbus-dataslot.c: ditto + + * dbus/dbus-list.c: ditto + + * dbus/dbus-internals.h: wait, just include + dbus-threads-internal.h here + + * dbus/dbus-string.c (_dbus_string_copy_to_buffer): move back for + use in main library + + * dbus/dbus-sysdeps.c (_dbus_generate_random_bytes_buffer): new function + +2005-02-24 Colin Walters + + * test/glib/Makefile.am (EXTRA_DIST): Add test-service-glib.xml + +2005-02-24 John (J5) Palmieir + + * glib/Makefile.am: added dbus-gobject.h to sources list + so distcheck doesn't fail + +2005-02-24 Havoc Pennington + + * dbus/dbus-server.c, dbus/dbus-server-unix.c: change semantics so + you must disconnect before unref, since locking and other things + are screwed up otherwise. Fix assorted other locking stuff. + + * dbus/dbus-signature.c (dbus_signature_iter_get_element_type): + fix compilation + + * dbus/dbus-threads-internal.h: move the mutex/condvar wrappers + into a private header and don't export from the library + + * throughout - call _dbus_thread_stuff vs. dbus_thread_stuff + +2005-02-24 Colin Walters + + * dbus/dbus-signature.c: New file; implements various functions + related to type signatures. Includes an interator for parsing, + validation functions. + (dbus_type_is_basic): Moved here from + dbus-marshal-basic.c:_dbus_type_is_basic. + (dbus_type_is_container): Moved here from + dbus-marshal-basic.c:_dbus_type_is_container. + + All callers of _dbus_type_is_container and _dbus_type_is_basic + updated, and include dbus-signature.h. + + * dbus/dbus-signature.h: New file; prototypes for the above. + + * dbus/Makefile.am (DBUS_LIB_SOURCES): Add dbus-signature.c, + dbus-signature.h. + + * dbus/dbus-marshal-basic.c (map_type_char_to_type): New utility + function factored out of _dbus_first_type_in_signature. + (_dbus_first_type_in_signature_c_str): New function; returns first + type code for a type signature character. + + * dbus/dbus-marshal-basic.h: Prototype _dbus_first_type_in_signature_c_str, + handle function moves. + + * dbus/dbus-marshal-recursive.h: Export _dbus_type_signature_next. + + * dbus/dbus-marshal-recursive.c (_dbus_type_signature_next): New + function; skips to next complete type in type signature. + Implemented using previous skip_one_complete_type. Now + skip_one_complete_type just delegates to + _dbus_type_signature_next. + + * dbus/dbus-marshal-basic.c (_dbus_type_is_basic): Moved + to dbus-signature.c + (_dbus_type_is_container): Ditto. + + * doc/dbus-specification.xml: Update introspection sample to + use real type signatures. + + * dbus/dbus-test.h: Prototype signature test. + + * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): Run + signature tests. + + * dbus/dbus-protocol.h (DBUS_ERROR_INVALID_SIGNATURE): New error. + +2005-02-23 John (J5) Palmieri + + * python/dbus_bindings.pyx.in (PendingCall::get_reply): + s/dbus_pending_call_get_reply/dbus_pending_call_steal_reply + +2005-02-21 Colin Walters + + * dbus/dbus-test-main.c (main): Take optional specific test + argument. + + * dbus/dbus-test.c (run_test): New function, runs a test function + with no data directory. + (run_data_test): Like above, but takes data directory. + (dbus_internal_do_not_use_run_tests): Take + specific test argument. Replace lots of cut n' paste code + with run_test and run_data_test. + + * dbus/dbus-test.h: Update prototype for + dbus_internal_do_not_use_run_tests. + +2005-02-20 Havoc Pennington + + Fix bugs reported by Daniel P. Berrange + + * dbus/dbus-server.c (_dbus_server_unref_unlocked): new function + (protected_change_watch): new function + (_dbus_server_toggle_watch, _dbus_server_remove_watch) + (_dbus_server_add_watch): change to work like the + dbus-connection.c equivalents; like those, probably kind of + busted, but should at least mostly work for now + (dbus_server_disconnect): drop the lock if we were already + disconnected, patch from Daniel P. Berrange + + * dbus/dbus-server.c (_dbus_server_toggle_timeout) + (_dbus_server_remove_timeout, _dbus_server_add_timeout): all the + same stuff + + * doc/TODO: todo about unscrewing this mess + +2005-02-19 Colin Walters + + * glib/dbus-binding-tool-glib.c + (dbus_binding_tool_output_glib_server): Fix iochannel refcounting. + + * glib/dbus-glib-tool.c: Include dbus-glib-tool.h, as well + as errno.h and sys/stat.h. + (lose): New function, prints error with + newline and exits. + (lose_gerror): Similar, but takes GError for message. + (main): Add --output argument to specify output file to write to, + instead of always printing to stdout. In this mode, determine + timestamps on source files to see whether any are newer than the + target file. If not, exit. Also convert a number of error + messages to use lose (since it's shorter), and switch to using + g_io_channel_shutdown. + +2005-02-19 Havoc Pennington + + * glib/dbus-gobject.c + (_dbus_glib_marshal_dbus_message_to_gvalue_array): add docs + + * glib/dbus-glib.c: fix doxygen warnings + + * glib/dbus-gparser.c (parse_annotation): error if an annotation + is found on an + +2005-02-17 Colin Walters + + * glib/dbus-gobject.h: Don't export + _dbus_glib_marshal_dbus_message_to_gvalue_array. + + * glib/dbus-gobject.c (_dbus_glib_marshal_dbus_message_to_gvalue_array): Do rename. + (invoke_object_method): Handle it. + + * glib/dbus-gproxy.c (marshal_dbus_message_to_g_marshaller): + Handle rename. + +2005-02-17 Colin Walters + + * bus/.cvsignore, doc/.cvsignore + * test/data/valid-service-files/.cvsignore, test/glib/.cvsignore: + Update. + +2005-02-17 Colin Walters + + * dbus/dbus-protocol.h (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS): + Rename to DBUS_SERVICE_DBUS. + (DBUS_PATH_ORG_FREEDESKTOP_DBUS): Rename to DBUS_PATH_DBUS. + (DBUS_PATH_ORG_FREEDESKTOP_LOCAL): Rename to DBUS_PATH_LOCAL. + Change the value from "org.freedesktop.Local" + to "org.freedesktop.DBus.Local". + (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS): Rename to DBUS_INTERFACE_DBUS. + (DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE): Rename to + DBUS_INTERFACE_INTROSPECTABLE. + Change the value from "org.freedesktop.Introspectable" + to "org.freedesktop.DBus.Introspectable". + (DBUS_INTERFACE_ORG_FREEDESKTOP_PROPERTIES): Rename to + DBUS_INTERFACE_PROPERTIES. + Change the value from "org.freedesktop.Properties" + to "org.freedesktop.DBus.Properties". + (DBUS_INTERFACE_ORG_FREEDESKTOP_PEER): Rename to + DBUS_INTERFACE_PEER. + Change the value from "org.freedesktop.Peer" + to "org.freedesktop.DBus.Peer". + (DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL): + DBUS_INTERFACE_LOCAL. + Change the value from "org.freedesktop.Local" + to "org.freedesktop.DBus.Local". + + All other users of those constants have been changed. + + * bus/driver.c (bus_driver_handle_introspect): Use constants. + + * glib/dbus-gobject.c (handle_introspect): Use constants. + + * doc/dbus-faq.xml, doc/dbus-specification.xml: Update for rename. + +2005-02-17 Colin Walters + + * glib/dbus-gparser.c (struct Parser): Add in_annotation boolean. + (parse_node, parse_interface, parse_method, parse_signal) + (parse_property, parse_annotation): Lose if we're currently in an + annotation. + (parse_annotation): New function. + (parser_start_element, parser_end_element): Handle annotation. + (parse_method, parse_interface): Remove support for c_name attribute, + switch to annotations. + + * glib/dbus-gidl.h (interface_info_get_binding_names) + (method_info_get_binding_names) + (interface_info_get_binding_name, method_info_get_binding_name) + (interface_info_set_binding_name, method_info_set_binding_name): + Remove. + (interface_info_get_annotations, method_info_get_annotations) + (interface_info_get_annotation, method_info_get_annotation) + (interface_info_add_annotation, method_info_add_annotation): + Prototype. + + * glib/dbus-gidl.c (struct InterfaceInfo): Substitute "annotations" + for "bindings". + (struct MethodInfo): Ditto. + Straightfoward conversion of binding methods into annotation methods + as prototyped. + + * glib/dbus-glib-tool.c (pretty_print): Print annotations. + + * glib/dbus-binding-tool-glib.h (DBUS_GLIB_ANNOTATION_C_SYMBOL): Define. + + * glib/dbus-binding-tool-glib.c (gather_marshallers, generate_glue): + Use new annotation API. + + * doc/introspect.dtd: Fix a number of DTD syntax errors. Add + annotation element. + + * doc/dbus-specification.xml: Discuss introspection annotations, + include list of well-known annotations. + + * test/glib/test-service-glib.xml: Make validate against new DTD. + +2005-02-17 Colin Walters + + This patch is based on initial work from + Paul Kuliniewicz . + + * glib/dbus-gvalue.c (dbus_gvalue_init): New function; move + initialization of GValue from dbus type to here. + (dbus_gvalue_genmarshal_name_from_type): New function; generates a string + for the "glib-genmarshal" program from a DBus type. + (dbus_gvalue_binding_type_from_type): New function; turns a DBus type + into the C name for it we use in the glib bindings. + (dbus_gvalue_ctype_from_type): New function; maps a DBus type into a + glib C type (not GValue). + (dbus_gvalue_demarshal): invoke dbus_gvalue_init. + + * glib/dbus-gutils.c (_dbus_gutils_wincaps_to_uscore): Moved here + from dbus-gobject.c. + + * glib/dbus-gutils.h: Prototype it. + + * glib/dbus-gproxy.c: Include new dbus-gobject.h. + (marshal_dbus_message_to_g_marshaller): Use new shared function + dbus_glib_marshal_dbus_message_to_gvalue_array. + + * glib/dbus-gparser.c (parse_interface, parse_method): Handle c_name attribute. + Will be changed once we have annotations. + + * glib/dbus-gobject.c: Change info_hash_mutex from GStaticMutex to + GStaticRWLock. Callers updated. + (wincaps_to_uscore): Move to dbus-gutils.c. Callers updated. + (string_table_next): New function for iterating over zero-terminated + string value array. + (string_table_lookup): New function; retrieves specific entry in + array. + (get_method_data): New function; look up method data in object data chunk. + (object_error_domain_prefix_from_object_info) + (object_error_code_from_object_info): New functions, but not implemented yet. + (method_interface_from_object_info): New function; retrieve interface name. + (method_name_from_object_info): New function; retrieve method name. + (method_arg_info_from_object_info): New function; retrieve argument data. + (arg_iterate): New function; iterates over serialized argument data. + (method_dir_signature_from_object_info): New function; returns a + GString holding type signature for arguments for just one + direction (input or output). + (method_input_signature_from_object_info) + (method_output_signature_from_object_info): New functions. + (dbus_glib_marshal_dbus_message_to_gvalue_array): New shared function; + converts dbus message arguments into a GValue array. Used for both + signal handling and method invocation. + (struct DBusGlibWriteIterfaceData): New utility structure. + (write_interface): New function; generate introspection XML for + an interface. + (introspect_interfaces): New function; gathers all interface->methods, + generates introspection XML for them. + (handle_introspect): Invoke introspect_interfaces. + (get_object_property): Be sure to zero-initalize stack-allocated GValue. + (lookup_object_and_method): New function; examines an incoming message + and attempts to match it up (via interface, method name, and argument + signature) with a known object and method. + (gerror_domaincode_to_dbus_error_name): New function; converts a + GError domain and code into a DBus error name. Needs GError data + added to object introspection to work well. + (gerror_to_dbus_error_message): Creates a DBusMessage error return from + GError. + (invoke_object_method): New function to invoke an object method + looked up via lookup_object_and_method. Parses the incoming + message, turns it into a GValue array, then invokes the marshaller + specified in the DBusGMethodInfo. Creates a new message with + either return values or error message as appropriate. + (gobject_message_function): Invoke lookup_object_and_method and + invoke_object_method. + + * glib/dbus-glib-tool.c: Include dbus-binding-tool-glib.h. + (enum DBusBindingOutputMode): New enum for binding output modes. + (pretty_print): Print binding names. + (dbus_binding_tool_error_quark): GError bits. + (version): Fix typo. + (main): Create GIOChannel for output. Parse new --mode argument, + possible values are "pretty-print", "glib-server", "glib-client". + Use mode to invoke appropriate function. + + * glib/dbus-gobject.h: Prototype dbus_glib_marshal_dbus_message_to_gvalue_array. + + * glib/dbus-glib-tool.h: New header, just includes GError bits + for now. + + * glib/dbus-gidl.c (struct InterfaceInfo): Add bindings hashtable; + maps binding style to name. + (struct MethodInfo): Ditto. + (get_hash_keys, get_hash_key): Utility function, returns keys for + a GHashTable. + (interface_info_new, method_info_new): Initialize bindings. + (interface_info_unref, method_info_unref): Destroy bindings. + (method_info_get_binding_names, method_info_get_binding_name) + (interface_info_get_binding_names, interface_info_get_binding_name): + Functions for retrieving binding names. + (method_info_set_binding_name, interface_info_set_binding_name): + Functions for setting binding names. + + * glib/dbus-binding-tool-glib.h: New file, has prototypes + for glib binding generation. + + * glib/dbus-binding-tool-glib.c: New file, implements server-side + and client-side glib glue generation. + + * glib/Makefile.am (dbus_binding_tool_SOURCES): Add + dbus-binding-tool-glib.c, dbus-binding-tool-glib.h, + dbus-glib-tool.h. + + * dbus/dbus-glib.h (struct DBusGMethodMarshaller): Remove in favor + of using GClosureMarshal directly. + (struct DBusGObjectInfo): Add n_infos member. + + * test/glib/test-service-glib.xml: New file; contains introspection data + for MyTestObject used in test-service-glib.c. + + * test/glib/test-service-glib.c (enum MyObjectError): New GError enum. + (my_object_do_nothing, my_object_increment, my_object_throw_error) + (my_object_uppercase, my_object_many_args): New test methods. + (main): Use dbus_g_object_class_install_info to include generated object + info. + + * test/glib/Makefile.am: Generate server-side glue for test-service-glib.c, + as well as client-side bindings. + + * test/glib/test-dbus-glib.c: Include test-service-glib-bindings.h. + (main): Activate TestSuiteGLibService; test invoke a bunch of its methods + using both the dbus_gproxy stuff directly as well as the generated bindings. + +2005-02-15 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_dispatch): always + complete a pending call, don't run filters first. + + * glib/dbus-gproxy.c (dbus_g_proxy_end_call): change to use + dbus_pending_call_steal_reply + + * dbus/dbus-pending-call.c (dbus_pending_call_block): just call + _dbus_connection_block_pending_call + (dbus_pending_call_get_reply): change to steal_reply and return a + ref + + * dbus/dbus-connection.c + (dbus_connection_send_with_reply_and_block): port to work in terms + of DBusPendingCall + (_dbus_connection_block_pending_call): replace block_for_reply + with this + +2005-02-14 Havoc Pennington + + * dbus/dbus-userdb-util.c (_dbus_user_database_lookup_group): + properly handle looking up group information by name; fix + from j@bootlab.org + +2005-02-13 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_return_message) + (dbus_connection_borrow_message): hold dispatch lock while message + is outstanding + (_dbus_connection_block_for_reply): hold dispatch lock while we + block for the reply, so nobody steals our reply + (dbus_connection_pop_message): hold the dispatch lock while we + pluck the message + +2005-02-13 Havoc Pennington + + * dbus/dbus-connection.c (_dbus_connection_acquire_dispatch) + (_dbus_connection_release_dispatch) + (_dbus_connection_acquire_io_path) + (_dbus_connection_release_io_path): make the mutex and condvar + control access to the "acquired" flag. Drop the connection lock + while waiting on the condvar. Hopefully these are baby steps in + roughly the right direction. + +2005-02-13 Havoc Pennington + + * dbus/dbus-connection.c: use separate mutexes for the condition + variables; this is some kind of baseline for sanity, but the + condition variables still aren't used correctly afaict + +2005-02-13 Havoc Pennington + + * dbus/dbus-object-tree.c (handle_default_introspect_and_unlock): + fix a double-unlock + + * dbus/dbus-connection.c + (_dbus_connection_detach_pending_call_unlocked): add this + + Initial semi-correct pass through to fix thread locking; there are + still some issues with the condition variable paths I'm pretty + sure + + * dbus/dbus-server.c: add a mutex on DBusServer and appropriate + lock/unlock calls + + * dbus/dbus-connection.c (_dbus_connection_do_iteration_unlocked): + rename to add _unlocked + (struct DBusConnection): move "dispatch_acquired" and + "io_path_acquired" to use only one bit each. + (CONNECTION_LOCK, CONNECTION_UNLOCK): add checks with !DBUS_DISABLE_CHECKS + (dbus_connection_set_watch_functions): hacky fix to reentrancy + (_dbus_connection_add_watch, _dbus_connection_remove_watch) + (_dbus_connection_toggle_watch, _dbus_connection_add_timeout) + (_dbus_connection_remove_timeout) + (_dbus_connection_toggle_timeout): drop lock when calling out to + user functions; done in a hacky/bad way. + (_dbus_connection_send_and_unlock): add a missing unlock + (_dbus_connection_block_for_reply): add a missing unlock + + * dbus/dbus-transport.c (_dbus_transport_get_is_authenticated): + drop lock in a hacky probably unsafe way to call out to user + function + +2005-02-12 Havoc Pennington + + * tools/dbus-tree-view.c (info_set_func_text): display more + details on args + + * bus/driver.c (bus_driver_handle_list_services): list the bus + driver + + * glib/dbus-gparser.c (parse_arg): generate an arg name if none is supplied + + * glib/dbus-gidl.c (signal_info_get_n_args): new function + (method_info_get_n_args): new function + +2005-02-12 Havoc Pennington + + * bus/driver.c (bus_driver_handle_introspect): add introspection + for bus driver + +2005-02-12 Havoc Pennington + + * bus/driver.c: put the signature of each bus driver method in the + table of handlers and check it on incoming calls; this isn't + really useful, but going to add introspect support in a minute. + +2005-02-11 Joe Shaw + + * mono/Connection.cs: The unpredictability of finalizers in mono + prevents us from deterministically disconnecting the filters from + the Service class's finalizer, so move tracking of filters and + matches here. Add API for that. + + * mono/Service.cs: Remove the code, add code which calls the + methods now on the Connection class. + +2005-02-11 John (J5) Palmieri + + * python/dbus.py (class Sender): added to support dbus signals better + (Bus::add_signal_receiver): added expand_args parameter which defaults + to True. When expand args is True the signal handler will pass the + message arguments as parameters to the signal handler. If False + revert to previous behavior where the signal handler must get the + argument list from the message. This is to help port applications + like HAL that have a tendancy to send variable length argument lists. + self._match_rule_to_receivers is now a dict of dicts. + (Bus::remove_signal_receiver): pop handler off the dict intead of + removing it from a list + (Bus::_signal_func): change signal handlers so that interface, + signal_name, service, path and message are packed into a Sender + object and that is passed to the handler. If expand_args is True + extract the args list from the message and append it to the parameter + list + + * python/dbus_bindings.pyx.in (class Signature): added to support + signiature types + (MessageIter::__init__): changed iteration limit to match D-BUS + (MessageIter::get*): added INT16, UINT16, SIGNATURE, DICT_ENTRY, + STRUCT and VARIENT type support + (MessageIter::python_value_to_dbus_sig): made recursive to support + recursive types + (MessageIter::append*): added Signature, dict, tuple + support + + * python/examples/example-client.py: added examples of getting tuples + and dicts + + * python/examples/example-service.py: added examples of sending tuples + and dicts + + * python/examples/example-signal-recipient.py: Fixed to handle new + signal callback format + +2005-02-10 Havoc Pennington + + * test/glib/test-dbus-glib.c (main): fix so this test doesn't fail + (call dbus_g_proxy_add_signal) + + * dbus/dbus-server-unix.c (_dbus_server_new_for_tcp_socket): + escape the hostname + (_dbus_server_new_for_domain_socket): escape the path + + * dbus/dbus-address.c (dbus_address_escape_value): new + (dbus_address_unescape_value): new + (dbus_parse_address): unescape values + + * dbus/dbus-string.c (_dbus_string_append_byte_as_hex): new function + + * doc/dbus-specification.xml: explain how to escape values in + addresses + +2005-02-10 Havoc Pennington + + * dbus/dbus-message-factory.c (generate_special): modify test to + avoid using a non-basic dict key + + * dbus/dbus-marshal-validate-util.c: add test for the below + + * doc/dbus-specification.xml: require that dict keys are a basic + type + + * dbus/dbus-marshal-validate.c + (_dbus_validate_signature_with_reason): require that dict key is a + basic type + +2005-02-10 Havoc Pennington + + * dbus/dbus-object-tree.c (handle_default_introspect_and_unlock): + change to be _and_unlock instead of _unlocked + + * dbus/dbus-connection.c + (_dbus_connection_send_preallocated_unlocked_no_update): rename to + have no_update so we can find this bug quickly in future + +2005-02-10 Havoc Pennington + + * dbus/dbus-message-util.c (verify_test_message): tests for string + array + + * dbus/dbus-message.c (dbus_message_append_args_valist): add + support for arrays of string/signature/path + +2005-02-10 Joe Shaw + + * dbus/dbus-connection.c + (_dbus_connection_queue_received_message_link, + _dbus_connection_message_sent): Add the path to + the verbose output. + (_dbus_connection_send_preallocated_and_unlock): Added. Calls + _dbus_connection_send_preallocated_unlocked(), updated the + dispatch status, and unlocks. Fixes a bug where certain + situations (like a broken pipe) could cause a Disconnect message + to not be sent, tricking the bus into thinking a service was still + there when the process had quit. + (_dbus_connection_send_preallocated): Call + _dbus_connection_send_preallocated_and_unlock(). + (_dbus_connection_send_and_unlock): Added. Calls + _dbus_connection_send_preallocated_and_unlock(). + (dbus_connection_send): Call _dbus_connection_send_and_unlock(). + (dbus_connection_send_with_reply): Update the dispatch status and + unlock. + + * mono/Service.cs (~Service): Added. Removes the filter so that + we don't get unmanaged code calling back into a GCed delegate. + (RemoveFilter); Added. + +2005-02-09 John (J5) Palmieri + + * dbus/dbus-message.c (dbus_message_iter_open_container): + - Removed check for iterator type being an array because + get_arg_type does not work with writer iterators + - Pass NULL to _dbus_type_writer_recurse if signiture is NULL + +2005-02-07 Havoc Pennington + + * doc/dbus-specification.xml: some more language cleanups; add + stuff about how to deal with invalid protocol and extension + points; add _ to allowed chars in auth commands; add EXTENSION_ + auth command prefix + +2005-02-06 Havoc Pennington + + * s/expected/required/ in a couple places for clarity + +2005-02-07 Colin Walters + + * bus/selinux.c (bus_selinux_allows_send): Handle NULL for + sender or proposed_recipient. + +2005-02-06 Havoc Pennington + + * dbus/dbus-message-factory.c (generate_special): more tests + + * dbus/dbus-marshal-validate.c (validate_body_helper): detect + array length that exceeds the maximum + +2005-02-05 Havoc Pennington + + * dbus/dbus-message-factory.c (generate_special): more test cases, + increasing coverage + + * dbus/dbus-marshal-validate.c (validate_body_helper): return the + reason why a signature was invalid + + * dbus/dbus-marshal-header.c (load_and_validate_field): fix to + skip the length of the string before we look at it in validation + + * dbus/dbus-string-util.c (_dbus_string_test): add tests for + equal_substring + + * dbus/dbus-message.c (_dbus_message_loader_new): default + max_message_length to DBUS_MAXIMUM_MESSAGE_LENGTH + +2005-02-05 Havoc Pennington + + * dbus/dbus-marshal-validate.c (validate_body_helper): fix crash + if the signature of a variant was empty + (_dbus_validate_signature_with_reason): catch "(a)" (array inside + struct with no element type) + + * dbus/dbus-message-factory.c (generate_uint32_changed): add more + mangled messages to break things + +2005-02-04 Havoc Pennington + + * glib/dbus-gproxy.c (dbus_g_proxy_disconnect_signal): use + g_quark_try_string() so it actually can return 0 + (dbus_g_proxy_connect_signal): ditto + +2005-02-04 Havoc Pennington + + * glib/dbus-gproxy.c (dbus_g_proxy_emit_remote_signal): fix a + bogus warning + (tristring_from_message): assert cleanly on null path/interface + (should not be possible though I decided later) + (dbus_g_proxy_dispose): move proxy manager unregistration here + (DBUS_G_PROXY_DESTROYED): add this macro, and use it in a bunch of + g_return_if_fail() checks + +2005-02-04 Havoc Pennington + + * doc/Makefile.am (EXTRA_DIST): add DTDs to makefile + + * doc/introspect.dtd: add introspect.dtd from David A. Wheeler + (with some minor changes) + + * doc/dbus-specification.xml: add deprecated attribute to + introspection format + +2005-01-31 Havoc Pennington + + * glib/dbus-gproxy.c: rewrite how signals work again, this time I + think it's sort of right + +2005-01-30 Havoc Pennington + + * tools/dbus-viewer.c: kind of half-ass hook up the option menu. + +2005-01-30 Havoc Pennington + + * tools/dbus-names-model.c: dynamically watch NameOwnerChanged + + * autogen.sh: change to autotools 1.9 + + * glib/dbus-gproxy.c: completely change how signals work + (dbus_g_proxy_add_signal): new function to specify signature of a + signal + (dbus_g_proxy_emit_received): marshal the dbus message to GValues, + and g_warning if the incoming message has the wrong signature. + +2005-01-30 Havoc Pennington + + * tools/dbus-names-model.c (have_names_notify): fix this + + * dbus/dbus-message.c (_dbus_message_iter_get_args_valist): clean + up the string array handling a bit + +2005-01-30 Havoc Pennington + + * glib/dbus-glib.c (dbus_g_pending_call_set_notify): new function + (dbus_g_pending_call_cancel): new function + + * dbus/dbus-glib.h: move GType decls for connection/message here; + * dbus/dbus-glib.c: move all the g_type and ref/unref stuff in + here, just kind of rationalizing how we handle all that + + * tools/dbus-names-model.c: new file for a tree model listing the + services on a bus + + * tools/dbus-tree-view.c (model_new): use proper typing on the + model rows + +2005-01-30 Havoc Pennington + + * glib/dbus-gmain.c: add a custom GSource back that just checks + whether the message queue has anything in it; otherwise, there are + cases where we won't see messages in the queue since there was no + IO visible to the glib main loop + + * dbus/dbus-connection-internal.h (_DBUS_DEFAULT_TIMEOUT_VALUE): + increase default message timeout to 25 seconds + +2005-01-30 Havoc Pennington + + * test/glib/test-profile.c (no_bus_stop_server): remove the + warning about the g_warning that I just fixed + + * glib/dbus-gmain.c: rewrite the main loop stuff to avoid the + custom source, seems to be a lot easier to understand and work + better. + +2005-01-30 Havoc Pennington + + I think this main loop thing is conceptually broken, but here are + some band aids. I'll maybe rewrite it in a minute. + + * glib/dbus-gmain.c (add_timeout): timeout stuff doesn't use the + custom GSource, so don't pass it in; confusing + (gsource_server_finalize, gsource_connection_finalize): add + finalize handlers that remove all the watches. + +2005-01-30 Havoc Pennington + + * glib/dbus-gobject.c (introspect_properties): fix the XML + generated + + * dbus/dbus-message.c (dbus_message_unref): add an in_cache flag + which effectively detects the use of freed messages + + * glib/dbus-gobject.c (handle_introspect): modify and return the + reply message instead of the incoming message + + * dbus/dbus-object-tree.c (handle_default_introspect_unlocked): + gee, maybe it should SEND THE XML instead of just making a string + and freeing it again ;-) + + * tools/dbus-print-message.c (print_message): improve printing of + messages + + * configure.in: add debug-glib.service to the output + +2005-01-30 Havoc Pennington + + dbus-viewer introspected and displayed the bus driver + + * dbus/dbus-object-tree.c + (object_tree_test_iteration): add tests for a handler registered on "/" + + * dbus/dbus-object-tree.c + (_dbus_decompose_path): fix to handle path "/" properly + (run_decompose_tests): add tests for path decomposition + + * glib/dbus-gutils.c (_dbus_gutils_split_path): fix to handle "/" + properly + + * glib/dbus-gobject.c (handle_introspect): fix quotes + + * test/glib/run-test.sh: support launching the bus, then running + dbus-viewer + + * test/glib/test-service-glib.c (main): put in a trivial gobject + subclass and register it on the connection + + * bus/driver.c (bus_driver_handle_introspect): implement + introspection of the bus driver service + + * dbus/dbus-protocol.h: add #defines for the XML namespace, + identifiers, doctype decl + + * bus/driver.c (bus_driver_handle_get_service_owner): handle + attempts to get owner of DBUS_SERVICE_ORG_FREEDESKTOP_DBUS by + returning the service unchanged. + (bus_driver_handle_message): remove old check for reply_serial in + method calls, now the message type deals with that + (bus_driver_handle_message): handle NULL interface + + * glib/dbus-gproxy.c (dbus_g_proxy_get_bus_name): new function + + * glib/dbus-gloader-expat.c (description_load_from_string): allow + -1 for len + + * tools/dbus-viewer.c: add support for introspecting a service on + a bus + + * glib/dbus-gproxy.c (dbus_g_pending_call_ref): add + (dbus_g_pending_call_unref): add + +2005-01-29 Havoc Pennington + + * tools/dbus-tree-view.c: add support for displaying properties. + (run dbus-viewer with an introspect xml file as arg, then resize + the window so the tree elements show up, not sure what that is) + + * glib/dbus-gobject.c (handle_introspect): return + org.freedesktop.Properties and org.freedesktop.Introspectable + interfaces when we are introspected. + + * doc/dbus-specification.xml: allow empty interface name when + Get/Set a property + +2005-01-29 Havoc Pennington + + * glib/Makefile.am: rename dbus-glib-tool to dbus-binding-tool; + though it uses glib, it could be extended for any binding in + principle + + * glib/dbus-gobject.c (gobject_message_function): change to the + new way properties work + + * dbus/dbus-protocol.h: add the new interfaces + + * doc/dbus-specification.xml: document the introspection format, + Introspectable interface, and add an org.freedesktop.Properties + interface. + + * glib/dbus-gparser.c: add support for a element + + * glib/dbus-gidl.c: add PropertyInfo + + * glib/dbus-gobject.c (handle_introspect): put the outermost + outside the signal and property descriptions. + (introspect_properties): export properties as rather + than as method calls + +2005-01-28 Havoc Pennington + + * doc/TODO, doc/dbus-specification.xml: spec and TODO tweaks + related to authentication protocol + +2005-01-28 John (J5) Palmieri + + * python/dbus_bindings.pyx.in: Updated to handle new D-BUS type system + - BUS_ACTIVATION -> BUS_STARTER + - DBUS_BUS_ACTIVATION -> DBUS_BUS_STARTER + - class MessageIter (__init__): Added recursion checking + so we throw a nice error instead of just disconnecting from the + bus. + (get): Added arg_type parameter for recursion. + Removed the nil type + Added signiture type placeholder (not implemented) + Added struct type placeholder (not implemented) + Added varient type placeholder (not implemented) + Commented out dict type for now + (get_element_type): renamed from get_array_type + (get_*): changed to use the dbus_message_iter_get_basic API + (get_*_array): removed in favor of recursive get_array method + (get_array): new recursive method which calls get to marshal + the elements of the array + (value_to_dbus_sig): New method returns the corrasponding + dbus signiture to a python value + (append): Comment out dict handling for now + Handle lists with the new recursive API + Comment out None handling for now + (append_nil): removed + (append_*): changed to use dbus_message_iter_append_basic API + (append_*_array): removed in favor of recursive append_array + method + (__str__): Make it easier to print out recursive iterators + for debugging + - class Message (__str__): moved type inspection to the + MessageIter class' __str__ method + (get_iter): Added an append parameter wich defaults to False + If True use the new API's to create an append iterator + + * python/dbus.py: Update to use new bindings API + - TYPE_ACTIVATION -> TYPE_STARTER + - class Bus (_get_match_rule): GetServiceOwner -> GetNameOwner + - class ActivationBus -> class StarterBus + - class RemoteObject (__call__): get an append iterator + - (_dispatch_dbus_method_call): get an append iterator + - class Object (emit_signal): get an append iterator + + * python/examples/: Fixed up the examples to work with the new API + +2005-01-28 Joe Shaw + + * configure.in: Bump version up to 0.30. + + * HACKING: Add a release item to bump the version number up after + a release. + +2005-01-28 Havoc Pennington + + * doc/dbus-specification.xml: update to describe 16-bit types and + dict entries + + * dbus/dbus-marshal-basic.c (_dbus_unpack_uint16): fix broken + assertion + + * dbus/dbus-protocol.h (DBUS_TYPE_DICT_ENTRY): add DICT_ENTRY as a + type + + * dbus/dbus-marshal-recursive.c: implement + +2005-01-27 Havoc Pennington + + * dbus/dbus-arch-deps.h.in: add 16/32-bit types + + * configure.in: find the right type for 16 and 32 bit ints as well + as 64 + + * dbus/dbus-protocol.h (DBUS_TYPE_INT16, DBUS_TYPE_UINT16): add + the 16-bit types so people don't have to stuff them in 32-bit or + byte arrays. + +2005-01-27 Havoc Pennington + + * dbus/dbus-message.c: byteswap the message if you init an + iterator to read/write from it + + * dbus/dbus-marshal-byteswap.c: new file implementing + _dbus_marshal_byteswap() + + * dbus/dbus-marshal-basic.c: add _dbus_swap_array() + +2005-01-26 Havoc Pennington + + * dbus/dbus-marshal-validate-util.c: break this out (and fix + build, apparently - nobody noticed?) + +2005-01-26 Havoc Pennington + + * dbus/dbus-marshal-recursive.h: remove todo comment + +2005-01-25 Joe Shaw + + * Land the mono binding changes to conform to the new APIs. + + * mono/Makefile.am: Remove Custom.cs, DBusType/Custom.cs, + DBusType/Dict.cs, and DBusType/Nil.cs from the build. + + * mono/Arguments.cs (GetCodeAsString): Added. Returns the dbus + type code as a string. + (InitAppending): Rename dbus_message_append_iter_init() to + dbus_message_iter_init_append(). + + * mono/BusDriver.cs: Rename ServiceEventHandler to + NameOwnerChangedHandler. Rename GetServiceOwner to GetOwner. + Rename ServiceOwnerChanged to NameOwnerChanged. + + * mono/Connection.cs: Rename BaseService to UniqueName, and the + underlying C call. + + * mono/Custom.cs: Removed. The CUSTOM type has been removed. + + * mono/Service.cs: Rename Exists to HasOwner, internally rename + dbus_bus_acquire_service() to dbus_bus_request_name(). + + * mono/DBusType/Array.cs (ctor): Use Type.GetElementType() instead + of Type.UnderlyingSystemType to get the correct element type for + the array. + (ctor): Update code for new APIs: use dbus_message_iter_recurse(), + dbus_message_get_{element|arg}_type() instead of + dbus_message_iter_init_array_iterator(). + (Append): Replace dbus_message_iter_append_array() with + dbus_message_iter_open_container() and + dbus_message_iter_close_container(). + + * mono/DBusType/Custom.cs, mono/DBusType/Nil.cs: Removed. These + types have been removed. + + * mono/DBusType/*.cs: Replace calls of + dbus_message_iter_get_[type]() to dbus_message_iter_get_basic(), + but specify the type in the DllImport extern declaration. Ditto + for dbus_message_iter_append_[type]() -> + dbus_message_iter_append_basic(). + + * mono/example/BusListener.cs: Update for ServiceEventHandler -> + NameOwnerChangedHandler. + +2005-01-25 John (J5) Palmieri + + * python/dbus_bindings.pyx.in: Rename of methods and bindings + - get_base_service -> get_unique_name + - bus_get_base_service -> bus_get_unique_name + - dbus_bus_get_base_service -> dbus_bus_get_unique_name + - ACTIVATION_REPLY_ACTIVATED -> DBUS_START_REPLY_SUCCESS + - ACTIVATION_REPLY_ALREADY_ACTIVE -> DBUS_START_REPLY_ALREADY_RUNNING + - bus_activate_service -> bus_start_service_by_name + - dbus_bus_activate_service -> dbus_bus_start_service_by_name + - bus_acquire_service -> bus_request_name + - dbus_bus_acquire_service -> dbus_bus_request_name + - bus_service_exists -> bus_name_has_owner + - dbus_bus_service_exists -> dbus_bus_name_has_owner + + * python/dbus.py: Rename of methods + - activate_service -> start_service_by_name + - bus_acquire_service -> bus_request_name + - ACTIVATION_REPLY_ACTIVATED -> START_REPLY_SUCCESS + - ACTIVATION_REPLY_ALREADY_ACTIVE -> START_REPLY_ALREADY_RUNNING + + +2005-01-24 Joe Shaw + + * dbus/dbus-connection.c (dbus_connection_dispatch): Print out the + signature for the method that can't be found. + + * dbus/dbus-message.c (dbus_message_iter_init): To check to see if + the message has any arguments, we need to call + _dbus_type_reader_get_current_type(), not + _dbus_type_reader_has_next(). + +2005-01-24 Havoc Pennington + + * dbus/dbus-message-factory.c: more testing of message validation + + * dbus/dbus-protocol.h (DBUS_MINIMUM_HEADER_SIZE): move to this + header + +2005-01-23 Havoc Pennington + + * dbus/dbus-message-factory.c, dbus/dbus-message-util.c: + get this all working, not many tests in the framework yet though + +2005-01-22 Havoc Pennington + + * doc/dbus-faq.xml, doc/dbus-tutorial: add a FAQ and update + tutorial, based on work from David Wheeler. + +2005-01-21 Havoc Pennington + + * dbus/dbus-bus.c: add more return_if_fail checks + + * dbus/dbus-message.c (load_message): have the "no validation" + mode (have to edit the code to toggle the mode for now though) + + * dbus/dbus-marshal-header.c (_dbus_header_load): have a mode that + skips all validation; I want to use this at least for benchmark + baseline, I'm not sure if it should be a publicly-available switch. + +2005-01-21 Havoc Pennington + + * glib/dbus-gmain.c: don't put the GLib bindings in the same + toplevel doxygen group as the low-level API stuff + + * dbus/dbus.h: note that libdbus is the low-level API + +2005-01-20 Havoc Pennington + + * update-dbus-docs.sh: script to update docs on the web site, only + works for me though. neener. + +2005-01-20 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_poll): amazingly, trying to compile + code can reveal bugs in it + +2005-01-20 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_poll): fix several bugs in the + select() version, patches from Tor Lillqvist + +2005-01-20 Havoc Pennington + + * doc/dbus-tutorial.xml: replace > with > + + * bus/services.c (bus_registry_acquire_service): validate the name + and return a better error if it's no good. + + * doc/dbus-specification.xml: note NO_AUTO_START change + + * dbus/dbus-protocol.h (DBUS_HEADER_FLAG_NO_AUTO_START): change + from AUTO_START, we're toggling the default + + * bus/dispatch.c: adapt the tests to change of auto-start default + +2005-01-18 Havoc Pennington + + * rename dbus-daemon-1 to dbus-daemon throughout + +2005-01-18 Havoc Pennington + + * Throughout, grand renaming to strip out the use of "service", + just say "name" instead (or "bus name" when ambiguous). Did not + change the internal code of the message bus itself, only the + programmer-facing API and messages. + + * doc/dbus-specification.xml: further update the message bus section + + * bus/config-parser.c (all_are_equiv): fix bug using freed string + in error case + +2005-01-17 Havoc Pennington + + * dbus/dbus-types.h: remove 16-bit types since we don't use them + ever + + * dbus/dbus-marshal-validate.c (_dbus_validate_path): disallow any + "invalid name character" not only non-ASCII + + * doc/dbus-specification.xml: further update spec, message bus + parts are still out-of-date but the marshaling etc. stuff is now + accurate-ish + +2005-01-17 Havoc Pennington + + * doc/dbus-specification.xml: partially update spec + +2005-01-17 Havoc Pennington + + * Throughout, align variant bodies according to the contained + type, rather than always to 8. Should save a fair bit of space in + message headers. + + * dbus/dbus-marshal-validate.c (_dbus_validate_body_with_reason): + fix handling of case where p == end + + * doc/TODO: remove the dbus_bool_t item and variant alignment items + +2005-01-17 Havoc Pennington + + * dbus/dbus-types.h: hardcode dbus_bool_t to 32 bits + + * Throughout: modify DBUS_TYPE_BOOLEAN to be a 32-bit type instead + of an 8-bit type. Now dbus_bool_t is the type to use whenever you + are marshaling/unmarshaling a boolean. + +2005-01-16 Havoc Pennington + + This is about it on what can be disabled/deleted from libdbus + easily, back below 150K anyhow. Deeper cuts are more work than + just turning the code off as I've done here. + + * dbus/dbus-marshal-basic.c (_dbus_pack_int32): we don't need the + signed int convenience funcs + + * dbus/dbus-internals.c (_dbus_verbose_real): omit when not in + verbose mode + + * dbus/dbus-string-util.c, dbus/dbus-string.c: more breaking + things out of libdbus + + * dbus/dbus-sysdeps.c, dbus/dbus-sysdeps-util.c: same + + * dbus/dbus-hash.c: purge the TWO_STRINGS crap (well, make it + tests-enabled-only, though it should probably be deleted) + + * dbus/dbus-message-util.c: same stuff + + * dbus/dbus-auth-util.c: same stuff + +2005-01-16 Havoc Pennington + + * dbus/dbus-userdb-util.c: split out part of dbus-userdb.c + + * dbus/dbus-sysdeps.c (_dbus_uid_from_string): move here to pave + way for stripping down dbus-userdb.c stuff included in libdbus. + Rename _dbus_parse_uid for consistency. + +2005-01-16 Havoc Pennington + + * dbus/dbus-internals.c (_dbus_real_assert): print the function + name the assertion failed in + + * dbus/dbus-internals.h (_dbus_return_if_fail) + (_dbus_return_val_if_fail): assert that the name of the function + containing the check doesn't start with '_', since we only want to + use checks on public functions + + * dbus/dbus-connection.c (_dbus_connection_ref_unlocked): change + checks to assertions + + * dbus/dbus-marshal-header.c (_dbus_header_set_field_basic): + change checks to asserts for private function + + * dbus/dbus-message.c (_dbus_message_set_serial): checks + to asserts for private function + + * dbus/dbus-marshal-recursive.c (skip_one_complete_type): remove + broken assertion that was breaking make check + (_dbus_type_reader_array_is_empty): remove this rather than fix + it, was only used in assertions + +2005-01-16 Havoc Pennington + + * test/unused-code-gc.py: hacky script to find code that's used + only by the bus (not libdbus) or used only by tests or not used at + all. It has some false alarms, but looks like we can clean up a + lot of size from libdbus. + + * dbus/dbus-sysdeps.c, dbus/dbus-sysdeps-utils.c, + dbus/Makefile.am: initially move 10K of binary size out of libdbus + +2005-01-16 Havoc Pennington + + * Add and fix docs according to Doxygen warnings throughout + source. + + * dbus/dbus-marshal-recursive.c + (_dbus_type_reader_array_is_empty): change this to just call + array_reader_get_array_len() and make it static + + * dbus/dbus-message.c (dbus_message_iter_get_element_type): rename + from get_array_type + (dbus_message_iter_init_append): rename from append_iter_init + + * dbus/dbus-marshal-recursive.c + (_dbus_type_reader_get_element_type): rename from + _dbus_type_reader_get_array_type + +2005-01-15 Havoc Pennington + + * test/glib/test-profile.c (with_bus_server_filter): fix crash + + * dbus/dbus-marshal-basic.c (_dbus_unpack_uint32): inline as macro + when DBUS_DISABLE_ASSERT + (_dbus_marshal_set_basic): be sure we align for the string length + + * dbus/dbus-marshal-recursive.c (skip_one_complete_type): make + this look faster + + * dbus/dbus-string.c (_dbus_string_get_const_data_len): add an + inline macro version + (_dbus_string_set_byte): provide inline macro version + +2005-01-15 Havoc Pennington + + * Land the new message args API and type system. + + This patch is huge, but the public API change is not + really large. The set of D-BUS types has changed somewhat, + and the arg "getters" are more geared toward language bindings; + they don't make a copy, etc. + + There are also some known issues. See these emails for details + on this huge patch: + http://lists.freedesktop.org/archives/dbus/2004-December/001836.html + http://lists.freedesktop.org/archives/dbus/2005-January/001922.html + + * dbus/dbus-marshal-*: all the new stuff + + * dbus/dbus-message.c: basically rewritten + + * dbus/dbus-memory.c (check_guards): with "guards" enabled, init + freed blocks to be all non-nul bytes so using freed memory is less + likely to work right + + * dbus/dbus-internals.c (_dbus_test_oom_handling): add + DBUS_FAIL_MALLOC=N environment variable, so you can do + DBUS_FAIL_MALLOC=0 to skip the out-of-memory checking, or + DBUS_FAIL_MALLOC=10 to make it really, really, really slow and + thorough. + + * qt/message.cpp: port to the new message args API + (operator<<): use str.utf8() rather than str.unicode() + (pretty sure this is right from the Qt docs?) + + * glib/dbus-gvalue.c: port to the new message args API + + * bus/dispatch.c, bus/driver.c: port to the new message args API + + * dbus/dbus-string.c (_dbus_string_init_const_len): initialize the + "locked" flag to TRUE and align_offset to 0; I guess we never + looked at these anyhow, but seems cleaner. + + * dbus/dbus-string.h (_DBUS_STRING_ALLOCATION_PADDING): + move allocation padding macro to this header; use it to implement + (_DBUS_STRING_STATIC): ability to declare a static string. + + * dbus/dbus-message.c (_dbus_message_has_type_interface_member): + change to return TRUE if the interface is not set. + + * dbus/dbus-string.[hc]: move the D-BUS specific validation stuff + to dbus-marshal-validate.[hc] + + * dbus/dbus-marshal-basic.c (_dbus_type_to_string): move here from + dbus-internals.c + + * dbus/Makefile.am: cut over from dbus-marshal.[hc] + to dbus-marshal-*.[hc] + + * dbus/dbus-object-tree.c (_dbus_decompose_path): move this + function here from dbus-marshal.c + +2005-01-12 Joe Shaw + + * NEWS: Update for 0.23. + + * configure.in: Release 0.23. + +2005-01-12 Joe Shaw + + * mono/Makefile.am, mono/example/Makefile.am: Always build the + dbus DLL with --debug. Clean up after the .mdb files this leaves + behind. + + * mono/doc/Makefile.am: Need to uninstall the docs on "make + uninstall" + + * mono/Arguments.cs (GetDBusTypeConstructor): If the type + is an enum, get the enum's underlying type. Another mono + 1.1.3 fix. + +2005-01-11 Joe Shaw + + Patch from Sjoerd Simons + + * mono/Makefile.am, mono/example/Makefile.am: Don't redefine + DESTDIR. It breaks stuff. + +2005-01-11 Joe Shaw + + Patch from Tambet Ingo + + * mono/DBusType/Array.cs (Get): Get the underlying element type by + calling type.GetElementType(). The code previously depended on + broken Mono behavior, which was fixed in Mono 1.1.3. + + * mono/DBusType/Dict.cs (constructor): Fix the parameters for + Activator.CreateInstance() so that the class's constructor is + called with the right parameters. + +2005-01-11 Joe Shaw + + Patch from Timo Teräs + + * dbus/dbus-connection.c + (_dbus_connection_queue_received_message_link): Call + _dbus_connection_remove_timeout() instead of the _locked() + variant, since it's always called from + _dbus_connection_handle_watch(), which handles the locking. + Removed the _locked() variant since it's no longer used. + +2005-01-03 Havoc Pennington + + * dbus/dbus-internals.h: I'm an idiot, _dbus_assert certainly can + return + +2004-12-26 Havoc Pennington + + * dbus/dbus-internals.h: add _DBUS_GNUC_NORETURN to _dbus_assert + +2005-01-03 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_sysdeps_test): fix using == on + floating point + + * dbus/dbus-string.c (_dbus_string_insert_alignment): new function + +2005-01-02 Havoc Pennington + + * dbus/dbus-internals.h (_DBUS_ALIGN_OFFSET): new macro + +2005-01-01 Havoc Pennington + + * configure.in: add -Wfloat-equal + +2005-01-01 Havoc Pennington + + * dbus/dbus-sysdeps.h: add _DBUS_DOUBLES_BITWISE_EQUAL macro, + for a variety of reasons '==' doesn't do this. + +2004-12-31 Havoc Pennington + + * dbus/dbus-string.c (_dbus_string_equal_substrings): new function + I keep wishing I had + +2004-12-30 John (J5) Palmieri + + * python/dbus.py: s/ACTIVATION_REPLY_ACTIVE/ACTIVATION_REPLY_ACTIVATED + +2004-12-30 John (J5) Palmieri + + * python/dbus_bindings.pyx.in: Change DBUS_ACTIVATION_REPLY_ACTIVATED + and DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE to match the values in + dbus-protocol.h. Because they are defines and not enums they are not + autogenerated. + +2004-12-26 John (J5) Palmieri + + * python/dbus_bindings.pyx.in (bus_activate_service): Bind + dbus_bus_activate_service + + * python/dbus.py (Bus.activate_service): activate a service on the + bus. + +2004-12-24 Havoc Pennington + + * test/decode-gcov.c: change to use .gcno and .gcda files, but the + file format has also changed and I haven't adapted to that yet + + * Makefile.am: load .gcno files from latest gcc + +2004-12-23 John (J5) Palmieri + * Patch from Rob Taylor + + * python/dbus_bindings.pyx.in (bus_get_unix_user): New + lowlevel binding + + * python/dbus.py (get_unix_user): Added binding to + call dbus_bindings.bus_get_unix_user + + * python/extract.py: Modified the proto_pat regex to + handle unsigned long + +2004-12-21 Olivier Andrieu + + * dbus/make-dbus-glib-error-enum.sh: omit the function keyword for + better POSIX compliance. + +2004-12-19 Havoc Pennington + + * dbus/dbus-string.c (_dbus_string_insert_4_aligned) + (_dbus_string_insert_8_aligned): new functions + + * dbus/dbus-string.c (_dbus_string_alloc_space): new function + +2004-12-18 Havoc Pennington + + * dbus/dbus-string.c (_dbus_string_validate_ascii): use ISASCII + macro + + * dbus/dbus-message.c: fix a comment, and add a still-unused + not-implemented function + + * dbus/dbus-marshal.h: fix comment + + * dbus/dbus-internals.h (_DBUS_ISASCII): new macro + +2004-12-17 Joe Shaw + + * mono/DBusType/Byte.cs, mono/DBusType/Int32.cs, + mono/DBusType/Int64.cs, mono/DBusType/UInt32.cs, + mono/DBusType/UInt64.cs: Use Enum.GetUnderlyingType() instead of + Type.UnderlyingSystemType to get the actual system type + underneath. This code previously depended on the broken Mono + behavior, which was fixed in 1.1.3. + +2004-11-27 Havoc Pennington + + * dbus/dbus-string.h (_dbus_string_get_byte): inline when asserts + are disabled + (_dbus_string_get_const_data): inline when asserts are disabled + + * dbus/dbus-message.c: record the _dbus_current_generation of + creation so we can complain if dbus_shutdown() is used improperly. + Do this only if checks are enabled. + + * dbus/dbus-connection.c: ditto + +2004-11-26 Havoc Pennington + + * test/glib/test-profile.c: add with_bus mode to profile echoes + that go through the bus. + + * test/glib/run-test.sh: add ability to run test-profile + + * bus/dbus-daemon-1.1.in: fix to say that SIGHUP causes partial + config file reload. + +2004-11-26 Havoc Pennington + + * test/glib/test-profile.c: clean up how the fake_malloc_overhead + thing was implemented + +2004-11-26 Havoc Pennington + + * test/glib/test-profile.c: tweak a bit, add support for some + made-up minimal malloc overhead with plain sockets, since in + real life some sort of buffers are unavoidable thus we could + count them in the theoretical best case + +2004-11-26 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_cache_or_finalize): fix bug + where I was trying to cache one too many messages + +2004-11-26 Havoc Pennington + + * dbus/dbus-message.c: reimplement message cache as an array which + makes the cache about twice as fast and saves maybe 1.5% overall + +2004-11-26 Havoc Pennington + + * dbus/dbus-threads.c (init_global_locks): forgot to put the + message cache lock here + +2004-11-26 Havoc Pennington + + * dbus/dbus-message.c (struct DBusMessage): put the locked bit and + the "char byte_order" next to each other to save 4 bytes + (dbus_message_new_empty_header): reduce preallocation, since the + message cache should achieve a similar effect + (dbus_message_cache_or_finalize, dbus_message_get_cached): add a + message cache that keeps a few DBusMessage around in a pool, + another 8% speedup or so. + + * dbus/dbus-dataslot.c (_dbus_data_slot_list_clear): new function + +2004-11-25 Havoc Pennington + + * dbus/dbus-transport-unix.c (unix_do_iteration): if we're going + to write, without reading or blocking, try it before the poll() + and skip the poll() if nothing remains to write. This is about a + 3% speedup in the echo client/server + +2004-11-25 Havoc Pennington + + The primary change here is to always write() once before adding + the write watch, which gives us about a 10% performance increase. + + * dbus/dbus-transport-unix.c: a number of modifications to cope + with removing messages_pending + (check_write_watch): properly handle + DBUS_AUTH_STATE_WAITING_FOR_MEMORY; adapt to removal of + messages_pending stuff + (check_read_watch): properly handle WAITING_FOR_MEMORY and + AUTHENTICATED cases + (unix_handle_watch): after writing, see if the write watch can be + removed + (unix_do_iteration): assert that write_watch/read_watch are + non-NULL rather than testing that they aren't, since they + aren't allowed to be NULL. check_write_watch() at the end so + we add the watch if we did not finish writing (e.g. got EAGAIN) + + * dbus/dbus-transport-protected.h: remove messages_pending call, + since it resulted in too much inefficient watch adding/removing; + instead we now require that the transport user does an iteration + after queueing outgoing messages, and after trying the first + write() we add a write watch if we got EAGAIN or exceeded our + max bytes to write per iteration setting + + * dbus/dbus-string.c (_dbus_string_validate_signature): add this + function + + * dbus/dbus-server-unix.c (unix_finalize): the socket name was + freed and then accessed, valgrind flagged this bug, fix it + + * dbus/dbus-message.c: fix several bugs where HEADER_FIELD_LAST was taken + as the last valid field plus 1, where really it is equal to the + last valid field. Corrects some message corruption issues. + + * dbus/dbus-mainloop.c: verbosity changes + + * dbus/dbus-keyring.c (_dbus_keyring_new_homedir): handle OOM + instead of aborting in one of the test codepaths + + * dbus/dbus-internals.c (_dbus_verbose_real): fix a bug that + caused not printing the pid ever again if a verbose was missing + the newline at the end + (_dbus_header_field_to_string): add HEADER_FIELD_SIGNATURE + + * dbus/dbus-connection.c: verbosity changes; + (dbus_connection_has_messages_to_send): new function + (_dbus_connection_message_sent): no longer call transport->messages_pending + (_dbus_connection_send_preallocated_unlocked): do one iteration to + try to write() immediately, so we can avoid the write watch. This + is the core purpose of this patchset + (_dbus_connection_get_dispatch_status_unlocked): if disconnected, + dump the outgoing message queue, so nobody will get confused + trying to send them or thinking stuff is pending to be sent + + * bus/test.c: verbosity changes + + * bus/driver.c: verbosity/assertion changes + + * bus/dispatch.c: a bunch of little tweaks to get it working again + because this patchset changes when/where you need to block. + +2004-11-23 Havoc Pennington + + * test/glib/test-profile.c: modify to accept a plain_sockets + argument in which case it will bench plain sockets instead of + libdbus, for comparison purposes. + +2004-11-22 Havoc Pennington + + * test/glib/test-profile.c (N_CLIENT_THREADS): run multiple + threads for more time, so sysprof can get a grip on it. + + * dbus/dbus-string.c (_dbus_string_validate_utf8): remove + pointless variable + +2004-11-13 Havoc Pennington + + * test/glib/test-profile.c: fix this thing up a bit + + * dbus/dbus-message.c (dbus_message_new_empty_header): increase + preallocation sizes by a fair bit; not sure if this will be an + overall performance win or not, but it does reduce reallocs. + + * dbus/dbus-string.c (set_length, reallocate_for_length): ignore + the test hack that forced constant realloc if asserts are + disabled, so we can profile sanely. Sprinkle in some + _DBUS_UNLIKELY() which are probably pointless, but before I + noticed the real performance problem I put them in. + (_dbus_string_validate_utf8): micro-optimize this thing a little + bit, though callgrind says it didn't help; then special-case + ascii, which did help a lot; then be sure we detect nul bytes as + invalid, which is a bugfix. + (align_length_then_lengthen): add some more _DBUS_UNLIKELY + superstition; use memset to nul the padding instead of a manual + loop. + (_dbus_string_get_length): inline this as a + macro; it showed up in the profile because it's used for loop + tests and so forth + +2004-11-10 Colin Walters + + * dbus/dbus-spawn.c (check_babysit_events): Handle EINTR, + for extra paranoia. + +2004-11-09 Colin Walters + + * dbus/dbus-string.c (_dbus_string_get_length): New + function, writes DBusString to C buffer. + + * dbus/dbus-string.h: Prototype it. + + * dbus/dbus-message.c (dbus_message_type_to_string): New + function, converts message type into C string. + + * dbus/dbus-message.h: Prototype it. + + * bus/selinux.c (bus_selinux_check): Take source pid, + target pid, and audit data. Pass audit data to + avc_has_perm. + (log_audit_callback): New function, appends extra + audit information. + (bus_selinux_allows_acquire_service): Also take + service name, add it to audit data. + (bus_selinux_allows_send): Also take message + type, interface, method member, error name, + and destination, and add them to audit data. + (log_cb): Initialize func_audit. + + * bus/selinux.h (bus_selinux_allows_acquire_service) + (bus_selinux_allows_send): Update prototypes + + * bus/services.c (bus_registry_acquire_service): Pass + service name to bus_selinux_allows_acquire_service. + + * bus/bus.c (bus_context_check_security_policy): Pass + additional audit data. Move assignment of dest + to its own line. + +2004-11-07 Colin Walters + + * dbus/dbus-transport-unix.c (do_authentication): Always + initialize auth_completed. + +2004-11-07 Colin Walters + + * bus/bus.c (load_config): Break into three + separate functions: process_config_first_time_only, + process_config_every_time, and process_config_postinit. + (process_config_every_time): Move call of + bus_registry_set_service_context_table into + process_config_postinit. + (process_config_postinit): New function, does + any processing that needs to happen late + in initialization (and also on reload). + (bus_context_new): Instead of calling load_config, + open config parser here and call process_config_first_time_only + and process_config_every_time directly. Later, after + we have forked but before changing UID, + invoke bus_selinux_full_init, and then call + process_config_postinit. + (bus_context_reload_config): As in bus_context_new, + load parse file inside here, and call process_config_every_time + and process_config_postinit. + + * bus/services.h, bus/services.c + (bus_registry_set_service_context_table): Rename + from bus_registry_set_sid_table. Take string hash from config + parser, and convert them here into SIDs. + + * bus/config-parser.c (struct BusConfigParser): Have + config parser only store a mapping of service->context + string. + (merge_service_context_hash): New function. + (merge_included): Merge context string hashes instead + of using bus_selinux_id_table_union. + (bus_config_parser_new): Don't use bus_selinux_id_table_new; + simply create a new string hash. + (bus_config_parser_unref): Unref it. + (start_selinux_child): Simply insert strings into hash, + don't call bus_selinux_id_table_copy_over. + + * bus/selinux.h, bus/selinux.c (bus_selinux_id_table_union) + (bus_selinux_id_table_copy_over): Delete. + +2004-11-03 Colin Walters + + * bus/selinux.c (bus_selinux_pre_init): Kill some unused + variables. + +2004-11-03 Colin Walters + + * bus/test-main.c (test_pre_hook): Fix test logic, + thanks Joerg Barfurth . + +2004-11-02 Colin Walters + + * bus/selinux.c (bus_selinux_init): Split into two functions, + bus_selinux_pre_init and bus_selinux_post_init. + (bus_selinux_pre_init): Just determine whether SELinux is + enabled. + (bus_selinux_post_init): Do everything else. + + * bus/main.c (main): Call bus_selinux_pre_init before parsing + config file, and bus_selinux_post_init after. This ensures that + we don't lose the policyreload notification thread that + bus_selinux_init created before forking previously. + + * bus/test-main.c (test_pre_hook): Update for split. + +2004-10-31 Owen Fraser-Green + + Patch from Johan Fischer + + * mono/doc/Makefile.am (install-data-local): Added directory + install for DESTDIR + +2004-10-29 Colin Walters + + * dbus/dbus-sysdeps.h (_dbus_become_daemon): Also take + parameter for fd to write pid to. + + * dbus/dbus-sysdeps.c (_dbus_become_daemon): Implement it. + + * bus/bus.c (bus_context_new): Pass print_pid_fd + to _dbus_become_daemon (bug #1720) + +2004-10-29 Colin Walters + + Patch from Ed Catmur + + * mono/doc/Makefile.am (install-data-local): Handle + DESTDIR. + +2004-10-29 Colin Walters + + * bus/.cvsignore, qt/.cvsignore: Update. + +2004-10-29 Colin Walters + + Patch from Kristof Vansant + + * configure.in: Detect Slackware. + * bus/Makefile.am (SCRIPT_IN_FILES): Add rc.messagebus.in. + * bus/rc.messagebus.in: New file. + +2004-10-29 Colin Walters + + * tools/dbus-monitor.c (filter_func): Return + DBUS_HANDLER_RESULT_HANDLED in filter function + for now. See: + http://freedesktop.org/pipermail/dbus/2004-August/001433.html + +2004-10-29 Colin Walters + + Patch from Matthew Rickard + + * bus/services.c (bus_registry_acquire_service): + Correctly retrieve service name from DBusString + for printing. + +2004-10-29 Colin Walters + + * dbus/dbus-glib.h: Update documentation to not + refer to internal APIs. + +2004-10-27 Joe Shaw + + * mono/Arguments.cs (GetDBusTypeConstructor): + type.UnderlyingSystemType will return "System.Byte" if you do it + on "byte[]", which is not what we want. So check the type.IsArray + property and use System.Array instead. + +2004-10-25 John (J5) Palmieri + + * dbus/dbus-sysdeps.c (fill_user_info): On errors do not free + the DBusUserInfo structure since this is passed into the function. + This would cause a double free when the function that allocated + the structure would try to free it when an error occured. + + * (bus/session.conf.in, bus/Makefile.am, dbus/configure.in): + use /usr/share/dbus-1/services instead of /usr/lib/dbus-1.0/services + for service activation to avoid 32bit/64bit parallel install issues + +2004-10-21 Colin Walters + + * AUTHORS: Fix my email address, the @gnu.org one + has been bouncing for some time. Also add J5. + +2004-10-21 Colin Walters + + * dbus/dbus-transport-unix.c (do_authentication): Return + authentication status to callers. + (unix_handle_watch): If we completed authentication this round, + don't do another read. Instead wait until the next iteration, + after we've read any pending data in the auth buffer. + (unix_do_iteration): Ditto. + (unix_handle_watch): Updated for new do_authentication prototype. + +2004-10-18 Colin Walters + + * bus/selinux.c (bus_selinux_enabled): Handle + --disable-selinux case. + +2004-10-18 Colin Walters + + * bus/selinux.h: Add bus_selinux_enabled. + + * bus/selinux.c (bus_selinux_enabled): Implement it. + + * bus/config-parser.c (struct include): Add + if_selinux_enabled member. + (start_busconfig_child): Parse if_selinux_enabled + attribute for include. + (bus_config_parser_content): Handle it. + + * bus/session.conf.in, bus/system.conf.in: Add + inclusion of context mapping to default config files; + conditional on SELinux being enabled. + + * doc/busconfig.dtd: Add to if_selinux_enabled to default DTD. + + * test/data/invalid-config-files/badselinux-1.conf, + test/data/invalid-config-files/badselinux-2.conf: + Test files for bad syntax. + +2004-10-17 Colin Walters + + * dbus/dbus-memory.c (_dbus_initialize_malloc_debug, check_guards) + (dbus_malloc, dbus_malloc0, dbus_realloc): Fix up printf + format specifier mismatches. + +2004-10-07 Olivier Andrieu + + * dbus/dbus-sysdeps.c (_dbus_file_get_contents): fix an incorrect + format string. + + * glib/dbus-dbus-gmain.c (dbus_g_bus_get): do not mangle NULL + pointer (bug #1540, Leonardo Boiko). + +2004-09-28 Jon Trowbridge + + * mono/BusDriver.cs: Changed BusDriver struct to remove + the ServiceCreated and ServiceDeleted events and replace them + with the new ServiceOwnerChanged event. + + * mono/example/BusListener.cs: Added a new example program, + which listens for and reports any ServiceOwnerChanged events + on the bus driver. + + * mono/example/Makefile.am (DESTDIR): Build changes for the + new BusListener.cs example. + +2004-09-27 Olivier Andrieu + + * bus/signals.c (bus_match_rule_parse): validate the components of + match rules (bug #1439). + + * dbus/dbus-bus.c (dbus_bus_add_match): add a missing OOM test. + +2004-09-24 Olivier Andrieu + + * doc/dbus-specification.xml: document ServiceOwnerChanged + signal. + + * bus/driver.c, bus/driver.h, bus/services.c: Use + ServiceOwnerChanged signal instead of ServiceCreated and + ServiceDeleted. + + * bus/dispatch.c: update testcase for the new signal. + +2004-09-20 Jon Trowbridge + + Patch from Nat Friedman + + * mono/Makefile.am: A number of small build fixes to allow "make + distcheck" to succeed. + + * mono/example/Makefile.am: "make distcheck" fixes. + + * mono/AssemblyInfo.cs.in: When signing the assembly, look for the + key in @srcdir@. + + * test/Makefile.am: "make distcheck" fixes. + +2004-09-17 Olivier Andrieu + + * dbus/dbus-sysdeps.c (_dbus_user_at_console): fix memleak in OOM. + + * doc/busconfig.dtd: update the DTD for the at_console attribute. + + * bus/driver.c (bus_driver_handle_hello): correctly handle Hello + messages after the first one (bug #1389). + + * bus/dispatch.c (check_double_hello_message): add a test case for + the double hello message bug. + (check_existent_service_activation): fix check of spawning error. + +2004-09-16 David Zeuthen + + * python/dbus_bindings.pyx.in: Add support for int64 and uint64 + +2004-09-12 David Zeuthen + + Patch from Kay Sievers + + * bus/bus.c (bus_context_new): + * bus/bus.h: + * bus/main.c (usage) + (main): + Add commandline option --nofork to override configuration file + setting. + +2004-09-09 Olivier Andrieu + + * dbus/dbus-*.h: remove the ; after DBUS_(BEGIN|END)_DECLS. Some C + compilers don't like it (bug #974). + +2004-09-04 Harald Fernengel + + * qt/connection.*: Applied patch by Jérôme Lodewyck + to integrate an existing + connection into the Qt eventloop + +2004-08-30 Jon Trowbridge + + * mono/BusDriver.cs: Added. This is a class for interacting with + the org.freedesktop.DBus service. + + * mono/Message.cs: Added a mechanism to expose the message that is + currently being dispatched via the static Message.Current + property. Added Message.Sender and Message.Destination + properties. + + * mono/Handler.cs: Expose the dispatched message via + Message.Current when handling method calls. + + * mono/Service.cs: Expose the dispatched message via + Message.Current when handling signal emissions. + + * mono/Connection.cs: Bind dbus_bus_get_base_service via the + Connection.BaseService property. + +2004-08-28 Havoc Pennington + + * dbus/dbus-userdb.c (_dbus_is_console_user): remove unused variable + + More fixes from Steve Grubb + + * dbus/dbus-sysdeps.c (_dbus_connect_tcp_socket): fix fd leak + (_dbus_listen_tcp_socket): fix fd leak + + * dbus/dbus-spawn.c (read_pid, read_ints): move the "again:" for + EINTR to a bit lower in the code + +2004-08-26 Jon Trowbridge + + * bus/driver.c (bus_driver_handle_service_exists): Respond with + TRUE if we are inquiring about the existence of the built-in + org.freedesktop.DBus service. + +2004-08-25 John Palmieri + * bus/config-parser.c: + (struct PolicyType): Add POLICY_CONSOLE + (struct Element.d.policy): s/gid_or_uid/gid_uid_or_at_console + (start_busconfig_child): Sets up console element when + is encountered in a policy file + (append_rule_from_element): Convert console elements to console + rules. + + * bus/policy.c: + (bus_policy_create_client_policy): Add console rules to the client + policy based on if the client is at the console + (bus_policy_append_console_rule): New function for adding a + console rule to a policy + (bus_policy_merge): Handle console rule merging + + * dbus/dbus-sysdeps.h: Added the DBUS_CONSOLE_DIR constant + where we check for console user files + + * dbus/dbus-sysdeps.c: + (_dbus_file_exists): New function which checks if the given + file exists + (_dbus_user_at_console): New function which does the system + specific process of checking if the user is at the console + + * dbus/dbus-userdb.c: + (_dbus_is_console_user): New function converts a UID to user name + and then calls the system specific _dbus_user_at_console to + see if the user is at the console and therefor a console user + +2004-08-25 Olivier Andrieu + + * bus/config-parser.c (set_limit): + * bus/dbus-daemon-1.1.in: + * test/data/valid-config-files/many-rules.conf: set the + max_match_rules_per_connection limt from the config file. + + * doc/busconfig.dtd: update the DTD. + + * bus/driver.c: remove some unused variables. + +2004-08-24 Mikael Hallendal + + * dbus/dbus-glib-lowlevel.h: Removed dbus_bus_get_with_g_main since + it's been replaced by dbus_g_bus_get + +2004-08-23 Colin Walters + + Updated SELinux support from Matthew Rickard + + * bus/selinux.h: Prototype bus_selinux_get_policy_root. + + * bus/selinux.c: Create a thread for policy reload notification. + (bus_selinux_get_policy_root): Implement. + + * bus/config-parser.c (start_busconfig_child) + (bus_config_parser_content): Support SELinux-root relative + inclusion. + + * configure.in : Add -lpthread. + + * bus/test-main.c (test_pre_hook, test_post_hook): New. + (test_post_hook): Move memory checking into here. + (test_pre_hook, test_post_hook): Move SELinux checks in + here, but conditional on a DBUS_TEST_SELINUX environment + variable. Unfortunately we can't run the SELinux checks + as a normal user, since they won't have any permissions + for /selinux. So this will have to be tested manually + for now, until we have virtualization for most of + libselinux. + +2004-08-23 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_change_identity): add setgroups() to + drop supplementary groups, suggested by Steve Grubb + +2004-08-20 Colin Walters + + * bus/config-parser.c (start_busconfig_child): Remove some unused + variables. + + * bus/selinux.c (bus_selinux_id_table_insert): Avoid compiler + warning. + +2004-08-17 Joe Shaw + + * configure.in: If --enable-mono is passed in, if we can't find + mono error out. + + * mono/Makefile.am: Use /gacutil to install assemblies into the + GAC and not /root. + +2004-08-12 Havoc Pennington + + * NEWS: update for 0.22 + + * configure.in: release 0.22 + +2004-08-11 Colin Walters + + * tools/dbus-send.c (main, usage): Add --reply-timeout + argument. + +2004-08-10 Olivier Andrieu + + * bus/bus.c (process_config_first_time_only): get rid of an unused + DBusError that was causing a memoy leak (bug #989). + + * dbus/dbus-keyring.c, dbus/dbus-message.c: + fix compilation on Solaris/Forte C (bug #974) + + * bus/main.c (main): plug two minuscule memleaks. + +2004-08-10 Havoc Pennington + + * doc/dbus-tutorial.xml: add some more info on GLib bindings + +2004-08-09 Havoc Pennington + + * COPYING: switch to Academic Free License version 2.1 instead of + 2.0, to resolve complaints about patent termination clause. + +2004-07-31 John (J5) Palmieri + + * README: added documentation for the --enable-python + configure switch. + +2004-07-31 Olivier Andrieu + + * bus/config-parser.c (bus_config_parser_new): fix an invalid + _unref in the SELinux support. + + * doc/busconfig.dtd: update DTD for SELinux support. + + * bus/config-loader-libxml.c: fix error handler and parser + initialisation/cleanup. OOM test now works with libxml2 HEAD. + + * configure.in: remove the warning about libxml2. + + * dbus/dbus-bus.c: silence doxygen warning. + +2004-07-31 Colin Walters + + * configure.in: Move #error in SELinux check to its own line. + +2004-07-31 Olivier Andrieu + + * dbus/dbus-internals.h (_DBUS_SET_OOM): + * bus/utils.h (BUS_SET_OOM): use dbus_error_set_const instead of + dbus_error_set. + + * bus/dispatch.c (check_send_exit_to_service): fix the test case, + broken by the change in the _SET_OOM macros. + +2004-07-31 Colin Walters + + * bus/selinux.c : Include utils.h to get + BUS_SET_OOM. + +2004-07-31 Colin Walters + + * configure.in: Use AC_TRY_COMPILE instead of AC_EGREP_HEADER + to correctly detect DBUS__ACQUIRE_SVC. Also add an + AC_MSG_CHECKING. + +2004-07-24 Havoc Pennington + + SELinux support from Matthew Rickard + + * bus/selinux.c, bus/selinux.h: new file encapsulating selinux + functionality + + * configure.in: add --enable-selinux + + * bus/policy.c (bus_policy_merge): add FIXME to a comment + + * bus/main.c (main): initialize and shut down selinux + + * bus/connection.c: store SELinux ID on each connection, to avoid + repeated getting of the string context and converting it into + an ID + + * bus/bus.c (bus_context_get_policy): new accessor, though it + isn't used + (bus_context_check_security_policy): check whether the security + context of sender connection can send to the security context of + recipient connection + + * bus/config-parser.c: add parsing for and + + * dbus/dbus-transport.c (_dbus_transport_get_unix_fd): to + implement dbus_connection_get_unix_fd() + + * dbus/dbus-connection.c (dbus_connection_get_unix_fd): new + function, used by the selinux stuff + +2004-07-29 Olivier Andrieu + + * bus/config-loader-libxml.c: complete the implementation of + libxml backend for config file loader. Doesn't work with full OOM + test yet. + + * configure.in: change error when selecting libxml into a warning. + + * test/data/invalid-config-files: add two non-well-formed XML + files. + + * glib/Makefile.am: libdbus_gtool always uses expat, not libxml. + + * dbus/dbus-transport-unix.c (unix_handle_watch): do not + disconnect in case of DBUS_WATCH_HANGUP, several do_reading() may + be necessary to read all the buffer. (bug #894) + + * bus/activation.c (bus_activation_activate_service): fix a + potential assertion failure (bug #896). Small optimization in the + case of auto-activation messages. + + * dbus/dbus-message.c (verify_test_message, _dbus_message_test): + add test case for byte-through-vararg bug (#901). patch by Kimmo + Hämäläinen. + +2004-07-28 Anders Carlsson + + * python/dbus.py: + * python/dbus_bindings.pyx.in: + Add dbus.init_gthreads (), allow emit_signal to pass + arguments to the signal. + +2004-07-24 Havoc Pennington + + * AUTHORS: add some people, not really comprehensively, let me + know if I missed you + +2004-07-24 Havoc Pennington + + * Makefile.am (DIST_SUBDIRS): add DIST_SUBDIRS, problem solved by + Owen + + * test/Makefile.am (DIST_SUBDIRS): here also + +2004-07-22 Olivier Andrieu + + * dbus/dbus-sysdeps.c (fill_user_info): fix inexistent label name, + breaking build on Solaris, reported by Farhad Saberi on the ML. + + * dbus/dbus-message.c (dbus_message_append_args_valist): fix the + va_arg invocation to account for integer promotion in the case of + DBUS_TYPE_BYTE (unsigned char is promoted to int). (bug #901) + + * bus/services.c (bus_service_remove_owner): fix bug #902, use + _dbus_list_get_first_link, not _dbus_list_get_first. + + * dbus/dbus-bus.c (dbus_bus_service_exists): plug a memory leak. + + * dbus/dbus-object-tree.c (free_subtree_recurse): always null + handler functions so that the asserts in _dbus_object_subtree_unref + do not fail. + + * dbus/dbus-transport-unix.c (do_reading): + _dbus_transport_queue_messages return value is of type + dbus_bool_t, not DBusDispatchStatus. + +2004-07-19 David Zeuthen + + * dbus/dbus-protocol.h: Add DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN + + * bus/dispatch.c: + (check_get_connection_unix_user): Debug says GetProperty; but the + method is called GetConnectionUnixUser + (check_get_connection_unix_process_id): New function + (bus_dispatch_test): Actually call check_get_connection_unix_user(); + also call check_get_connection_unix_process_id() + + * bus/driver.c: + (bus_driver_handle_get_connection_unix_process_id): New function, + handles GetConnectionUnixProcessID on the org.freedesktop.DBus + interface + + * dbus/dbus-auth.c: + (handle_server_data_external_mech): Set pid from the credentials + obtained from the socket + + * dbus/dbus-connection.c: + (dbus_connection_get_unix_process_id): New function + + * dbus/dbus-connection.h: + Add prototype for dbus_connection_get_unix_process_id + + * dbus/dbus-transport.c: + (_dbus_transport_get_unix_process_id): New function + + * dbus/dbus-transport.h: + Add prototype for _dbus_transport_get_unix_process_id + +2004-07-19 Olivier Andrieu + + * dbus/dbus-message.c: Message counter fix, patch by Christian + Hammond + +2004-07-18 Seth Nickell + + * python/dbus.py: + * python/dbus_bindings.pyx.in: + * python/tests/test-client.py: + + Add dbus.ByteArray and dbus_bindings.ByteArray + types so that byte streams can be passed back. + + Give jdahlin the heaps of credit that are so + rightfully his. + +2004-07-12 Seth Nickell + + * python/dbus.py: + + Add message argument to the default object_method_handler + function. + + * python/dbus_bindings.pyx.in: + + Automatically return NIL when passed an empty list + (we can't pass back a list since lists are typed + and we don't have any idea what type the the client + intended the list to be... :-( ) + +2004-07-10 Seth Nickell + + * python/examples/Makefile.am: + + Fix distcheck breakage caused by new examples. + +2004-07-10 Seth Nickell + + * python/dbus.py: + + Add "message" argument to service-side dbus.Object + methods. This will break existing services written + using the python bindings, but will allow extraction + of all the message information (e.g. who its from). + + Add improved "object oriented" signal handling/emission. + + * python/examples/example-service.py: + + Nix this example. + + * python/examples/example-signal-emitter.py: + * python/examples/example-signal-recipient.py: + + Two new examples that show how to emit and receive + signals using the new APIs. + + * python/examples/example-signals.py: + * python/examples/gconf-proxy-service.py: + * python/examples/gconf-proxy-service2.py: + + Add "message" argument to service methods. + +2004-06-28 Kay Sievers + + * bus/driver.c (bus_driver_handle_get_connection_unix_user) + * dbus/bus.c (dbus_bus_get_unix_user) + * doc/dbus-specification.xml: implement GetConnectionUnixUser + method of org.freedesktop.DBus interface. + + * bus/dispatch.c: test case + +2004-06-23 John (J5) Palmieri + + * python/Makefile.am: switched include directory from glib/ to dbus/ + since dbus-glib.h moved + +2004-06-22 Olivier Andrieu + + * configure.in: prevent building the gcj stuff and libxml loader + since they are broken. + +2004-06-20 Havoc Pennington + + * dbus/dbus-glib-error-enum.h: autogenerate the GError enum + codes from the dbus error names + + * glib/dbus-glib.h: move to subdir dbus/ since it's included + as dbus/dbus-glib.h and that breakage is now visible due to + including dbus/dbus-glib.h in dbus-glib-lowlevel.h + + * glib/dbus-glib.h: s/gproxy/g_proxy/ + + * dbus/dbus-shared.h: new header to hold stuff shared with + binding APIs + + * dbus/dbus-protocol.h (DBUS_ERROR_*): move errors here rather + than dbus-errors.h + + * glib/dbus-glib.h (dbus_set_g_error): move to + dbus-glib-lowlevel.h + + * glib/dbus-glib.h: remove dbus/dbus.h from here; change a bunch + of stuff to enable this + + * dbus/dbus-glib-lowlevel.h: put dbus/dbus.h here + + * a bunch of other changes with the same basic "separate glib + bindings from dbus.h" theme + +2004-06-10 Owen Fraser-Green + + * dbus-sharp.pc.in: Removed glib-sharp inclusion in Libs. + + * python/examples/Makefile.am: Fixed typo in EXTRA_DIST. + +2004-06-09 Olivier Andrieu + + * bus/driver.c, dbus/dbus-bus.c: use BOOLEAN instead of UINT32 for + the reply value of the ServiceExists message. + +2004-06-07 John (J5) Palmieri + + * python/dbus_bindings.pyx.in: No longer need to parse path + elements and pass them as arrays of strings. The C API now + accepts plain path strings. + (_build_parsed_path): removed + +2004-06-07 Havoc Pennington + + * doc/TODO: remove auto-activation item since it's done; sort + items by importance/milestone + +2004-06-07 Havoc Pennington + + * dbus/dbus-message-builder.c (_dbus_message_data_load): append + random signature when using REQUIRED_FIELDS (this hack won't work + in the long term) + + * dbus/dbus-message.c: change the signature to be a header field, + instead of message->signature special-case string. Incremental + step forward. Then we can fix up code to send the signature in the + message, then fix up code to validate said signature, then fix up + code to not put the typecodes inline, etc. + (load_one_message): don't make up the signature after the fact + (decode_header_data): require signature field for the known + message types + + * dbus/dbus-marshal.c (_dbus_marshal_string_len): new + + * dbus/dbus-protocol.h: add DBUS_HEADER_FIELD_SIGNATURE + +2004-06-07 Owen Fraser-Green + + * mono/DBusType/ObjectPath.cs: Renamed PathName argument to Path + + * mono/Handler.cs: Updated to follow new path argument for + (un-)registering objects. + + * mono/example/Makefile.am: + * mono/Makefile.am: + * configure.in: Bumped required version for mono and use new -pkg + syntax for deps + +2004-06-05 Olivier Andrieu + + * dbus/dbus-connection.h, dbus/dbus-connection.c: have object path + registration functions take the path argument as char* instead of + char**. + + * dbus/dbus-marshal.h, dbus/dbus-marshal.c (_dbus_decompose_path): + split off the path decompostion part of + _dbus_demarshal_object_path. Some misc. fixes to silence compiler + warnings. + + * glib/dbus-gobject.c, test/test-service.c: update accordingly. + +2004-06-02 Kristian Høgsberg + + * dbus/dbus-auth.c: Rewrite auth protocol handling to use a state + machine approach. A state is implemented as a function that + handles incoming events as specified for that state. + + * doc/dbus-specification.xml: Update auth protocol state machine + specification to match implementation. Remove some leftover + base64 examples. + +2004-06-02 Kristian Høgsberg + + * glib/dbus-gproxy.c, glib/dbus-gmain.c, dbus/dbus-string.c, + dbus/dbus-object-tree.c, dbus/dbus-message.c: add comments to + quiet doxygen. + + * Doxyfile.in: remove deprecated options. + + * dbus/dbus-message-handler.c, dbus/dbus-message-handler.h, + glib/test-thread.h, glib/test-thread-client.c, + glib/test-thread-server.c, glib/test-profile.c, + glib/test-dbus-glib.c: remove these unused files. + +2004-06-01 Olivier Andrieu + + * dbus/dbus-object-tree.c + (_dbus_object_tree_dispatch_and_unlock): fix dispatch for + non-fallback handlers (bug #684). + (_dbus_object_subtree_new): initialize invoke_as_fallback field. + (find_subtree_recurse): report wether the returned subtree is an + exact match or a "fallback" match higher up in the tree. + (object_tree_test_iteration): update test case. + +2004-06-01 Seth Nickell + + * python/dbus_bindings.pyx.in: + * python/tests/test-client.py: + + Round off basic type support. Add dicts (yay!), and + remaining array types. + + Make MessageIter more general so it works for dicts too. + + Mark all loop variables as C integers. + +2004-05-31 Havoc Pennington + + * glib/dbus-gidl.c (method_info_add_arg): keep args sorted with + "in" before "out" + + * glib/dbus-gobject.c (dbus_type_to_string): move to dbus-gutils.c + + * glib/dbus-glib-tool.c (main): set up to have a --self-test + option that runs the tests, and start filling in some code + including for starters just dumping the interfaces to stdout + + * glib/Makefile.am (INCLUDES): define DBUS_LOCALEDIR + + * test/data/valid-introspection-files/lots-of-types.xml: test of + an example introspection file + + * glib/dbus-gparser.c (parser_check_doctype): doctype should be + "node" (I think...) + +2004-05-31 Seth Nickell + + * python/dbus_bindings.pyx.in: + * python/tests/test-client.py: + + Test Suite: 1 + Python Bindings: 0 + + Fix string array memory trashing bug... oops... + +2004-05-30 Seth Nickell + + * python/dbus.py: + + Add a nicer-but-less-flexible alternate API for handling + calls to virtual objects in dbus.ObjectTree. + + Screw up the argument order to the dbus.Object constructor + for consistency with dbus.ObjectTree (and to make dbus_methods + optional for future extension) + + * python/examples/Makefile.am: + * python/examples/gconf-proxy-service.py: + * python/examples/gconf-proxy-service2.py: + + Alternate implementation of gconf-proxy-service using the + nicer dbus.ObjectTree API. + + * python/examples/example-service.py: + * python/tests/test-server.py + + Reverse the argument order to deal with dbus.Object constructor + changes. + +2004-05-30 Seth Nickell + + * python/examples/example-client.py: + * python/examples/example-service.py: + + Take it back. Lists seem to work but they're broken + in the test suite. Make the base examples use + lists (works fine). + +2004-05-30 Seth Nickell + + * python/dbus_bindings.pyx.in: + * python/tests/test-client.py: + + Add some more tests and fix errors that crop up. + Unfortunately, currently it seems like marshalling + and unmarshalling of lists is completely broken :-( + +2004-05-30 Seth Nickell + + * python/dbus_bindings.pyx.in: + + Add support for ObjectPath type. + + * python/dbus.py: + + Refactor message handling code to a common function. + + * python/tests/test-client.py: + * python/tests/test-server.py: + + Add tests that check to make sure values of all types + can be echoed from a service w/o mangling. + +2004-05-29 Seth Nickell + + * python/dbus.py: + + Add ObjectTree class which allows implementation + of trees of "virtual" objects. Basically the python + wrapper for "register_fallback". + + * python/examples/Makefile.am + * python/examples/gconf-proxy-client.py: + * python/examples/gconf-proxy-service.py: + + Implement a simple GConf proxy service that supports + get/set on string and int GConf keys using the ObjectTree. + +2004-05-29 Seth Nickell + + * python/dbus.py: + * python/examples/example-client.py: + * python/examples/example-service.py: + * python/examples/list-system-services.py: + + Add SessionBus, SystemBus and ActivationBus classes + so you don't need to know the special little BUS_TYPE + flag. + +2004-05-29 Havoc Pennington + + * bus/config-parser.c (process_test_valid_subdir): temporarily + stop testing config parser OOM handling, since expat has issues + http://freedesktop.org/pipermail/dbus/2004-May/001153.html + + * bus/dbus-daemon-1.1.in: change requested_reply to + send_requested_reply/receive_requested_reply so we can send the + replies, not just receive them. + + * bus/config-parser.c: parse the new + send_requested_reply/receive_requested_reply + + * bus/policy.c (bus_client_policy_check_can_send): add + requested_reply argument and use it + + * bus/bus.c (bus_context_check_security_policy): pass through + requested_reply status to message send check + + * bus/system.conf.in: adapt to requested_reply change + +2004-05-28 Havoc Pennington + + * test/glib/test-service-glib.c (main): remove unused variable + + * glib/dbus-gidl.c (base_info_ref): fix a silly compiler warning + + * dbus/dbus-auth.h (enum): remove AUTHENTICATED_WITH_UNUSED_BYTES + from the enum, no longer in use. + + * dbus/dbus-sysdeps.h: include config.h so DBUS_VA_COPY actually + works right. + + * dbus/dbus-message.c: add various _dbus_return_val_if_fail for + whether error_name passed in is a valid error name. + +2004-05-28 John (J5) Palmieri + + * dbus/dbus-message.c (dbus_message_get_args): Added support for + OBJECT_PATH and OBJECT_PATH_ARRAY + +2004-05-28 Seth Nickell + + * python/examples/Makefile.am: + + Forget to add Makefile.am. Do not pass go. + +2004-05-28 Michael Meeks + + * glib/dbus-gvalue.c (dbus_gvalue_marshal, dbus_gvalue_demarshal): + fix no int64 case. + + * dbus/dbus-string.c (_dbus_string_parse_basic_type): impl. + + * dbus/dbus-message.c (_dbus_message_iter_get_basic_type), + (_dbus_message_iter_get_basic_type_array): impl. + drastically simplify ~all relevant _get methods to use these. + (_dbus_message_iter_append_basic_array), + (dbus_message_iter_append_basic): impl + drastically simplify ~all relevant _append methods to use these. + + * dbus/dbus-message-builder.c (parse_basic_type) + (parse_basic_array, lookup_basic_type): impl. + (_dbus_message_data_load): prune scads of duplicate / + cut & paste coding. + + * dbus/dbus-marshal.c (_dbus_demarshal_basic_type_array) + (_dbus_demarshal_basic_type): implement, + (demarshal_and_validate_len/arg): beef up debug. + (_dbus_marshal_basic_type, _dbus_marshal_basic_type_array): impl. + +2004-05-27 Seth Nickell + + * configure.in: + * python/Makefile.am: + + Include the example python apps in the tarball. + + * python/examples/list-system-services.py + + Add a python new example that fetches the list of services + from the system bus. + +2004-05-27 Seth Nickell + + * python/dbus.py: + * python/dbus_bindings.pyx.in: + + Fix failure to notify that a signal was not handled, + resulted in hung functions. + +2004-05-25 Colin Walters + + * tools/dbus-monitor.c (main): Monitor all types of messages. + +2004-05-23 Owen Fraser-Green + + * mono/Handler.cs, mono/Service.cs: Added UnregisterObject method + which unregisters the object path and disposes the handler. + +2004-05-23 Kristian Høgsberg + + Patch from Timo Teräs (#614): + + * dbus/dbus-message.c (dbus_message_iter_get_args_valist): Swap + operands to && so we call dbus_message_iter_next () for the last + argument also. + +2004-05-21 Olivier Andrieu + + * dbus/dbus-object-tree.c + (_dbus_object_tree_list_registered_unlock, lookup_subtree): return + children even if the requested path isn't registered. + (object_tree_test_iteration): test object_tree_list_registered. + + * configure.in: undefine HAVE_ABSTRACT_SOCKETS instead of defining + it to 0. + +2004-05-20 Kristian Høgsberg + + * doc/TODO: Remove resolved items. + + * bus/expirelist.h (struct BusExpireList): remove unused n_items + field. + + * bus/connection.c (bus_connections_expect_reply): Enforce the + per-connection limit on pending replies. + + Patch from Jon Trowbridge : + + * bus/main.c (setup_reload_pipe): Added. Creates a pipe and sets + up a watch that triggers a config reload when one end of the pipe + becomes readable. + (signal_handler): Instead of doing the config reload in our SIGHUP + handler, just write to the reload pipe and let the associated + watch handle the reload when control returns to the main loop. + + * bus/driver.c (bus_driver_handle_reload_config): Added. + Implements a ReloadConfig method for requesting a configuration + file reload via the bus driver. + +2004-05-19 Owen Fraser-Green + + * HACKING: Updated release instructions concerning the wiki page. + +2004-05-18 Kristian Høgsberg + + * dbus/dbus-auth.c (client_try_next_mechanism): Remove logic to + filter against auth->allowed_mechs; we only add allowed mechs in + record_mechanisms(). + + * dbus/dbus-auth-script.c (_dbus_auth_script_run): Add an + ALLOWED_MECHS to auth-script format so we can set the list of + allowed mechanisms. + + * data/auth/client-out-of-mechanisms.auth-script: New test to + check client disconnects when it is out of mechanisms to try. + + * dbus/dbus-auth.c (process_command): Remove check for lines + longer that 1 MB; we only buffer up maximum 16 kB. + + * dbus/dbus-transport.c, dbus/dbus-transport-unix.c, + dbus/dbus-auth-script.c, dbus/dbus-auth.c, dbus/dbus-auth.h: + Remove auth state AUTHENTICATED_WITH_UNUSED_BYTES, instead always + assume there might be unused bytes. + + * dbus/dbus-auth.c (_dbus_auth_do_work): Remove check for + client-out-of-mechs, it is handled in process_reject(). Move check + for max failures to send_rejected(), as it's a server-only thing. + + * dbus/dbus-auth.c: Factor out protocol reply code into functions + send_auth(), send_data(), send_rejected(), send_error(), + send_ok(), send_begin() and send_cancel(). + +2004-05-17 Kristian Høgsberg + + Remove base64 encoding, replace with hex encoding. Original patch + from trow@ximian.com, added error handling. + + * dbus/dbus-string.c (_dbus_string_base64_encode) + (_dbus_string_base64_decode): Remove. + (_dbus_string_hex_decode): Add end_return argument so we can + distinguish between OOM and invalid hex encoding. + (_dbus_string_test): Remove base64 tests and add test case for + invalid hex. + + * dbus/dbus-keyring.c, dbus/dbus-auth-script.c, dbus/dbus-auth.c: + Replace base64 with hex. + + * test/data/auth/invalid-hex-encoding.auth-script: New test case + for invalid hex encoded data in auth protocol. + +2004-05-17 Olivier Andrieu + + * dbus/dbus-connection.c (check_for_reply_unlocked): plug a memory + leak. + +2004-05-15 Owen Fraser-Green + + * mono/dbus-sharp.dll.config.in: Added for GAC + * mono/dbus-sharp.snk: Added for GAC + * mono/Assembly.cs.in: Added for GAC + * mono/Makefile.am: Changes for GAC installation + * configure.in: Added refs for dbus-sharp.dll.config.in and + Assembly.cs.in. More fixes for mono testing + * mono/example/Makefile.am: Changed var to CSC + * Makefile.am: Changed flag name to DBUS_USE_CSC + +2004-05-15 Owen Fraser-Green + + * mono/Makefile.am: Added SUBDIRS for docs. Changed SUBDIRS order + * mono/doc/*: Added documentation framework + * configure.in: Added monodoc check + * README: Added description of mono configure flags + +2004-05-11 John (J5) Palmieri : + + * doc/dbus-specification.xml: Added a "Required" column to the + header fields table and changed the "zero or more" verbage in + the above paragraph to read "The header must contain the required + named header fields and zero or more of the optional named header + fields". + * test/data/invalid-messages/*.message: Added the required PATH + named header field to the tests so that they don't fail on + 'Missing path field' + +2004-05-07 John (J5) Palmieri + + * python/dbus-bindings.pyx.in: Stopped the bindings from trashing + the stack by implicitly defining variable and parameter types and + removing the hack of defining C pointers as python objects and later + casting them. + +2004-05-02 Owen Fraser-Green + + * mono/Makefile.am: Removed test-dbus-sharp.exe from all target + +2004-05-01 Owen Fraser-Green + + * mono/DBusType/Dict.cs: Handle empty dicts + * mono/DBusType/Array.cs: Handle empty arrays + * mono/Arguments.cs: Handle empty arguments + +2004-04-30 Owen Fraser-Green + + * dbus-sharp.pc.in: Modified to include include Libs and Requires + field + +2004-04-25 Kristian Høgsberg + + * test/data/valid-messages/standard-*.message: Update message + test scripts to new header field names. + +2004-04-22 John (J5) Palmieri + + * test/break-loader.c (randomly_do_n_things): tracked down buffer + overflow to times_we_did_each_thing array which would chop off the + first character of the failure_dir string. Increased the size of + the array to 7 to reflect the number of random mutation functions + we have. + +2004-04-21 Kristian Høgsberg + + * dbus/dbus-server-unix.c (unix_finalize): Don't unref + unix_server->watch here, it is unreffed in disconnect. + (_dbus_server_new_for_tcp_socket): convert NULL host to + "localhost" here so we don't append NULL to address. + + * dbus/dbus-server.c (_dbus_server_test): Add test case for + various addresses, including tcp with no explicit host. + +2004-04-21 Olivier Andrieu + + * dbus/dbus-message.c (decode_header_data, decode_string_field): + fix incorrect setting of .name_offset in the HeaderField (it was + off by two bytes, positioned right after the name and typecode) + + * bus/bus.c (bus_context_new, bus_context_unref): test before + calling dbus_server_free_data_slot and _dbus_user_database_unref + in case of an error. + + * tools/Makefile.am: add $(DBUS_GLIB_TOOL_LIBS), xml libs needed + by libdbus-gtool. + +2004-04-19 Kristian Høgsberg + + * dbus/dbus-transport-unix.c (unix_do_iteration): Rewrite to use + _dbus_poll() instead of select(). + +2004-04-15 Jon Trowbridge + + * bus/main.c (signal_handler): Reload the configuration files + on SIGHUP. + (main): Set up our SIGHUP handler. + + * bus/bus.c (struct BusContext): Store the config file, user and + fork flag in the BusContext. + (process_config_first_time_only): Added. Contains the code + (previously in bus_context_new) for setting up the BusContext from + the BusConfigParser that should only be run the first time the + config files are read. + (process_config_every_time): Added. Contains the code (previously + in bus_context_new) for setting up the BusContext from the + BusConfigParser that should be run every time the config files are + read. + (load_config): Added. Builds a BusConfigParser from the config + files and passes the resulting structure off to + process_config_first_time_only (assuming this is the first time) + and process_config_every_time. + (bus_context_new): All of the config-related code has been moved + to process_config_first_time_only and process_config_every_time. + Now this function just does the non-config-related initializations + and calls load_config. + (bus_context_reload_config): Added. + +2004-04-15 Olivier Andrieu + + * bus/driver.c (bus_driver_handle_get_service_owner): + implement a GetServiceOwner method. + * doc/dbus-specification.xml: document it. + * dbus/dbus-errors.h: add a 'ServiceHasNoOwner' error. + + * glib/dbus-gproxy.c (dbus_gproxy_new_for_service_owner): + implement, using the bus GetServiceOwner method. + + * test/glib/test-dbus-glib.c: + use dbus_gproxy_new_for_service_owner so that we can receive the + signal. + +2004-04-15 John (J5) Palmieri + + * dbus/dbus-internals.c, dbus/dbus-message-builder.c, + dbus/dbus-message.c, dbus/dbus-protocol.h + (DBUS_HEADER_FIELD_SERVICE): renamed DBUS_HEADER_FIELD_DESTINATION + + * dbus/dbus-internals.c, dbus/dbus-message-builder.c, + dbus/dbus-message.c, dbus/dbus-protocol.h + (DBUS_HEADER_FIELD_SENDER_SERVICE): renamed DBUS_HEADER_FIELD_SENDER + + * dbus/dbus-internals.c (_dbus_header_field_to_string): + DBUS_HEADER_FIELD_DESTINATION resolves to "destination" + DBUS_HEADER_FIELD_SENDER resolves to "sender" + + * doc/dbus-specification.xml (Header Fields Table): + s/SERVICE/DESTINATION + s/SENDER_SERVICE/SENDER + + +2004-04-14 Olivier Andrieu + + * test/glib/test-dbus-glib.c (timed_exit): fail the test after + a few seconds. + +2004-04-13 Michael Meeks + + * glib/dbus-gobject.c (handle_introspect): split out + (introspect_properties): this. + (handle_introspect): implement this. + + * test/glib/Makefile.am: use the absolute path so the bus + daemon's chdir ("/") doesn't kill us dead. + + * configure.in: subst ABSOLUTE_TOP_BUILDDIR + +2004-04-12 Jon Trowbridge + + * bus/config-parser.c (struct BusConfigParser): Added + included_files field. + (seen_include): Added. Checks whether or not a file has already + been included by any parent BusConfigParser. + (bus_config_parser_new): Copy the parent's included_files. + (include_file): Track which files have been included, and fail on + circular inclusions. + (process_test_valid_subdir): Changed printf to report if we are + testing valid or invalid conf files. + (all_are_equiv): Changed printf to be a bit clearer about + what we are actually doing. + (bus_config_parser_test): Test invalid configuration files. + +2004-04-09 Jon Trowbridge + + * bus/config-parser.c (bus_config_parser_new): Added a 'parent' + argument. If non-null, the newly-constructed BusConfigParser will + be initialized with the parent's BusLimits instead of the default + values. + (include_file): When including a config file, pass in + the current parser as the parent and then copy the BusLimits + from the included BusConfigParser pack to the current parser. + (process_test_valid_subdir): Renamed from process_test_subdir. + (process_test_equiv_subdir): Added. Walks through a directory, + descending into each subdirectory and loading the config files + it finds there. If any subdirectory contains two config files + that don't produce identical BusConfigParser structs, fail. + For now, the BusConfigParser's BusPolicies are not compared. + (bus_config_parser_test): Call both process_test_valid_subdir and + process_test_equiv_subdir. + + * bus/config-loader-libxml.c (bus_config_load): Take a parent + argument and pass it along to the call to bus_config_parser_new. + Also made a few small changes to allow this code to compile. + + * bus/config-loader-expat.c (bus_config_load): Take a parent + argument and pass it along to the call to bus_config_parser_new. + + * bus/bus.c (bus_context_new): Load the config file + with a NULL parent argument. + +2004-03-29 Michael Meeks + + * glib/dbus-gobject.c (introspect_properties): split + out, fix mangled 'while' flow control. + (introspect_signals): implement. + (handle_introspect): update. + +2004-03-29 Michael Meeks + + * glib/dbus-gobject.c (set_object_property): split out / + re-work, use the property type, and not the message type(!) + (get_object_property): ditto. + + * glib/dbus-gvalue.c (dbus_gvalue_demarshal), + (dbus_gvalue_marshal): make this code re-usable, needed + for signals too, also on both proxy and server side. + Re-write for more efficiency / readability. + +2004-03-29 Michael Meeks + + * dbus/dbus-message.c + (dbus_message_new_error_printf): impl. + + * dbus/dbus-connection.c + (dbus_connection_unregister_object_path): fix warning. + + * configure.in: fix no-mono-installed situation. + +2004-03-27 Havoc Pennington + + Patch from Timo Teräs: + + * tools/dbus-send.c (main): if --print-reply, assume type is + method call; support boolean type args + + * dbus/dbus-connection.c (dbus_connection_send_with_reply): fix a + bunch of memleak and logic bugs + +2004-03-23 Owen Fraser-Green + + * mono/Arguments.cs: + * mono/Introspector.cs: + * mono/Handler.cs: + * mono/InterfaceProxy.cs: + * mono/Message.cs + * mono/ProxyBuilder.cs: + * mono/Service.cs: + Added InterfaceProxy class to avoid building proxies for every + object. + + * dbus-message.h: + * dbus-message.c (dbus_message_append_args_valist) + (dbus_message_iter_get_object_path) + (dbus_message_iter_get_object_path_array) + (dbus_message_iter_append_object_path) + (dbus_message_iter_append_object_path_array): + Added object_path iter functions to handle OBJECT_PATH arguments + +2004-03-23 Owen Fraser-Green + + First checkin of mono bindings. + * configure.in: + * Makefile.am: + Build stuff for the bindings + * dbus-sharp.pc.in: Added for pkgconfig + +2004-03-21 Havoc Pennington + + * test/test-service.c (main): remove debug spew + +2004-03-21 Olivier Andrieu + + * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): accept empty + arrays + + * dbus/dbus-message.h, bus/dbus-message.c (dbus_message_iter_init) + (dbus_message_iter_init_array_iterator) + (dbus_message_iter_init_dict_iterator): return a dbus_bool_t to + indicate whether the iterator is empty + + * dbus/dbus-pending-call.c, dbus/dbus-server.c: silence compiler + warnings + +2004-03-19 Havoc Pennington + + * NEWS: 0.21 updates + + * configure.in: 0.21 + + * doc/Makefile.am: add all XMLTO usage to DBUS_XML_DOCS_ENABLED + + * python/Makefile.am: change to avoid dist of dbus_bindings.c so + you don't need pyrex to make dist + + * qt/Makefile.am (libdbus_qt_1_la_SOURCES): add integrator.h to + sources; run moc + +2004-03-18 Richard Hult + + * dbus/dbus-message.c (dbus_message_get_auto_activation) + (dbus_message_set_auto_activation): Add doxygen docs. + +2004-03-16 Richard Hult + + * bus/activation.c: (bus_activation_service_created), + (bus_activation_send_pending_auto_activation_messages), + (bus_activation_activate_service): + * bus/activation.h: + * bus/dispatch.c: (bus_dispatch), + (check_nonexistent_service_auto_activation), + (check_service_auto_activated), + (check_segfault_service_auto_activation), + (check_existent_service_auto_activation), (bus_dispatch_test): + * bus/driver.c: (bus_driver_handle_activate_service): + * bus/services.c: (bus_registry_acquire_service): + * dbus/dbus-message.c: (dbus_message_set_auto_activation), + (dbus_message_get_auto_activation): + * dbus/dbus-message.h: + * dbus/dbus-protocol.h: Implement auto-activation. + + * doc/dbus-specification.xml: Add auto-activation to the spec. + +2004-03-12 Olivier Andrieu + + * dbus/dbus-marshal.c (_dbus_marshal_get_arg_end_pos): + fix a bug with CUSTOM types. + + * dbus/dbus-message.c (message_iter_test, _dbus_message_test): add + a unit test for this bug (used to fail). + +2004-03-12 Mikael Hallendal + + * bus/activation.c: + (babysitter_watch_callback): notify all pending activations waiting for + the same exec that the activation failed. + (bus_activation_activate_service): shortcut the activation if we + already waiting for the same executable to start up. + +2004-03-12 Mikael Hallendal + + * bus/activation.c: + - Added service file reloading. + Each service files directory is kept in an hash table in + BusActivation and each BusActivationEntry knows what .service-file it + was read from. So when you try to activate a service the bus will + check if it's been updated, removed or if new .service-files has + been installed. + - Test code at the bottom for the service file reloading. + * bus/test-main.c: (main): + * bus/test.h: + - added service reloading test. + * dbus/dbus-sysdeps.c: + * dbus/dbus-sysdeps.h: (_dbus_delete_directory): Added. + +2004-03-08 Michael Meeks + + * dbus/dbus-connection.c (_dbus_connection_block_for_reply): + bail immediately if disconnected, to avoid busy loop. + + * dbus/dbus-message.c (dbus_message_iter_get_args_valist): + cleanup cut/paste/inefficiency. + +2004-03-01 David Zeuthen + + * dbus/dbus-string.c (_dbus_string_append_printf_valist): Fix a + bug where args were used twice. This bug resulted in a segfault + on a Debian/PPC system when starting the messagebus daemon. Include + dbus-sysdeps.h for DBUS_VA_COPY + + * dbus/dbus-sysdeps.h: Define DBUS_VA_COPY if neccessary. From GLib + + * configure.in: Check for va_copy; define DBUS_VA_COPY to the + appropriate va_copy implementation. From GLib + +2004-02-24 Joe Shaw + + * bus/services.c (bus_registry_acquire_service): We need to pass + in the service name to dbus_set_error() to prevent a crash. + +2003-12-26 Anders Carlsson + + * AUTHORS: Reveal my True identity. + +2003-12-17 Mikael Hallendal + + * dbus/dbus-message.c: (dbus_message_append_args_valist): + - Added case for DBUS_TYPE_BYTE, patch from Johan Hedberg. + +2003-12-13 Mikael Hallendal + + * doc/TODO: Added not about better error check of configuration files. + +2003-12-02 Richard Hult + + * Update AFL version to 2.0 throughout the source files to reflect + the update that was done a while ago. + +2003-12-02 Richard Hult + + * dbus/dbus-message.c (dbus_message_iter_append_dict): Set + wrote_dict_key to FALSE on the iter that the dict is appended to, + just like when appending other types. Fixes a bug where a dict + couldn't be put inside a dict. + (dbus_message_iter_append_dict_key): Fix typo in warning message. + (message_iter_test, _dbus_message_test): Add test case for dict + inside dict. + +2003-12-01 David Zeuthen + + * python/dbus.py: Add the actual message when calling the reciever + of a signal such that parameters can be inspected. Add the method + remove_signal_receiver + +2003-11-26 Mikael Hallendal + + * bus/*.[ch]: + * dbus/*.[ch]: + * glib/*.[ch]: Made ref functions return the pointer + +2003-11-25 Zack Rusin + + * qt/integrator.h, qt/integrator.cpp: Adding handling of DBusServer, + + * qt/server.h, qt/server.cpp, qt/Makefile.am: Adding DBusServer + wrappers, + + * qt/connection.h, qt/connection.cpp: Adjusting to changes in + the Integrator and to better fit with the server, + +2003-11-24 Zack Rusin + + * qt/connection.h, qt/connection.cpp: removing initDbus method since + the integrator handles it now + + * qt/integrator.h, qt/integrator.cpp: reworking handling of timeouts, + since QTimer wasn't really meant to be used the way DBusTimeout is + +2003-11-24 Zack Rusin + + * qt/integrator.h, qt/integrator.cpp, Makefile.am: Adding + Integrator class which integrates D-BUS with the Qt event loop, + + * qt/connection.h, qt/connection.cpp: Move all the code which + was dealing with D-BUS integration to the Integrator class, + and start using Integrator, + +2003-11-23 Zack Rusin + + * qt/connection.h, qt/connection.cpp: Adding the DBusConnection + wrapper + + * qt/message.h, qt/message.cpp: updating to the current D-BUS api, + switching namespaces to DBusQt, reworking the class, + + * Makefile.cvs: switching dependencies so that it matches KDE + schematics, + + * qt/Makefile.am: adding connection.{h,cpp} and message.{h,cpp} to + the library + +2003-11-19 Havoc Pennington + + * NEWS: update + + * configure.in: bump version to 0.20 + + * configure.in (have_qt): add yet another place to look for qt + (someone hand trolltech a .pc file...) + +2003-11-01 Havoc Pennington + + * doc/dbus-specification.xml: add state machine docs on the auth + protocol; just a first draft, I'm sure it's wrong. + +2003-10-28 David Zeuthen + + * python/dbus_bindings.pyx.in: add get_dict to handle dictionaries + return types. Fixup TYPE_* to reflect changes in dbus/dbus-protocol.h + +2003-10-28 Havoc Pennington + + * dbus/dbus-message.c (get_next_field): delete unused function + +2003-10-28 Havoc Pennington + + * bus/expirelist.c (do_expiration_with_current_time): detect + failure of the expire_func due to OOM + + * bus/connection.c (bus_pending_reply_expired): return FALSE on OOM + + * bus/dispatch.c (check_send_exit_to_service): fix to handle the + NoReply error that's now created by the bus when the service exits + +2003-10-28 Havoc Pennington + + * dbus/dbus-message.c (_dbus_message_test): enable and fix the + tests for set_path, set_interface, set_member, etc. + + * dbus/dbus-string.c (_dbus_string_insert_bytes): allow 0 bytes + + * dbus/dbus-message.c (set_string_field): always just delete and + re-append the field; accept NULL for deletion + (re_align_fields_recurse): reimplement + +2003-10-26 Havoc Pennington + + * dbus/dbus-connection.c: fix docs to properly describe the + disconnected message + (_dbus_connection_notify_disconnected): remove this function; + we can't synchronously add the disconnected message, we have to + do it after we've queued any remaining real messages + (_dbus_connection_get_dispatch_status_unlocked): queue the + disconnect message only if the transport has finished queueing all + its real messages and is disconnected. + (dbus_connection_disconnect): update the dispatch status here + +2003-10-22 Havoc Pennington + + * bus/bus.c (bus_context_check_security_policy): fix up assertion + + * bus/connection.c (bus_transaction_send_from_driver): set the + destination to the connection's base service + +2003-10-20 Havoc Pennington + + hmm, make check is currently not passing. + + * doc/dbus-specification.xml: add requirement that custom type + names follow the same rules as interface names. + + * dbus/dbus-protocol.h: change some of the byte codes, to avoid + duplication and allow 'c' to be 'custom'; dict is now 'm' for + 'map' + + * doc/dbus-specification.xml: update type codes to match + dbus-protocol.h, using the ASCII byte values. Rename type NAMED to + CUSTOM. Add type OBJECT_PATH to the spec. + +2003-10-17 Havoc Pennington + + * bus/driver.c (create_unique_client_name): use "." as separator + in base service names instead of '-' + + * dbus/dbus-string.c (_dbus_string_get_byte): allow getting nul + byte at the end of the string + + * dbus/dbus-internals.h (_DBUS_LIKELY, _DBUS_UNLIKELY): add + optimization macros since string validation seems to be a slow + point. + + * doc/dbus-specification.xml: restrict valid + service/interface/member/error names. Add test suite code for the + name validation. + + * dbus/dbus-string.c: limit service/interface/member/error names + to [0-9][A-Z][a-z]_ + + * dbus/dbus-connection.c (dbus_connection_dispatch): add missing + format arg to verbose spew + + * glib/dbus-gproxy.c (dbus_gproxy_call_no_reply): if not out of + memory, return instead of g_error + + * test/test-service.c (path_message_func): support emitting a + signal on request + + * dbus/dbus-bus.c (init_connections_unlocked): only fill in + activation bus type if DBUS_BUS_ACTIVATION was set; default to + assuming the activation bus was the session bus so that services + started manually will still register. + (init_connections_unlocked): fix so that in OOM situation we get + the same semantics when retrying the function + + * test/test-service.c (main): change to use path registration, to + test those codepaths; register with DBUS_BUS_ACTIVATION rather + than DBUS_BUS_SESSION + +2003-10-16 Havoc Pennington + + * glib/dbus-gtest-main.c: bracket with #ifdef DBUS_BUILD_TESTS + + * Makefile.am (GCOV_DIRS): remove "test", we don't care about test + coverage of the tests + (coverage-report.txt): don't move the .da and .bbg files around + +2003-10-16 Havoc Pennington + + * bus/bus.c (struct BusContext): remove struct field I didn't mean + to put there + +2003-10-16 Havoc Pennington + + * bus/connection.c (bus_pending_reply_expired): either cancel or + execute, not both + (bus_connections_check_reply): use unlink, not remove_link, as we + don't want to free the link; fixes double free mess + + * dbus/dbus-pending-call.c (dbus_pending_call_block): fix in case + where no reply was received + + * dbus/dbus-connection.c (_dbus_pending_call_complete_and_unlock): + fix a refcount leak + + * bus/signals.c (match_rule_matches): add special cases for the + bus driver, so you can match on sender/destination for it. + + * dbus/dbus-sysdeps.c (_dbus_abort): print backtrace if + DBUS_PRINT_BACKTRACE is set + + * dbus/dbus-internals.c: add pid to assertion failure messages + + * dbus/dbus-connection.c: add message type code to the debug spew + + * glib/dbus-gproxy.c (gproxy_get_match_rule): match rules want + sender=foo not service=foo + + * dbus/dbus-bus.c (dbus_bus_get): if the activation bus is the + session bus but DBUS_SESSION_BUS_ADDRESS isn't set, use + DBUS_ACTIVATION_ADDRESS instead + + * bus/activation.c: set DBUS_SESSION_BUS_ADDRESS, + DBUS_SYSTEM_BUS_ADDRESS if appropriate + + * bus/bus.c (bus_context_new): handle OOM copying bus type into + context struct + + * dbus/dbus-message.c (dbus_message_iter_get_object_path): new function + (dbus_message_iter_get_object_path_array): new function (half + finished, disabled for the moment) + + * glib/dbus-gproxy.c (dbus_gproxy_end_call): properly handle + DBUS_MESSAGE_TYPE_ERROR + + * tools/dbus-launch.c (babysit): support DBUS_DEBUG_OUTPUT to + avoid redirecting stderr to /dev/null + (babysit): close stdin if not doing the "exit_with_session" thing + + * dbus/dbus-sysdeps.c (_dbus_become_daemon): delete some leftover + debug code; change DBUS_DEBUG_OUTPUT to only enable stderr, not + stdout/stdin, so things don't get confused + + * bus/system.conf.in: fix to allow replies, I modified .conf + instead of .conf.in again. + +2003-10-14 David Zeuthen + + * python/dbus_bindings.pyx.in (MessageIter.get): fixed typo in + argtype to arg_type when raising unknown arg type exception. + Changed type list to reflect the changes in dbus-protocol.h so + the bindings actually work. + +2003-10-14 Havoc Pennington + + * test/decode-gcov.c: support gcc 3.3 also, though gcc 3.3 seems + to have a bug keeping it from outputting the .da files sometimes + (string_get_string): don't append garbage nul bytes to the string. + +2003-10-15 Seth Nickell + + * python/Makefile.am: + + Include dbus_h_wrapper.h in the dist tarball. + +2003-10-14 Havoc Pennington + + * bus/bus.c (bus_context_check_security_policy): revamp this to + work more sanely with new policy-based requested reply setup + + * bus/connection.c (bus_transaction_send_from_driver): set bus + driver messages as no reply + + * bus/policy.c (bus_client_policy_check_can_receive): handle a + requested_reply attribute on allow/deny rules + + * bus/system.conf: add + + * bus/driver.c (bus_driver_handle_message): fix check for replies + sent to the bus driver, which was backward. How did this ever work + at all though? I think I'm missing something. + + * dbus/dbus-message.c (decode_header_data): require error and + method return messages to have a reply serial field to be valid + (_dbus_message_loader_queue_messages): break up this function; + validate that reply serial and plain serial are nonzero; + clean up the OOM/error handling. + (get_uint_field): don't return -1 from this + (dbus_message_create_header): fix signed/unsigned bug + + * bus/connection.c (bus_connections_expect_reply): save serial of + the incoming message, not reply serial + +2003-10-14 Havoc Pennington + + * bus/connection.c: implement pending reply tracking using + BusExpireList + + * bus/bus.c (bus_context_check_security_policy): verify that a + reply is pending in order to allow a reply to be sent. Deny + messages of unknown type. + + * bus/dbus-daemon-1.1.in: update to mention new resource limits + + * bus/bus.c (bus_context_get_max_replies_per_connection): new + (bus_context_get_reply_timeout): new + +2003-10-13 Seth Nickell + + * python/Makefile.am: + + Pass "make distcheck": remove a couple files from DIST_FILES + that weren't included in the final version. + +2003-10-12 Havoc Pennington + + Added test code that 1) starts an actual bus daemon and 2) uses + DBusGProxy; fixed bugs that were revealed by the test. Lots + more testing possible, but this is the basic framework. + + * glib/dbus-gproxy.c (dbus_gproxy_manager_unregister): remove + empty proxy lists from the proxy list hash + + * dbus/dbus-message.c (dbus_message_iter_get_args_valist): add a + couple of return_if_fail checks + + * dbus/dbus-pending-call.c (_dbus_pending_call_new): use dbus_new0 + to allocate, so everything is cleared to NULL as it should be. + + * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): pass + source as data to dbus_connection_set_timeout_functions() as the + timeout functions expected + + * test/glib/run-test.sh: add a little script to start up a message + bus and run tests using it + + * tools/dbus-launch.1: updates + + * tools/dbus-launch.c (main): add --config-file option + + * tools/dbus-launch.c (main): remove confusing else if (runprog) + that could never be reached. + + * dbus/dbus-message.c (dbus_message_new_method_return) + (dbus_message_new_error, dbus_message_new_signal): set the + no-reply-expected flag on all these. Redundant, but may + as well be consistent. + +2003-10-11 Havoc Pennington + + * test/decode-gcov.c (function_solve_graph): make broken block + graph a nonfatal error since it seems to be broken. Need to debug + this. + + * dbus/dbus-marshal.c (_dbus_type_is_valid): new function since we + can't just check type > INVALID < LAST anymore + + * dbus/dbus-message.c (dbus_message_get_signature): new function + (dbus_message_has_signature): new function + (struct DBusMessage): add signature field (right now it isn't sent + over the wire, just generated on the fly) + (dbus_message_copy): copy the signature, and init strings to + proper length to avoid some reallocs + (dbus_message_iter_init_array_iterator): return void, since it + can't fail + (dbus_message_iter_init_dict_iterator): return void since it can't fail + (_dbus_message_loader_queue_messages): add silly temporary hack to + fill in message->signature on load + + * dbus/dbus-protocol.h: change DBUS_TYPE_* values to be ASCII + characters, so they are relatively human-readable. + +2003-10-11 Havoc Pennington + + * dbus/dbus-message.c (_dbus_message_test): add more test + coverage, but #if 0 for now since they uncover a bug + not fixed yet; I think in re_align_field_recurse() + (re_align_field_recurse): add FIXME about broken assertion + + * dbus/dbus-sysdeps.c (_dbus_sysdeps_test): add more test coverage + + * bus/connection.c: share a couple code bits with expirelist.c + + * bus/expirelist.h, bus/expirelist.c: implement a generic + expire-items-after-N-seconds facility, was going to share between + expiring connections and replies, decided not to use for expiring + connections for now. + + * COPYING: include AFL 2.0 (still need to change all the file headers) + +2003-10-09 Havoc Pennington + + * configure.in: define DBUS_HAVE_GCC33_GCOV if we have + gcc 3.3. Not that we do anything about it yet. + + * bus/signals.c (bus_match_rule_parse): impose max length on the + match rule text + + * dbus/dbus-protocol.h: add DBUS_MAXIMUM_MATCH_RULE_LENGTH + +2003-10-09 Havoc Pennington + + Make matching rules theoretically work (add parser). + + * bus/bus.c (bus_context_check_security_policy): fix up to handle + the case where destination is explicitly specified as bus driver + and someone else is eavesdropping. + + * bus/policy.c (bus_client_policy_check_can_receive): fix up + definition of eavesdropping and assertion + + * tools/dbus-send.c (main): use dbus_message_type_from_string + + * bus/signals.c (bus_match_rule_parse): implement + + * dbus/dbus-message.c (dbus_message_type_from_string): new + + * dbus/dbus-errors.h (DBUS_ERROR_MATCH_RULE_INVALID): add + +2003-10-02 Havoc Pennington + + * glib/dbus-gproxy.c (dbus_gproxy_call_no_reply): rename from + dbus_gproxy_oneway_call + + * glib/dbus-gmain.c (dbus_connection_setup_with_g_main) + (dbus_server_setup_with_g_main): fix to allow calling them more + than once on the same args + (dbus_bus_get_with_g_main): new function + +2003-10-02 Havoc Pennington + + * doc/dbus-tutorial.xml: write some stuff + +2003-09-29 Havoc Pennington + + * configure.in: split checks for Doxygen from XML docs, check for + xmlto + + * doc/Makefile.am: XML-ify all the docs, and add a blank + dbus-tutorial.xml + +2003-09-29 Havoc Pennington + + * Merge dbus-object-names branch. To see the entire patch + do cvs diff -r DBUS_OBJECT_NAMES_BRANCHPOINT -r dbus-object-names, + it's huuuuge though. + To revert, I tagged DBUS_BEFORE_OBJECT_NAMES_MERGE. + +2003-09-28 Havoc Pennington + + * HACKING: update to reflect new server + +2003-09-26 Seth Nickell + + * python/dbus.py: + * python/examples/example-signals.py: + + Start implementing some notions of signals. The API + is really terrible, but they sort of work (with the + exception of being able to filter by service, and to + transmit signals *as* a particular service). Need to + figure out how to make messages come from the service + we registered :-( + + * python/dbus_bindings.pyx.in: + + Removed duplicate message_handler callbacks. + +2003-09-25 Havoc Pennington + + * bus/session.conf.in: fix my mess + +2003-09-25 Havoc Pennington + + * bus/session.conf.in: fix security policy, reported by Seth Nickell + +2003-09-25 Seth Nickell + + * python/examples/example-service.py: + + Johan notices complete wrong code in example-service, but + completely wrong in a way that works exactly the same (!). + Johan is confused, how could this possibly work? Example + code fails to serve purpose of making things clear. + Seth fixes. + +2003-09-25 Mark McLoughlin + + * doc/dbus-specification.sgml: don't require header fields + to be 4-byte aligned and specify that fields should be + distinguished from padding by the fact that zero is not + a valid field name. + + * doc/TODO: remove re-alignment item and add item to doc + the OBJECT_PATH type. + + * dbus/dbus-message.c: + (HeaderField): rename the original member to value_offset + and introduce a name_offset member to keep track of where + the field actually begins. + (adjust_field_offsets): remove. + (append_int_field), (append_uint_field), + (append_string_field): don't align the start of the header + field to a 4-byte boundary. + (get_next_field): impl finding the next marhsalled field + after a given field. + (re_align_field_recurse): impl re-aligning a number of + already marshalled fields. + (delete_field): impl deleting a field of any type and + re-aligning any following fields. + (delete_int_or_uint_field), (delete_string_field): remove. + (set_int_field), (set_uint_field): no need to re-check + that we have the correct type for the field. + (set_string_field): ditto and impl re-aligning any + following fields. + (decode_header_data): update to take into account that + the fields aren't 4-byte aligned any more and the new + way to distinguish padding from header fields. Also, + don't exit when there is too much header padding. + (process_test_subdir): print the directory. + (_dbus_message_test): add test to make sure a following + field is re-aligned correctly after field deletion. + + * dbus/dbus-string.[ch]: + (_dbus_string_insert_bytes): rename from insert_byte and + allow the insert of multiple bytes. + (_dbus_string_test): test inserting multiple bytes. + + * dbus/dbus-marshal.c: (_dbus_marshal_set_string): add + warning note to docs about having to re-align any + marshalled values following the string. + + * dbus/dbus-message-builder.c: + (append_string_field), (_dbus_message_data_load): + don't align the header field. + + * dbus/dbus-auth.c: (process_test_subdir): print the + directory. + + * test/break-loader.c: (randomly_add_one_byte): upd. for + insert_byte change. + + * test/data/invalid-messages/bad-header-field-alignment.message: + new test case. + + * test/data/valid-messages/unknown-header-field.message: shove + a dict in the unknown field. + +2003-09-25 Seth Nickell + + * python/dbus.py: + * python/dbus_bindings.pyx.in: + + Handle return values. + + * python/examples/example-client.py: + * python/examples/example-service.py: + + Pass back return values from the service to the client. + +2003-09-24 Seth Nickell + + * python/dbus.py: + + Connect Object methods (when you are sharing an object) up... pass + in a list of methods to be shared. Sharing all the methods just + worked out too weird. You can now create nice Services over the + DBus in Python. :-) + + * python/dbus_bindings.pyx.in: + + Keep references to user_data tuples passed into C functions so + Python doesn't garbage collect on us. + + Implement MethodReturn and Error subclasses of Message for creating + DBusMessage's of those types. + + * python/examples/example-client.py: + * python/examples/example-service.py: + + Simple example code showing both how create DBus services and objects, + and how to use them. + +2003-09-23 Havoc Pennington + + * glib/dbus-gproxy.c (dbus_gproxy_manager_filter): implement + +2003-09-23 Havoc Pennington + + * glib/dbus-gproxy.c (dbus_gproxy_connect_signal): implement + (dbus_gproxy_disconnect_signal): implement + (dbus_gproxy_manager_remove_signal_match): implement + (dbus_gproxy_manager_add_signal_match): implement + (dbus_gproxy_oneway_call): implement + +2003-09-23 Havoc Pennington + + * glib/dbus-gproxy.c (struct DBusGProxy): convert to a GObject + subclass. This means dropping the transparent thread safety of the + proxy; you now need a separate proxy per-thread, or your own + locking on the proxy. Probably right anyway. + (dbus_gproxy_ref, dbus_gproxy_unref): nuke, just use g_object_ref + +2003-09-22 Havoc Pennington + + * glib/dbus-gproxy.c (dbus_gproxy_manager_get): implement + +2003-09-21 Seth Nickell + + First checkin of the Python bindings. + + * python/.cvsignore: + * python/Makefile.am: + * python/dbus_bindings.pyx.in: + * python/dbus_h_wrapper.h: + + Pieces for Pyrex to operate on, building a dbus_bindings.so + python module for low-level access to the DBus APIs. + + * python/dbus.py: + + High-level Python module for accessing DBus objects. + + * configure.in: + * Makefile.am: + + Build stuff for the python bindings. + + * acinclude.m4: + + Extra macro needed for finding the Python C header files. + +2003-09-21 Havoc Pennington + + * glib/dbus-gproxy.c (dbus_gproxy_manager_new): start + implementing the proxy manager, didn't get very far. + + * dbus/dbus-bus.c (dbus_bus_add_match): new + (dbus_bus_remove_match): new + + * glib/dbus-gproxy.c (dbus_gproxy_new_for_service): add a + path_name argument; adjust the other not-yet-implemented + gproxy constructors to be what I think they should be. + +2003-09-21 Havoc Pennington + + * dbus/dbus-bus.c (dbus_bus_get): set exit_on_disconnect to TRUE + by default for message bus connections. + + * dbus/dbus-connection.c (dbus_connection_dispatch): exit if + exit_on_disconnect flag is set and we process the disconnected + signal. + (dbus_connection_set_exit_on_disconnect): new function + +2003-09-21 Havoc Pennington + + Get matching rules mostly working in the bus; only actually + parsing the rule text remains. However, the client side of + "signal connections" hasn't been started, this patch is only the + bus side. + + * dbus/dispatch.c: fix for the matching rules changes + + * bus/driver.c (bus_driver_handle_remove_match) + (bus_driver_handle_add_match): send an ack reply from these + method calls + + * glib/dbus-gproxy.c (dbus_gproxy_begin_call): fix order of + arguments, reported by Seth Nickell + + * bus/config-parser.c (append_rule_from_element): support + eavesdrop=true|false attribute on policies so match rules + can be prevented from snooping on the system bus. + + * bus/dbus-daemon-1.1.in: consistently use terminology "sender" + and "destination" in attribute names; fix some docs bugs; + add eavesdrop=true|false attribute + + * bus/driver.c (bus_driver_handle_add_match) + (bus_driver_handle_remove_match): handle AddMatch, RemoveMatch + messages + + * dbus/dbus-protocol.h (DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST): get + rid of broadcast service concept, signals are just always broadcast + + * bus/signals.c, bus/dispatch.c, bus/connection.c, bus/bus.c: + mostly implement matching rules stuff (currently only exposed as signal + connections) + +2003-09-21 Mark McLoughlin + + * doc/dbus-specification.sgml: Change the header field name + to be an enum and update the rest of the spec to reference + the fields using the conventinal name. + + * dbus/dbus-protocol.h: update to reflect the spec. + + * doc/TODO: add item to remove the 4 byte alignment requirement. + + * dbus/dbus-message.c: Remove the code to generalise the + header/body length and serial number header fields as named + header fields so we can reference field names using the + protocol values. + (append_int_field), (append_uint_field), (append_string_field): + Append the field name as a byte rather than four chars. + (delete_int_or_uint_field), (delete_string_field): reflect the + fact that the field name and typecode now occupy 4 bytes instead + of 8. + (decode_string_field), (decode_header_data): update to reflect + protocol changes and move the field specific encoding from + decode_string_field() back into decode_header_data(). + + * dbus/dbus-internals.[ch]: (_dbus_header_field_to_string): + Add utility to aid debugging. + + * dbus/dbus-message-builder.c: + (append_string_field), (_dbus_message_data_load): Update to + reflect protocol changes; Change the FIELD_NAME directive + to HEADER_FIELD and allow it to take the field's conventional + name rather than the actual value. + + * test/data/*/*.message: Update to use HEADER_FIELD instead + of FIELD_NAME; Always align the header on an 8 byte boundary + *before* updating the header length. + +2003-09-15 Havoc Pennington + + * dbus/dbus-pending-call.c: add the get/set object data + boilerplate as for DBusConnection, etc. Use generic object data + for the notify callback. + + * glib/dbus-gparser.c (parse_node): parse child nodes + + * tools/dbus-viewer.c: more hacking on the dbus-viewer + + * glib/dbus-gutils.c (_dbus_gutils_split_path): add a file to + contain functions shared between the convenience lib and the + installed lib + + * glib/Makefile.am (libdbus_glib_1_la_LDFLAGS): add + -export-symbols-regex to the GLib library + + * dbus/dbus-object-tree.c (_dbus_object_tree_dispatch_and_unlock): + fix the locking in here, and add a default handler for + Introspect() that just returns sub-nodes. + +2003-09-14 Havoc Pennington + + * glib/dbus-gthread.c (dbus_g_thread_init): rename to make g_foo + rather than gfoo consistent + + * glib/dbus-gproxy.h: delete for now, move contents to + dbus-glib.h, because the include files don't work right since we + aren't in the dbus/ subdir. + + * glib/dbus-gproxy.c (dbus_gproxy_send): finish implementing + (dbus_gproxy_end_call): finish + (dbus_gproxy_begin_call): finish + + * glib/dbus-gmain.c (dbus_set_g_error): new + + * glib/dbus-gobject.c (handle_introspect): include information + about child nodes in the introspection + + * dbus/dbus-connection.c (dbus_connection_list_registered): new + function to help in implementation of introspection + + * dbus/dbus-object-tree.c + (_dbus_object_tree_list_registered_and_unlock): new function + +2003-09-12 Havoc Pennington + + * glib/dbus-gidl.h: add common base class for all the foo_info + types + + * tools/dbus-viewer.c: add GTK-based introspection UI thingy + similar to kdcop + + * test/Makefile.am: try test srcdir -ef . in addition to test + srcdir = ., one of them should work (yeah lame) + + * glib/Makefile.am: build the "idl" parser stuff as a convenience + library + + * glib/dbus-gparser.h: make description_load routines return + NodeInfo* not Parser* + + * Makefile.am (SUBDIRS): build test dir after all library dirs + + * configure.in: add GTK+ detection + +2003-09-07 Havoc Pennington + + * Make Doxygen contented. + +2003-09-07 Havoc Pennington + + * doc/dbus-specification.sgml: more updates + +2003-09-06 Havoc Pennington + + * doc/dbus-specification.sgml: partial updates + + * bus/dbus-daemon-1.1.in: fix the config file docs for the + zillionth time; hopefully I edited the right file this time. + + * bus/config-parser.c (append_rule_from_element): support + send_type, send_path, receive_type, receive_path + + * bus/policy.c: add message type and path to the list of things + that can be "firewalled" + +2003-09-06 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_register_fallback): add this + (dbus_connection_register_object_path): make this not handle + messages to paths below the given path + +2003-09-03 Havoc Pennington + + * test/glib/Makefile.am: add this with random glib-linked test + programs + + * glib/Makefile.am: remove the random test programs from here, + leave only the unit tests + + * glib/dbus-gobject.c (_dbus_gobject_test): add test for + uscore/javacaps conversion, and fix + (get_object_property, set_object_property): change to .NET + convention for mapping props to methods, set_FooBar/get_FooBar, + since one language has such a convention we may as well copy it. + Plus real methods in either getFooBar or get_foo_bar style won't + collide with this convention. + +2003-09-01 Havoc Pennington + + * glib/dbus-gparser.c: implement + + * glib/dbus-gobject.c: start implementing skeletons support + + * configure.in: when disabling checks/assert, also define + G_DISABLE_ASSERT and G_DISABLE_CHECKS + +2003-09-01 Havoc Pennington + + * glib/Makefile.am: rearrange a bunch of files and get "make + check" framework set up + +2003-08-31 Havoc Pennington + + * fix build with --disable-tests + +2003-08-30 Havoc Pennington + + * dbus/dbus-connection.c: purge DBusMessageHandler + + * dbus/dbus-message-handler.c: remove DBusMessageHandler, just + use callbacks everywhere + +2003-08-30 Havoc Pennington + + * test/data/valid-config-files/system.d/test.conf: change to + root for the user so warnings don't get printed + + * dbus/dbus-message.c: add dbus_message_get_path, + dbus_message_set_path + + * dbus/dbus-object-tree.c (do_test_dispatch): add test of + dispatching to a path + + * dbus/dbus-string.c (_dbus_string_validate_path): add + + * dbus/dbus-marshal.c (_dbus_demarshal_object_path): implement + (_dbus_marshal_object_path): implement + + * dbus/dbus-protocol.h (DBUS_HEADER_FIELD_PATH): new header field + to contain the path to the target object + (DBUS_HEADER_FIELD_SENDER_SERVICE): rename + DBUS_HEADER_FIELD_SENDER to explicitly say it's the sender service + +2003-08-30 Havoc Pennington + + * dbus/dbus-object-tree.c: write tests and fix the discovered bugs + +2003-08-29 Havoc Pennington + + * dbus/dbus-object-tree.c: modify to allow overlapping paths to be + registered + (struct DBusObjectSubtree): shrink this + a lot, since we may have a lot of them + (_dbus_object_tree_free_all_unlocked): implement + (_dbus_object_tree_dispatch_and_unlock): implement + +2003-08-29 Havoc Pennington + + * dbus/dbus-internals.h: fix _DBUS_N_GLOBAL_LOCKS + +2003-08-28 Havoc Pennington + + purge DBusObjectID + + * dbus/dbus-connection.c: port to no ObjectID, create a + DBusObjectTree, rename ObjectTree to ObjectPath in public API + + * dbus/dbus-connection.h (struct DBusObjectTreeVTable): delete + everything except UnregisterFunction and MessageFunction + + * dbus/dbus-marshal.c: port away from DBusObjectID, + add DBUS_TYPE_OBJECT_PATH + + * dbus/dbus-object-registry.[hc], dbus/dbus-object.[hc], + dbus/dbus-objectid.[hc]: remove these, we are moving to + path-based object IDs + +2003-08-25 Havoc Pennington + + Just noticed that dbus_message_test is hosed, I wonder when I + broke that. I thought make check was passing earlier... + + * dbus/dbus-object-tree.c: add new "object tree" to match DCOP + container tree, will replace most of dbus-object-registry + + * dbus/dbus-string.c (_dbus_string_append_printf_valist): fix C99 + screwup + +2003-08-19 Havoc Pennington + + * dbus/dbus-message.c (decode_string_field): support FIELD_SENDER + (dbus_message_is_error): fix this function + + * bus/dbus-daemon-1.1: clarify logic on when / rules + match + + * bus/policy.c (bus_client_policy_check_can_receive): fix code to + reflect clarified man page + (bus_client_policy_check_can_send): ditto + + * bus/session.conf.in: fixup + + * bus/system.conf.in: fixup + +2003-08-18 Havoc Pennington + + * dbus/dbus-hash.c (_dbus_hash_table_insert_two_strings): fix + + * dbus/dbus-message.c (_dbus_message_loader_queue_messages): fix + dumb bug created earlier (wrong order of args to + decode_header_data()) + + * tools/dbus-send.c: port + + * tools/dbus-print-message.c (print_message): port + + * test/data/*messages: port all messages over + + * dbus/dbus-message-builder.c: support including + message type + + * bus/driver.c: port over + + * bus/dispatch.c: port over to new stuff + + * dbus/dbus-connection.c (_dbus_connection_new_for_transport): + rename disconnect signal to "Disconnected" + +2003-08-17 Havoc Pennington + + This doesn't compile yet, but syncing up so I can hack on it from + work. What are branches for if not broken code? ;-) + + * dbus/dbus-protocol.h: remove DBUS_HEADER_FIELD_NAME, add + DBUS_HEADER_FIELD_INTERFACE, DBUS_HEADER_FIELD_MEMBER, + DBUS_HEADER_FIELD_ERROR_NAME + + * dbus/dbus-hash.c: Introduce DBUS_HASH_TWO_STRINGS as hack to use + for the interface+member pairs + (string_hash): change to use g_str_hash algorithm + (find_direct_function, find_string_function): refactor these to + share most code. + + * dbus/dbus-message.c: port all of this over to support + interface/member fields instead of name field + + * dbus/dbus-object-registry.c: port over + + * dbus/dbus-string.c (_dbus_string_validate_interface): rename + from _dbus_string_validate_name + + * bus/dbus-daemon-1.1: change file format for the + / stuff to match new message naming scheme + + * bus/policy.c: port over + + * bus/config-parser.c: parse new format + +2003-08-16 Havoc Pennington + + * dbus/dbus-object-registry.c (add_and_remove_objects): remove + broken assertion + + * glib/dbus-gproxy.c: some hacking + +2003-08-15 Havoc Pennington + + * dbus/dbus-pending-call.c (dbus_pending_call_block): implement + + * dbus/dbus-connection.c + (dbus_connection_send_with_reply_and_block): factor out internals; + change to convert any error replies to DBusError instead of + returning them as a message + +2003-08-15 Havoc Pennington + + * dbus/dbus-connection.c, + dbus/dbus-pending-call.c: Finish the pending call stuff + +2003-08-14 Havoc Pennington + + * dbus/dbus-pending-call.c: start on new object that will replace + DBusMessageHandler and ReplyHandlerData for tracking outstanding + replies + + * dbus/dbus-gproxy.c: start on proxy object used to communicate + with remote interfaces + + * dbus/dbus-gidl.c: do the boring boilerplate in here + +2003-08-12 Havoc Pennington + + * bus/dispatch.c (bus_dispatch): make this return proper + DBusHandlerResult to avoid DBUS_ERROR_UNKNOWN_METHOD + + * dbus/dbus-errors.c (dbus_set_error): use + _dbus_string_append_printf_valist + + * dbus/dbus-string.c (_dbus_string_append_printf_valist) + (_dbus_string_append_printf): new + + * dbus/dbus-errors.h (DBUS_ERROR_UNKNOWN_MESSAGE): change to + UNKNOWN_METHOD + + * dbus/dbus-connection.c (dbus_connection_dispatch): handle + DBUS_HANDLER_RESULT_NEED_MEMORY; send default error reply if a + message is unhandled. + +2003-08-11 Havoc Pennington + + * bus/test.c (client_disconnect_handler): change to return + HANDLED (would have been REMOVE_MESSAGE) + + * dbus/dbus-object.h (enum DBusHandlerResult): rename to + HANDLED/NOT_YET_HANDLED instead of + REMOVE_MESSAGE/ALLOW_MORE_HANDLERS to make it clearer how it + should be used. + +2003-08-10 Havoc Pennington + + * tools/dbus-send.c (main): add --type argument, for now + supporting only method_call and signal types. + + * tools/dbus-print-message.c: print message type + + * dbus/dbus-connection.c (_dbus_connection_new_for_transport): + init connection->objects + + * doc/dbus-specification.sgml: fix sgml + + * bus/*.c: port over to object-instance API changes + + * test/test-service.c: ditto + + * dbus/dbus-message.c (dbus_message_create_header): allow #NULL + name, we will have to fix up the rest of the code to also handle + this + (dbus_message_new): generic message-creation call + (set_string_field): allow appending name field + +2003-08-06 Havoc Pennington + + * dbus/dbus-object-registry.c: implement signal connection + and dispatch + + * dbus/dbus-connection.c (_dbus_connection_unref_unlocked): new + + * dbus/dbus-internals.c (_dbus_memdup): new function + +2003-08-02 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_get_no_reply) + (dbus_message_set_no_reply): add these and remove + set_is_error/get_is_error + + * dbus/dbus-protocol.h, doc/dbus-specification.sgml: + remove the ERROR flag, since there's now an ERROR type + +2003-08-01 Havoc Pennington + + * dbus/dbus-object-registry.c (_dbus_object_registry_handle_and_unlock): + implement + + * dbus/dbus-message.c (dbus_message_get_type): new function + + * doc/dbus-specification.sgml: add "type" byte to messages + +2003-08-01 Havoc Pennington + + * dbus/dbus-protocol.h (DBUS_MESSAGE_TYPE_*): introduce + a message type enum to distinguish kinds of message + (DBUS_HEADER_FLAG_NO_REPLY_EXPECTED): flag for a message + that need not be replied to + +2003-08-01 Havoc Pennington + + * dbus/dbus-marshal.c: adapt to DBusObjectID changes + (unpack_8_octets): fix no-64-bit-int bug + + * dbus/dbus-object-registry.c (validate_id): validate the + connection ID bits, not just the instance ID. + + * dbus/dbus-connection.c (_dbus_connection_init_id): initialize + the connection-global 33 bits of the object ID + + * dbus/dbus-object-registry.c (info_from_entry): fill in + object ID in the new way + + * dbus/dbus-objectid.h: rather than high/low bits, specifically + define server/client/instance bits. + +2003-07-30 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_register_object): fix + build + +2003-07-13 Havoc Pennington + + * dbus/dbus-object.h (struct DBusObjectVTable): add padding + fields to DBusObjectVTable and DBusObjectInfo + +2003-07-12 Havoc Pennington + + * dbus/dbus-object-registry.c: implement unit test, + fix bugs discovered in process + + * dbus/dbus-connection.c: remove handler_table and + register_handler(), add DBusObjectRegistry usage + + * dbus/dbus-objectid.c (dbus_object_id_is_null) + (dbus_object_id_set_null): new functions + +2003-07-08 Havoc Pennington + + * dbus/dbus-object.c: implement some of this + + * dbus/dbus-object-registry.c + (_dbus_object_registry_add_and_unlock): fill in the object_id out + param + (_dbus_object_registry_new): handle OOM + +2003-07-08 Havoc Pennington + + * dbus/dbus-object.h: sketch out an API for registering objects + with a connection, that allows us to use as little as 24 bytes + per object and lets application code represent an object in + any conceivable way. + + * dbus/dbus-object-registry.c: implement the hard bits of the + DBusConnection aspect of object API. Not yet wired up. + +2003-07-06 Havoc Pennington + + * dbus/dbus-marshal.c (_dbus_marshal_set_object_id): new function + (_dbus_marshal_object_id): new + (_dbus_demarshal_object_id): new + (_dbus_marshal_get_arg_end_pos): support object ID type, and + consolidate identical switch cases. Don't conditionalize handling + of DBUS_TYPE_UINT64, need to handle the type always. + (_dbus_marshal_validate_arg): consolidate identical cases, and + handle DBUS_TYPE_OBJECT_ID + + * dbus/dbus-objectid.c: new file with DBusObjectID data type. + + * dbus/dbus-protocol.h: add DBUS_TYPE_OBJECT_ID + +2003-09-28 Havoc Pennington + + * real 0.13 release + +2003-09-28 Havoc Pennington + + * doc/Makefile.am (dbus-specification.html): testing a funky hack + to work with Debian db2html + +2003-09-28 Havoc Pennington + + * configure.in: 0.13 + + * doc/Makefile.am (dbus-test-plan.html): accept nonexistence of + stylesheet-images for benefit of Debian + + Change back to using filesystem-linked sockets for the system + bus, so only root can create the default system bus address. + + * bus/system.conf.in: change to use + DBUS_SYSTEM_BUS_DEFAULT_ADDRESS + + * dbus/Makefile.am (INCLUDES): remove DBUS_SYSTEM_BUS_PATH define + from here. + + * configure.in: define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS + here, and AC_DEFINE DBUS_SYSTEM_PATH + +2003-08-09 Anders Carlsson + + * doc/TODO: + * doc/busconfig.dtd: + Add busconfig DTD. + +2003-08-09 Anders Carlsson + + * doc/dbus-specification.sgml: + Add activation reply values. + +2003-08-05 Havoc Pennington + + * configure.in: 0.12 + +2003-08-05 Anders Carlsson + + * glib/dbus-gmain.c: (watch_fd_new), (watch_fd_ref), + (watch_fd_unref), (dbus_gsource_check), (dbus_gsource_dispatch), + (add_watch), (remove_watch), (create_source): + Refcount fds, fixes some reentrancy issues. + +2003-07-30 Havoc Pennington + + * dbus/dbus-bus.c (init_connections_unlocked): fix default system + bus address to be abstract if we have abstract sockets + + * NEWS: update + +2003-07-28 Havoc Pennington + + * bus/messagebus.in: fix to avoid processname/servicename + confusion, from Michael Kearey + https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=100965 + +2003-07-23 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_iter_get_named): + fix from Andy Hanton to remove broken "+1" + +2003-07-16 Havoc Pennington + + * tools/dbus-launch.c (babysit): close stdout/stderr in the + babysitter process, as suggested by Thomas Leonard, so + an "eval `dbus-launch --exit-with-session`" will actually + return + +2003-07-16 Havoc Pennington + + * configure.in: print out EXPANDED_* variables in the summary at + the end; clean up the code that computes EXPANDED_ variables and + get the ones using exec_prefix right. Should make things work + when you build without --prefix + +2003-06-29 Havoc Pennington + + * mono/Test.cs (class Test): fire up a main loop and run it + + * mono/DBus.cs (DBus): don't g_thread_init since it can only be + done once, the app has to do it + +2003-06-26 Havoc Pennington + + * mono/Connection.cs: set up connection with the glib main loop + +2003-07-01 Havoc Pennington + + * doc/dbus-specification.sgml: clarify the format of a type code, + change suggested by Jim Blandy + +2003-06-29 Miloslav Trmac + + * doc/Makefile.am: + * tools/Makefile.am: Don't assume srcdir == builddir. + + * dbus/dbus-memory.c (dbus_realloc): Don't check guards after shrinking + the allocated block. + (_dbus_memory_test): New function. + * dbus/dbus-test.h: Add _dbus_memory_test (). + * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): Call it. + + * dbus/dbus-message.c (decode_header_data): Use %.4s instead + of %c%c%c%c. + (dbus_message_new): Remove obsolete @todo. + + * dbus/dbus-marshal.c (_dbus_marshal_set_int64) + (_dbus_marshal_set_uint64): Fix comment. + + * dbus/dbus-message.c (append_int_field, append_uint_field): Don't + hardcode FIELD_REPLY_SERIAL. + + * dbus/dbus-mainloop.c (_dbus_loop_remove_watch) + (_dbus_loop_remove_timeout): Cast function pointers to (void *) for %p + + * configure.in: Add -D_POSIX_C_SOURCE=199309L -DBSD_SOURCE to CFLAGS + and disable DBUS_USE_ATOMIC_INT_486 when --enable-ansi is used + +2003-06-24 Havoc Pennington + + * mono/*.cs: Use IntPtr.Zero instead of ((IntPtr) 0) + +2003-06-23 Anders Carlsson + + * configure.in: + * gcj/.cvsignore: + * gcj/Hello.java: + * gcj/Makefile.am: + * gcj/TestMessage.java: (TestMessage), (TestMessage.main): + * gcj/org/.cvsignore: + * gcj/org/Makefile.am: + * gcj/org/freedesktop/.cvsignore: + * gcj/org/freedesktop/Makefile.am: + * gcj/org/freedesktop/dbus/.cvsignore: + * gcj/org/freedesktop/dbus/Makefile.am: + * gcj/org/freedesktop/dbus/Message.java: (Message), + (Message.Message): + * gcj/org/freedesktop/dbus/natMessage.cc: + Fix the build system. + +2003-06-22 Havoc Pennington + + * mono/Connection.cs: add more bindings + + * dbus/dbus-threads.c (dbus_threads_init): allow calling this + more than once. + +2003-06-22 Havoc Pennington + + * mono/Connection.cs, mono/DBus.cs, mono/Error.cs: + Start wrapping more stuff. + +2003-06-22 Havoc Pennington + + * mono/Message.cs: implement Message.Wrap() that ensures we only + have a single C# wrapper per DBusMessage, assuming it works which + it probably doesn't. + + * dbus/dbus-message.c (dbus_message_allocate_data_slot): new + (dbus_message_free_data_slot): new + (dbus_message_set_data): new + (dbus_message_get_data): new + +2003-06-22 Havoc Pennington + + * dbus/dbus-dataslot.c (_dbus_data_slot_allocator_unref) + (_dbus_data_slot_allocator_alloc): rework these to keep a + reference count on each slot and automatically manage a global + slot ID variable passed in by address + + * bus/bus.c: convert to new dataslot API + + * dbus/dbus-bus.c: convert to new dataslot API + + * dbus/dbus-connection.c: convert to new dataslot API + + * dbus/dbus-server.c: convert to new dataslot API + + * glib/dbus-gmain.c: ditto + + * bus/test.c: ditto + + * bus/connection.c: ditto + +2003-06-22 Anders Carlsson + + * configure.in: Add AM_PROG_GCJ and move AM_PROG_LIBTOOL + after the gcj checks so that the correct configuration tags + will be added to libtool. + + * dbus-glib-1.pc.in: No need to specify any includes since + dbus-1.pc.in has those. + +2003-06-22 Havoc Pennington + + * mono/*, gcj/*, configure.in, Makefile.am: + Check in makefiles and subdirs for mono and gcj bindings. + Neither binding actually exists, just trying to get through + all the build and other boring bits. + +2003-06-21 Philip Blundell + + * tools/dbus-monitor.1: Updated. + + * tools/dbus-send.1: Likewise. + +2003-06-20 Anders Carlsson + + * dbus/dbus-transport-unix.c (unix_handle_watch): Check + for hangup and error after checking read so we won't discard + pending data if both hangup and read are set. + +2003-06-19 Philip Blundell + + * tools/dbus-print-message.c (print_message): Handle BOOLEAN. + + * tools/dbus-send.c: Accept both --system and --session. + + * tools/dbus-monitor.c: Same here. + +2003-06-19 Anders Carlsson + + * glib/dbus-glib.h: Fix so that dbus-glib.h can be used + from C++ (Patch by Miloslav Trmac). + +2003-06-15 Joe Shaw + + * configure.in: Check for socklen_t. + + * dbus/dbus-sysdeps.c: Define socklen_t if it's not defined. + + * test/test-segfault.c: Add #include + + * tools/Makefile.am: Add DBUS_X_CFLAGS to the INCLUDES since + dbus-launch needs it. + +2003-06-09 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_listen_unix_socket): don't use + SUN_LEN, it breaks abstract socket usage + + * dbus/dbus-internals.c (_dbus_verbose_real): only print PID at + starts of lines. + +2003-06-04 Havoc Pennington + + * dbus/dbus-server.c (dbus_server_listen): allow abstract sockets + using unix:abstract=/foo, and when listening in a tmpdir + i.e. unix:tmpdir=/tmp, always use abstract sockets if we can. + + * dbus/dbus-transport.c (_dbus_transport_open): support + unix:abstract=/foo + + * dbus/dbus-server-unix.c (_dbus_server_new_for_domain_socket): + support abstract sockets + + * dbus/dbus-transport-unix.c + (_dbus_transport_new_for_domain_socket): support abstract sockets + + * dbus/dbus-sysdeps.c (_dbus_connect_unix_socket): add "abstract" + toggle as an argument, implement abstract namespace support + (_dbus_listen_unix_socket): ditto + + * configure.in: add --enable-abstract-sockets and implement + a configure check for autodetection of the right value. + +2003-06-01 Havoc Pennington + + * tools/dbus-cleanup-sockets.c: add utility to clean up sockets + in /tmp (though on Linux this will end up being useless, + when we add abstract namespace support) + + * configure.in: define DBUS_SESSION_SOCKET_DIR in addition to + subst'ing it + +2003-05-28 Colin Walters + + * tools/dbus-monitor.c (main): Fix silly typo (s/--session/--system/). + +2003-05-18 Anders Carlsson + + * dbus/dbus-message.c (dbus_message_new): Remove @todo. + +2003-05-17 Colin Walters + + * tools/dbus-send.c: Don't exit with an error code if --help was + passed. Default to using the session bus instead of the system + one. + + * tools/dbus-launch.c: Ditto. + + * tools/dbus-monitor.c: Ditto. + + * tools/dbus-send.1: Update with new arguments. + + * tools/dbus-launch.c: Emit code to export variables. New + arguments -s and -c to specify shell syntax, and a bit of code to + autodetect syntax. Also, allow specifying a program to run. + + * tools/dbus-launch.1: Update with new arguments. + + * tools/dbus-send.1: Ditto. + + * tools/dbus-monitor.1: Ditto. + +2003-05-17 Havoc Pennington + + * bus/config-parser.c (merge_included): merge in policies from + child configuration file. + + * bus/policy.c (bus_policy_merge): function to merge two policies + together + +2003-05-16 Havoc Pennington + + * dbus/dbus-connection.c: disable verbose lock spew + + * tools/dbus-send.c: add --print-reply command line option + + * tools/dbus-print-message.h (print_message): new util function + shared by dbus-send and dbus-monitor + + * tools/dbus-monitor.c (handler_func): exit on disconnect + + * dbus/dbus-transport-unix.c (do_reading): if the transport is + disconnected, don't try to use the read_watch + + * dbus/dbus-watch.c (dbus_watch_get_enabled): assert watch != NULL + so we can find this bug more easily + +2003-05-16 Havoc Pennington + + * bus/policy.c (free_rule_list_func): avoid a crash when passed + NULL as DBusHashTable is annoyingly likely to do. + +2003-05-16 Colin Walters + + * tools/dbus-monitor.c: Add --session argument and usage() + function. + + * tools/dbus-monitor.1: Update with new --session arg. + + * bus/Makefile.am (install-data-hook): Create + $(libdir)/dbus-1.0/services so that the session bus is happy. + +2003-05-15 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_atomic_dec, _dbus_atomic_inc): work + on non-x86. ifdef's are evil. + +2003-05-15 Havoc Pennington + + * configure.in: 0.11 + + * NEWS: update + + * bus/Makefile.am (initddir): apparently we are supposed to put + init scripts in /etc/rc.d/init.d not /etc/init.d + + * bus/Makefile.am: remove the "you must --enable-tests to make + check" as it broke distcheck + + * bus/Makefile.am (install-data-hook): create /etc/dbus-1/system.d + +2003-05-13 James Willcox + + * configure.in: + * bus/activation.c: (bus_activation_service_created), + (bus_activation_activate_service): + * bus/driver.c: (bus_driver_send_service_deleted), + (bus_driver_send_service_created), (bus_driver_send_service_lost), + (bus_driver_send_service_acquired), + (bus_driver_send_welcome_message), + (bus_driver_handle_list_services): + * bus/session.conf.in: + * dbus/dbus-bus.c: (dbus_bus_acquire_service), + (dbus_bus_service_exists), (dbus_bus_activate_service): + * dbus/dbus-bus.h: + + Add some convenience API which lets you activate a service, and did a + bunch of s/0/DBUS_TYPE_INVALID/ in calls to dbus_message_append_args() + and dbus_message_get_args() + +2003-05-11 Havoc Pennington + + * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): fix to avoid + calling _dbus_marshal_validate_arg() for every byte in a byte + array, etc. + + * dbus/dbus-message-handler.c: use atomic reference counting to + reduce number of locks slightly; the global lock in here sucks + + * dbus/dbus-connection.c + (_dbus_connection_update_dispatch_status_and_unlock): variant of + update_dispatch_status that can be called with lock held; then use + in a couple places to reduce locking/unlocking + (dbus_connection_send): hold the lock over the whole function + instead of acquiring it twice. + + * dbus/dbus-timeout.c (_dbus_timeout_new): handle OOM + + * bus/connection.c (bus_connections_setup_connection): fix access + to already-freed memory. + + * dbus/dbus-connection.c: keep a little cache of linked list + nodes, to avoid using the global linked list alloc lock in the + normal send-message case. Instead we just use the connection lock + that we already have to take. + + * dbus/dbus-list.c (_dbus_list_find_last): new function + + * dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec): + change to use a struct for the atomic type; fix docs, + they return value before increment, not after increment. + + * dbus/dbus-string.c (_dbus_string_append_4_aligned) + (_dbus_string_append_8_aligned): new functions to try to + microoptimize this operation. + (reallocate_for_length): break this out of set_length(), to + improve profile info, and also so we can consider inlining the + set_length() part. + + * dbus/dbus-message.c (dbus_message_new_empty_header): init data + strings with some preallocation, cuts down on our calls to realloc + a fair bit. Though if we can get the "move entire string to empty + string" optimization below to kick in here, it would be better. + + * dbus/dbus-string.c (_dbus_string_move): just call + _dbus_string_move_len + (_dbus_string_move_len): add a special case for moving + an entire string into an empty string; we can just + swap the string data instead of doing any reallocs. + (_dbus_string_init_preallocated): new function + +2003-05-11 Havoc Pennington + + Write a "test-profile" that does echo client-server with threads; + profile reveals lock contention, memcpy/realloc of buffers, and + UTF-8 validation as hot spots. 20% of lock contention eliminated + with dbus_atomic_inc/dec implementation on x86. Much remaining + contention is global mempool locks for GList and DBusList. + + * dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec): add + x86 implementation + + * dbus/dbus-connection.c (struct DBusConnection): use + dbus_atomic_t for the reference count + + * dbus/dbus-message.c (struct DBusMessage): declare + dbus_atomic_t values as volatile + + * configure.in: code to detect ability to use atomic integer + operations in assembly, from GLib patch + + * dbus/dbus-internals.c (_dbus_verbose_real): call getpid every + time, tired of it being wrong in threads and forked processes + + * glib/test-profile.c: a little program to bounce messages back + and forth between threads and eat CPU + + * dbus/dbus-connection.c: add debug spew macros for debugging + thread locks; include config.h at top; fix deadlock in + dbus_connection_flush() + +2003-05-08 Havoc Pennington + + * dbus/dbus-spawn.c: s/_exit/exit/ because it was keeping gcov + data from getting written, and there wasn't a good reason to + use _exit really. + + * test/decode-gcov.c (mark_inside_dbus_build_tests): don't count + dbus_verbose lines in test coverage + (main): add list of functions sorted by # of untested blocks + to the coverage report + + * dbus/dbus-mempool.c: put some test-only code in DBUS_BUILD_TESTS + + * dbus/dbus-marshal.c (_dbus_marshal_test): extend test coverage + + * dbus/dbus-message-handler.c (_dbus_message_handler_test): + extend test coverage + + * test/data/auth/cancel.auth-script: test canceling an + authentication + + * dbus/Makefile.am: remove dbus-server-debug.[hc] for now, as they + aren't used. in CVS history if we end up needing them. + +2003-05-04 Havoc Pennington + + * dbus/dbus-message-handler.c (_dbus_message_handler_test): add + unit test + + * dbus/dbus-marshal.c (_dbus_demarshal_string_array): fix this + function, which assumed length was in # of strings, not bytes + + * dbus/dbus-message.c (_dbus_message_test): add tests for some + missing coverage + + * dbus/dbus-connection.c + (_dbus_connection_queue_received_message): disable function for + now, we are only using it in test mode + + * dbus/dbus-message.c (_dbus_message_loader_queue_messages): + remove a mistaken FIXME + +2003-05-04 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_preallocate_send): + unlock mutex on successful return, patch from Anders Gustafsson + +2003-05-04 Havoc Pennington + + * dbus-glib-1.pc.in (Requires): fix dependencies, from + Anders Gustafsson + +2003-05-04 Havoc Pennington + + * tools/dbus-launch.c: implement + + * bus/main.c (main), bus/bus.c (bus_context_new): + implement --print-pid and --fork + +2003-05-03 Havoc Pennington + + * dbus/dbus-address.c (dbus_parse_address): fix bug when a key in + the address had no value, and add to test suite. Fix and + regression test from Miloslav Trmac + +2003-05-03 Havoc Pennington + + * dbus/dbus-watch.c (dbus_watch_handle): warn and return if a + watch is invalid when handled + + * tools/Makefile.am, tools/dbus-launch.c, tools/dbus-launch.1: add + dbus-launch utility to launch the bus from a shell script. Didn't + actually implement dbus-launch yet, it's just a placeholder still. + +2003-05-03 Havoc Pennington + + * bus/Makefile.am, bus/dbus-daemon-1.1.in: man page for the + daemon; also documents daemon config file, so replaces + doc/config-file.txt. Corrected some stuff from config-file.txt in + the process of moving it. + +2003-05-03 Havoc Pennington + + * tools/Makefile.am, tools/dbus-send.1, tools/dbus-monitor.1: + add some man pages + +2003-05-03 Colin Walters + + * dbus/dbus-sysdeps.c (fill_user_info): Test against + DBUS_UID_UNSET to determine whether to do a uid lookup or not. + + * Makefile.am: Update to use new .pc versioning scheme. + +2003-05-02 Havoc Pennington + + * bus/system.conf.in: allow send/receive to/from message bus + service + +2003-04-30 Havoc Pennington + + * configure.in: print a note when building with unit tests and + without assertions + +2003-04-30 Havoc Pennington + + * Makefile.am: add a check-local that complains if you didn't + configure with --enable-tests + +2003-04-29 Havoc Pennington + + * glib/dbus-gmain.c: docs cleanups + + * dbus/dbus-types.h: add docs on int64 types + + * dbus/dbus-memory.c: fix docs to avoid putting private API in + public API docs section + +2003-04-29 Havoc Pennington + + * dbus-1.pc.in, dbus-glib-1.pc.in: rename these from + dbus-1.0.pc.in, dbus-glib-1.0.pc.in. As these change with the + parallel install API version, not with the D-BUS package version. + + * HACKING: move some of README over here + + * README: updates, and document API/ABI policy + + * configure.in: reindentation + +2003-04-29 Havoc Pennington + + * dbus/dbus.h: add "you have to define DBUS_API_SUBJECT_TO_CHANGE + to use this library" to be sure people have the right + expectations. + +2003-04-28 Havoc Pennington + + * configure.in: add --enable-docs which by default is auto yes if + doxygen and db2html found, no otherwise; but can be forced on/off + + * doc/Makefile.am: conditionalize whether to build docs on + --enable-docs + +2003-04-28 Havoc Pennington + + * configure.in: 0.10 + + * NEWS: update + + * bus/system.conf.in: add system.d + + * dbus/dbus-userdb.c (_dbus_user_database_lookup): fix bug when + username was provided but not uid + + * bus/config-parser.c (struct BusConfigParser): keep track of + whether the parser is toplevel or was included; change some + of the error handling if it's included. + +2003-04-27 Havoc Pennington + + Unbreak my code... + + * dbus/dbus-transport.c (_dbus_transport_get_dispatch_status): + report correct status if we finish processing authentication + inside this function. + + * bus/activation.c (try_send_activation_failure): use + bus_transaction_send_error_reply + + * bus/connection.c (bus_connection_get_groups): return an error + explaining the problem + + * bus/bus.c (bus_context_check_security_policy): implement + restriction here that inactive connections can only send the + hello message. Also, allow bus driver to send anything to + any recipient. + + * bus/connection.c (bus_connection_complete): create the + BusClientPolicy here instead of on-demand. + (bus_connection_get_policy): don't return an error + + * dbus/dbus-message.c (dbus_message_new_error_reply): allow NULL + sender field in message being replied to + + * bus/bus.c (bus_context_check_security_policy): fix silly typo + causing it to return FALSE always + + * bus/policy.c (bus_client_policy_check_can_send): fix bug where + we checked sender rather than destination + +2003-04-25 Havoc Pennington + + test suite is slightly hosed at the moment, will fix soon + + * bus/connection.c (bus_connections_expire_incomplete): fix to + properly disable the timeout when required + (bus_connection_set_name): check whether we can remove incomplete + connections timeout after we complete each connection. + + * dbus/dbus-mainloop.c (check_timeout): fix this up a bit, + probably still broken. + + * bus/services.c (bus_registry_acquire_service): implement max + number of services owned, and honor allow/deny rules on which + services a connection can own. + + * bus/connection.c (bus_connection_get_policy): report errors here + + * bus/activation.c: implement limit on number of pending + activations + +2003-04-25 Havoc Pennington + + * dbus/dbus-transport.c (_dbus_transport_get_unix_user): fix bug + where we used >= 0 instead of != DBUS_UID_UNSET. + +2003-04-25 Havoc Pennington + + * glib/dbus-gmain.c (remove_watch): fix for a crash when watches + were toggled without add/remove, fix from Anders Gustafsson + +2003-04-24 Havoc Pennington + + * test/data/valid-config-files/basic.conf: add tags to + this test + + * bus/config-parser.h, bus/config-parser.c, bus/bus.c: Implement + tag in configuration file. + +2003-04-24 Havoc Pennington + + * bus/dispatch.c: somehow missed some name_is + + * dbus/dbus-timeout.c (_dbus_timeout_set_enabled) + (_dbus_timeout_set_interval): new + + * bus/connection.c (bus_connections_setup_connection): record time + when each connection is first set up, and expire them after the + auth timeout passes. + +2003-04-24 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_name_is): rename + (dbus_message_service_is): rename + (dbus_message_sender_is): rename + (dbus_message_get_service): rename + +2003-04-24 Havoc Pennington + + * configure.in: add --enable-checks + + * dbus/dbus-message.c (dbus_message_new): reverse name/service arguments + + * dbus/dbus-connection.c (dbus_connection_preallocate_send): fix + to use thread locks. + (_dbus_connection_handler_destroyed_locked): move some private + functions into proper docs group + + * dbus/dbus-internals.h: add _dbus_return_if_fail, + _dbus_return_val_if_fail + + Throughout: use dbus_return_if_fail + +2003-04-23 James Willcox + + * glib/dbus-glib.h: + * glib/dbus-gmain.c: (add_timeout), (wakeup_main), (create_source), + (dbus_connection_setup_with_g_main), + (dbus_server_setup_with_g_main): + * glib/test-dbus-glib.c: (main): + * glib/test-thread-client.c: (main): + * glib/test-thread-server.c: (new_connection_callback), (main): + * tools/dbus-monitor.c: (main): + + Added a GMainContext argument to dbus_connection_setup_with_g_main() + and dbus_server_setup_with_g_main(). + +2003-04-20 Havoc Pennington + + * doc/dbus-specification.sgml: document the restrictions on + message and service names + +2003-04-22 Havoc Pennington + + * dbus/dbus-message.c, dbus/dbus-marshal.c: add 64-bit integer + support, and do some code cleanups to share more code and + speed up array marshal/demarshal. + + * dbus-1.0.pc.in (Cflags): put libdir include file in cflags + + * configure.in: generate dbus-arch-deps.h + + * dbus/dbus-protocol.h (DBUS_TYPE_INT64, DBUS_TYPE_UINT64): add + 64-bit typecodes + +2003-04-22 Havoc Pennington + + * test/data/valid-messages/opposite-endian.message: fix test + to use proper type for rply field + + * test/data/invalid-messages: add tests for below validation + + * dbus/dbus-message.c (decode_header_data): validate field types, + and validate that named fields are valid names + (decode_name_field): consider messages in the + org.freedesktop.Local. namespace to be invalid. + + * dbus/dbus-string.c (_dbus_string_validate_name): new + +2003-04-19 Havoc Pennington + + * bus/driver.c (bus_driver_handle_hello): check limits and + return an error if they are exceeded. + + * bus/connection.c: maintain separate lists of active and inactive + connections, and a count of each. Maintain count of completed + connections per user. Implement code to check connection limits. + + * dbus/dbus-list.c (_dbus_list_unlink): export + + * bus/bus.c (bus_context_check_security_policy): enforce a maximum + number of bytes in the message queue for a connection + +2003-04-18 Havoc Pennington + + * dbus/dbus-auth.c (record_mechanisms): memleak fixes + + * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): fix some + memleaks + + * dbus/dbus-keyring.c (add_new_key): fix a memleak, and + on realloc be sure to update the pointer in the keyring + + * dbus/dbus-string.c (_dbus_string_zero): compensate for align + offset to avoid writing to unallocated memory + + * dbus/dbus-auth.c (process_rejected): return FALSE if we fail to + try the next mechanism, so we properly handle OOM + + * dbus/dbus-keyring.c (_dbus_keyring_new_homedir): fix double-free + on OOM. + (_dbus_keyring_new): fix OOM bug + (_dbus_keyring_new_homedir): always set error; impose a maximum + number of keys we'll load from the file, mostly to speed up the + test suite and make its OOM checks more useful, but also for + general sanity. + + * dbus/dbus-auth.c (process_error_server): reject authentication + if we get an error from the client + (process_cancel): on cancel, send REJECTED, per the spec + (process_error_client): send CANCEL if we get an error from the + server. + +2003-04-18 Havoc Pennington + + * dbus/dbus-mainloop.c (_dbus_loop_iterate): fix UMR in verbose + debug spew + + * dbus/dbus-auth.c (handle_client_data_cookie_sha1_mech): fix OOM + handling problem + + * dbus/dbus-keyring.c (_dbus_keyring_new_homedir): only whine + about DBUS_TEST_HOMEDIR once + + * bus/Makefile.am (TESTS_ENVIRONMENT): put DBUS_TEST_HOMEDIR in + the environment + + * bus/dispatch.c (bus_dispatch_sha1_test): actually load sha1 + config file so we test the right thing + + Throughout: assorted docs improvements + +2003-04-18 Havoc Pennington + + * glib/dbus-gmain.c: adapt to watch changes + + * bus/bus.c, bus/activation.c, etc.: adjust to watch changes + + * dbus/dbus-server.h: remove dbus_server_handle_watch + + * dbus/dbus-connection.h: remove dbus_connection_handle_watch + + * dbus/dbus-watch.c (dbus_watch_handle): change DBusWatch to work + like DBusTimeout, so we don't need dbus_connection_handle_watch + etc. + +2003-04-17 Havoc Pennington + + * dbus/dbus-userdb.c, dbus/dbus-sysdeps.c: redo all the passwd + database usage so it all goes via the DBusUserDatabase cache. + +2003-04-17 Havoc Pennington + + * dbus/dbus-mainloop.c (_dbus_loop_iterate): fix logic so that if + there was an OOM watch we skipped, we always return TRUE so we + iterate again to have a look at it again. Fixes test suite hang. + Code rearrangement also lets us lose some memset and only iterate + over callbacks once. + + * bus/driver.c (bus_driver_handle_message): sense of test for + reply was backward + +2003-04-16 Havoc Pennington + + * doc/dbus-specification.sgml: make spec say serials are unsigned + + * dbus/dbus-message.h: change message serials to unsigned + + * dbus/dbus-connection.c: adapt to message serials being unsigned + +2003-04-15 Havoc Pennington + + * bus/bus.c: create and keep around a shared DBusUserDatabase + object. + + * bus/connection.c (bus_connection_get_groups): don't cache + groups for user in the connection object, since user database + object now does that. + +2003-04-16 Havoc Pennington + + * dbus/dbus-message.c (_dbus_message_add_size_counter): keep a + list of size counters + (_dbus_message_loader_putback_message_link): put back a popped link + + * dbus/dbus-connection.c + (dbus_connection_set_max_live_messages_size): rename + max_received_size + (dbus_connection_get_outgoing_size): get size of outgoing + queue + (_dbus_connection_set_connection_counter): remove this cruft + +2003-04-14 Havoc Pennington + + * dbus/dbus-userdb.c: user database abstraction, mostly to get + caching, but at some point we might want to be able to use a + different database. + + * bus/dispatch.c (bus_dispatch_sha1_test): add a test that uses + SHA1 conf file to test the sha1 auth mechanism, since the regular + test always uses EXTERNAL when available. + + * configure.in, + test/data/valid-config-files/debug-allow-all-sha1.conf.in: + add conf file that requires use of sha1 auth + +2003-04-13 Havoc Pennington + + * tools/dbus-send.c, tools/dbus-monitor.c: two utility programs + from Philip Blundell to send messages and monitor them. + +2003-04-13 Havoc Pennington + + * dbus/dbus-mainloop.c: fix some reentrancy issues by refcounting + callbacks + + * test/data/valid-config-files/debug-allow-all.conf.in: allow all + users + + * dbus/dbus-transport.c (_dbus_transport_get_dispatch_status): + fix to only recover unused bytes if we're already authenticated + (_dbus_transport_get_is_authenticated): fix to still mark us + authenticated if there are unused bytes. + + * bus/dispatch.c: implement security policy checking + + * bus/connection.c (bus_transaction_send_from_driver): new + + * bus/bus.c (bus_context_check_security_policy): new + + * bus/dispatch.c (send_service_nonexistent_error): delete this, + now we just set the DBusError and it gets converted to an error + reply. + + * bus/connection.c (allow_user_function): enable code using actual + data from the config file + + * bus/policy.c (list_allows_user): handle wildcard rules for + user/group connection perms + +2003-04-13 Havoc Pennington + + * bus/config-parser.c: Load up the BusPolicy and BusPolicyRules + + * dbus/dbus-sysdeps.c (_dbus_get_user_id): new function + + * bus/policy.c (bus_policy_append_mandatory_rule) + (bus_policy_append_default_rule, bus_policy_append_user_rule) + (bus_policy_append_group_rule): new functions + +2003-04-12 Havoc Pennington + + * bus/config-parser.c (bus_config_parser_new): fix a memleak + + * dbus/dbus-sysdeps.c: change DBusCredentials to use longs for + the pid/gid/uid, just for paranoia. + + * test/break-loader.c (randomly_do_n_things): find a byte + containing a type code, and randomly change it to a different + type code. + +2003-04-12 Havoc Pennington + + * bus/policy.h: change BusPolicy to be the thing from the config + file, and rename old BusPolicy to BusClientPolicy + + * bus/bus.c, bus/connection.c, bus/config-parser.c: change to + match change in how policy works + + * dbus/dbus-internals.h: mark assert_not_reached as + __attribute((noreturn))__ + +2003-04-11 Havoc Pennington + + * doc/dbus-specification.sgml: fix a spot with the wrong name for + the broadcast service. Use boolean return for ServiceExists. + +2003-04-11 Havoc Pennington + + * configure.in: add another directory to look for qt in. + +2003-04-11 Havoc Pennington + + * AUTHORS: add Colin Walters + +2003-04-11 Havoc Pennington + + * NEWS: update + + * configure.in: 0.9 + +2003-04-11 Havoc Pennington + + * bus/messagebus.in: remove pid file when stopping the + message bus, since the bus won't have privileges to remove it + itself. + +2003-04-11 Havoc Pennington + + * bus/bus.c (bus_context_new): move credentials change after + creating pidfile + +2003-04-11 Havoc Pennington + + * test/decode-gcov.c: add "below average functions" to the + coverage report, and change how some of the code works. + + * bus/test-main.c: bracket some stuff in DBUS_BUILD_TESTS so it's + not in the coverage stats. + + * test/test-service.c (main): use _dbus_verbose not fprintf in a + couple places so running the test suite doesn't result in megaspam. + +2003-04-11 Havoc Pennington + + * bus/dispatch.c (check_existent_service_activation): accept a no + memory error in a place we didn't before + + * bus/test.c (bus_test_run_everything): remove hacky "do it twice + in case the first one failed," since the test suite is less + broken now. + +2003-04-10 Havoc Pennington + + * bus/dispatch.c (check_segfault_service_activation): add test + for launching an executable that just crashes. + + * test/test-segfault.c (main): try setting coredumpsize to 0 so we + don't leave a million cores. We'll see how portable this is. + +2003-04-10 Havoc Pennington + + * dbus/dbus-spawn.c (_dbus_spawn_async_with_babysitter): move all + the possible parent failures before we fork, so that we don't + fail to create a babysitter after creating the child. + + * bus/activation.c (bus_activation_activate_service): kill child + if we don't successfully complete the activation. + +2003-04-10 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_flush): don't spin on + the connection if it's disconnected + + * bus/activation.c (bus_activation_service_created): use new + transaction features to roll back removal of pending activation if + we don't successfully create the service after all. Don't remove + pending activation if the function fails. + + * dbus/dbus-list.c (_dbus_list_insert_before_link) + (_dbus_list_insert_after_link): new code to facilitate + services.c fixes + + * dbus/dbus-hash.c (_dbus_hash_table_insert_string_preallocated): + new functionality, so we can preallocate the ability to insert + into a hash table. + + * bus/connection.c (bus_transaction_add_cancel_hook): new function + allowing us to put custom hooks in a transaction to be used for + cancelling said transaction + + * doc/dbus-specification.sgml: add some discussion of secondary + service owners, and disallow zero-length service names + + * bus/services.c (bus_registry_acquire_service): new function, + splits out part of bus_driver_handle_acquire_service() and fixes + a bug where we didn't remove the service doing the acquiring + from the secondary queue if we failed to remove the current owner + from the front of the queue. + +2003-04-10 Alexander Larsson + + * doc/dbus-specification.sgml: + s/org.freedesktop.Broadcast/org.freedesktop.DBus.Broadcast/ + +2003-04-10 Alexander Larsson + + * bus/.cvsignore: + * glib/.cvsignore: + * test/.cvsignore: + Added files to cvsignore + + * dbus/dbus-message.h: + * dbus/dbus-message.c: (dbus_message_iter_get_named): + Make get_named() take two out argument and return a boolean. + (dbus_message_iter_get_args_valist): + Update usage of get_named(). + (dbus_message_iter_append_byte): + Fix typo + (dbus_message_iter_append_named) + Fix typo + (message_iter_test), (check_message_handling_type), (_dbus_message_test): + More tests. + +2003-04-10 Alexander Larsson + + * dbus/dbus-marshal.[ch]: + Add array_type_pos argument to _dbus_marshal_validate_arg. + Let you pass a NULL end_pos to _dbus_marshal_validate_type. + + * dbus/dbus-message.[ch]: + Multi-dimensional arrays have full type specification in the + outermost array. Iter code re-arranged to handle this. + Added some more iter tests. + + * doc/dbus-specification.sgml: + Add me to authors. + Remove old FIXME. + Update new array encoding description. + Correct DBUS_SERVICE_FLAGS_REPLACE_EXISTING description. + + * test/data/invalid-messages/array-with-mixed-types.message: + * test/data/valid-messages/array-of-array-of-uint32.message: + Change to the new array format. + + * test/data/invalid-messages/too-short-dict.message: + Fix bug in test. + + * test/data/valid-messages/recursive-types.message: + Fix up and extend test. + +2003-04-10 Havoc Pennington + + * bus/dispatch.c: lots of fixes + + * dbus/dbus-mainloop.c (_dbus_loop_dispatch): export + (_dbus_loop_iterate): remove old "quit if no callbacks" code, + that was crack, broke the test service. + + * dbus/dbus-transport.c (_dbus_transport_open): fix error + handling to avoid piling up errors if we get a failure on the + first address. + + * dbus/dbus-internals.c (_dbus_real_assert_not_reached): include + pid in assertion failures. + + * dbus/dbus-mainloop.c (_dbus_loop_iterate): use static arrays up + to some fixed size of file descriptor array. Don't return TRUE + anytime a timeout exists, that led to lots of busy loop silliness + in the tests. + +2003-04-09 Havoc Pennington + + * dbus/dbus-mainloop.c (check_timeout): fix timeouts, I thought + I'd checked this in earlier but hadn't. + +2003-04-09 Havoc Pennington + + * bus/dispatch.c (bus_dispatch_test): get a bit further through + the activation test (man this is getting old!) + +2003-04-09 Havoc Pennington + + * test/test-utils.c: use dispatch status function to fix this up + + * bus/connection.c (connection_watch_callback): don't dispatch + from here + (connection_timeout_callback): don't dispatch from here + (bus_connections_setup_connection): set the dispatch status function + (bus_connection_disconnected): unset it + + * dbus/dbus-mainloop.c (_dbus_loop_queue_dispatch): new function + used to add a connection to be dispatched + (_dbus_loop_iterate): do the dispatching at the end of each + iteration + + * dbus/dbus-connection.c + (dbus_connection_set_dispatch_status_function): new function + allowing us to fix up main loop usage + (_dbus_connection_last_unref): free all the various function + user data + (dbus_connection_dispatch): call the DispatchStatusFunction + whenever this function returns + (dbus_connection_handle_watch): call DispatchStatusFunction + (dbus_connection_send_with_reply_and_block): call DispatchStatusFunction + (reply_handler_timeout): call DispatchStatusFunction + (dbus_connection_flush): call DispatchStatusFunction + +2003-04-09 Havoc Pennington + + * dbus/dbus-bus.c (dbus_bus_register): fix up error handling and + a memory leak + + * bus/dispatch.c (check_service_activated): fix bug in test + + * dbus/dbus-mainloop.c (check_timeout): fix this up + + * dbus/dbus-internals.c (_dbus_verbose_real): include PID in + verbose output so we can sort out output from different processes, + e.g. in the activation case. + +2003-04-08 Colin Walters + + * bus/bus.c (struct BusContext) [pidfile]: New member, to store + the pid file. + (bus_context_new): Set it. + (bus_context_unref): Use it to delete the pid file. + +2003-04-08 Havoc Pennington + + * test/data/invalid-messages/array-with-mixed-types.message: + regression test that fails for the moment + + * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): reorder + tests for convenience + + * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): don't allow + array of nil, it broke things. + + * test/data/invalid-messages/array-of-nil.message: regression test + + * test/data/valid-messages/array-of-array-of-uint32.message: + happened to write this so added it to suite + +2003-04-08 Havoc Pennington + + * bus/driver.c (bus_driver_handle_acquire_service): init + retval/reply before checking name + + * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): add a + recursion depth argument + + * dbus/dbus-message.h (struct DBusMessageIter): put some padding + in the public struct for future extension + + * dbus/dbus-message-builder.c (_dbus_message_data_load): fix + typo + + * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): fix a verbose + message + + * doc/dbus-specification.sgml: fix typo + +2003-04-08 Alexander Larsson + + Implemented recursive types, named types and new-style iters + + * bus/driver.c: + * glib/test-thread-client.c: (thread_func): + * glib/test-thread-server.c: (handle_test_message): + * test/test-service.c: (handle_echo): + Update to new api + + * dbus/Makefile.am: + * dbus/dbus-dict.c: + * dbus/dbus-dict.h: + * dbus/dbus.h + Remove DBusDict + + * dbus/dbus-internals.c: (_dbus_type_to_string): + Update for new types. + + * dbus/dbus-marshal.[ch]: + Implement recursive types and the new marshalling format. + Remove hardcoded dict marshalling. + Marshal named types. + + * dbus/dbus-message-builder.c: + Add BYTE_ARRAY. + Remove references to old types + + * dbus/dbus-message.[ch]: + New non-refcounted iter API that supports recursive iters. + Use iters for appending, including support for recursive + iters. + Add byte and named type support. + Update everything to new marshalling formats. + Add tests for new API. + + * dbus/dbus-protocol.h: + Remove old array types. + Add types: BYTE, ARRAY, DICT, NAMED + + * dbus/dbus-string.c: + * dbus/dbus-sysdeps.c: + Make parse_double locale safe. + + * dbus/dbus-test-main.c: + Call setlocale. + + * dbus/dbus-test.c: + Kill dict test + + * doc/dbus-specification.sgml: + Update spec + + * test/data/incomplete-messages/missing-body.message: + * test/data/invalid-messages/bad-boolean.message: + * test/data/invalid-messages/bad-boolean-array.message: + * test/data/invalid-messages/boolean-array-length-too-long.message-raw: + * test/data/invalid-messages/boolean-has-no-value.message-raw: + * test/data/invalid-messages/too-short-dict.message: + * test/data/valid-messages/dict-simple.message: + * test/data/valid-messages/dict.message: + * test/data/valid-messages/emptiness.message: + * test/data/valid-messages/lots-of-arguments.message: + * test/data/valid-messages/no-padding.message: + * test/data/valid-messages/recursive-types.message: + Add missing NAME fields + Fix up dicts & arrays + + * test/data/invalid-messages/dict-with-nil-value.message: + Removed, this is not invalid anymore. + + * test/data/valid-messages/recursive-types.message: + Add new test for deeply recursive types. + +2003-04-07 Havoc Pennington + + * bus/driver.c (bus_driver_handle_acquire_service): return an + error if you try to acquire a service that starts with ':' + +2003-04-07 Havoc Pennington + + * doc/dbus-specification.sgml: require that base service names + start with ':' and that the base service is created/deleted + as first and last things a connection does on the bus + + * bus/dispatch.c (check_existent_service_activation): lots more + work on the activation test; it doesn't fully pass yet... + + * test/test-service.c (main): fix so we don't memleak the + connection to the message bus + (filter_func): accept a message asking us to exit + +2003-04-06 Havoc Pennington + + * qt/Makefile.am (dbusinclude_HEADERS): install dbus-qt.h, + from Colin Walters + + * configure.in: fixes to Qt detection from Colin Walters + + * doc/Makefile.am: Only remove generated docbook dirs if they + exist, from Colin Walters + + * dbus/dbus-bus.c: change how we set well-known connections to + NULL, so that it works if a single connection is stored in + two well-known array slots. + + * test/Makefile.am: remove a lot of stuff that isn't immediately + useful, it's in CVS history if we want it. + + * test/test-service.c: use dbus-mainloop instead of that + watch.[hc] crack + +2003-04-06 Havoc Pennington + + * dbus/Makefile.am: split lists of sources into stuff that goes in + the library, util functions that go in the lib and are also used + elsewhere, and util functions that are used in tests/daemon but + don't go in the lib. + + * dbus/dbus-mainloop.h, dbus/dbus-mainloop.c: move bus/loop.[hc] + here so it can be used in test binaries also + +2003-04-06 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_become_daemon): write the pidfile + here in the parent process, so we can return an error if it + fails. Also, move some of the code into the child so the parent + is less hosed if we fail midway through. + + * bus/bus.c (bus_context_new): move pidfile detection further up + in the function, before we start overwriting sockets and such. + + * bus/messagebus.in: adjust this a bit, not sure if it will work. + + * configure.in: add --with-system-pid-file and --with-system-socket + +2003-04-06 Colin Walters + + * configure.in (DBUS_SYSTEM_PID_FILE): New variable. + + * bus/system.conf.in: Declare a pidfile. + + * bus/bus.c (bus_context_new): Test for an existing pid file, and + create one (if appropriate). + + * bus/config-parser.c (enum ElementType) [ELEMENT_PIDFILE]: New. + (struct BusConfigParser) [pidfile]: New. + (element_type_to_name, merge_included, start_busconfig_child) + (bus_config_parser_end_element, bus_config_parser_content): Handle it. + (bus_config_parser_unref): Free it. + (bus_config_parser_get_pidfile): New function. + + * bus/config-parser.h (_dbus_write_pid_file): Prototype. + + * dbus/dbus-errors.h (DBUS_ERROR_PIDFILE_EXISTS): New error. + + * dbus/dbus-sysdeps.c (_dbus_write_pid_file): New function. + + * dbus/dbus-sysdeps.h: Prototype it. + +2003-04-06 Havoc Pennington + + * bus/bus.c (bus_context_new): print the address in here, rather + than in main(), because we need to do it before forking the daemon + + * bus/dispatch.c (send_service_nonexistent_error): set the sender + on the service nonexistent error + + * bus/driver.c (bus_driver_handle_acquire_service): set the + sender on the AcquireService reply + + * test/data/valid-config-files/debug-allow-all.conf.in: Make test + server also listen on a UNIX socket so services can connect to it. + +2003-04-06 Havoc Pennington + + * dbus/dbus-threads.c: Redo how the fake debug mutexes are done + so it detects deadlocks and also we actually init threads when + debugging. + +2003-04-06 Havoc Pennington + + * dbus/dbus-server-unix.c (_dbus_server_new_for_domain_socket): + save the domain socket name, and unlink it when we disconnect the + server. Means that at least when we exit normally, we won't leave + a bunch of junk in /tmp + + * dbus/dbus-transport-unix.c + (_dbus_transport_new_for_domain_socket): code cleanup (nicer + memory management). (I was making a real change here but then + didn't) + +2003-04-06 Havoc Pennington + + * bus/bus.c (bus_context_new): fix wrong handling of + server_data_slot_unref() in the error case. + + * dbus/dbus-internals.h (_dbus_assert): change so it passes + "(condition) != 0" to _dbus_real_assert so that + "_dbus_assert (pointer)" doesn't cause a warning + + * bus/main.c (main): accept --print-address option to print out + the message bus address + + * dbus/dbus-sysdeps.c (_dbus_generate_random_ascii): export this + + * dbus/dbus-transport.c (_dbus_transport_open): special error for + "tmpdir" option to unix: address on client side + + * dbus/dbus-server.c (dbus_server_listen): handle "tmpdir" option + to unix: address + + * configure.in (TEST_SOCKET_DIR): locate a temporary directory + we can use to create sockets in the test suite. + + * bus/main.c (signal_handler): on SIGTERM, exit the daemon + cleanly. To be used for testing. + + * dbus/dbus-spawn.c (babysit): use _dbus_set_signal_handler() + + * dbus/dbus-sysdeps.c (_dbus_set_signal_handler): new + + * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new): + handle trying to call this when there's no servers active + +2003-04-05 Havoc Pennington + + * NEWS: update + + * configure.in: 0.8 + +2003-04-05 Havoc Pennington + + * bus/bus.c (setup_server): fix this so dbus-daemon-1 doesn't + crash on startup. Need to get "try starting the daemon" + in the test suite I guess. ;-) + + * dbus/dbus-server.h, dbus/dbus-server.c: remove the stuff that + tracked the number of open connections; it's better done in + application-specific code as you want it to span all servers etc. + +2003-04-05 Havoc Pennington + + * bus/Makefile.am (install-data-hook): add missing DESTDIR, + patch from Colin Walters + +2003-04-05 Havoc Pennington + + * doc/config-file.txt (Elements): fix docs of to reflect + reality; in fact multiple mechanisms are allowed. + + * dbus/dbus-internals.c (_dbus_real_assert) + (_dbus_real_assert_not_reached): move guts of _dbus_assert() and + _dbus_assert_not_reached() into functions, so that they don't show + up in basic block counts for test coverage, and don't use up as + much disk space. Does mean slower execution speed though, so + assumes --disable-asserts is the normal production case. + +2003-04-05 Havoc Pennington + + * test/Makefile.am (dist-hook): also dist *.in files + + * NEWS: update + + * configure.in: 0.7 + +2003-04-05 Havoc Pennington + + * dbus/dbus-string.c: docs warning + + * dbus/dbus-spawn.c: missing docs + + * dbus/dbus-memory.c (struct ShutdownClosure): missing docs + +2003-04-05 Havoc Pennington + + * bus/loop.c (bus_loop_iterate): fix the timeout code, using + magic from GLib + + * dbus/dbus-spawn.c (_dbus_babysitter_unref): set sitter_pid + to -1 once we've reaped the babysitter + (_dbus_babysitter_handle_watch): do as much work as we can, not + just one go of it + + * bus/activation.c: add code using DBusBabysitter so that we + handle it when a service fails to start up properly. + (bus_activation_service_created): don't remove the activation + entries as we go, just let them get removed when we free the pending + activation. Unref reply messages after sending them. + +2003-04-05 Havoc Pennington + + * test/decode-gcov.c (main): print per-directory stats in the report + + * Makefile.am (coverage-report.txt): don't include test/* in gcov stats + +2003-04-05 Havoc Pennington + + * Makefile.am (coverage-report.txt): add target "coverage-report.txt" + + * test/decode-gcov.c: hack up a little program to suck data + out of gcov files. Yes this is sort of silly. + + * configure.in: define something in config.h and do an + AM_CONDITIONAL when gcov is enabled + +2003-04-04 Havoc Pennington + + * dbus/dbus-spawn.c, dbus/dbus-spawn.h: Change dbus_spawn to + return a "babysitter" object that is used to monitor the status of + the spawned process and reap it when required. + + * test/test-segfault.c, test/test-exit.c, + test/test-sleep-forever.c: binaries that do various lame things, + used in the test suite. + + * dbus/dbus-sysdeps.c: kill _dbus_errno_to_string() + +2003-04-03 Havoc Pennington + + * dbus/dbus-spawn.c: Move dbus-spawn into a separate file + in preparation for modifying it, dbus-sysdeps is getting + a bit unmanageable. + +2003-04-03 Havoc Pennington + + * bus/loop.h, bus/loop.c: make the mainloop an object so we can + have multiple ones + + * bus/*.[hc]: adapt to mainloop change + +2003-04-03 Havoc Pennington + + * bus/activation.c (load_directory): fix up memleaks + (bus_activation_entry_free): free the entry + + * dbus/dbus-bus.c (dbus_bus_acquire_service): return an error if + we get one from the message bus; fix memleaks. + + * dbus/dbus-message.c (dbus_set_error_from_message): new function + +2003-04-03 Havoc Pennington + + * bus/config-parser.c (bus_config_parser_unref): free + list of mechanisms, bug discovered by test suite enhancements + (putting system.conf and session.conf into suite) + + * test/Makefile.am, test/test-service.c: add placeholder for a + test service that we'll activate as part of test suite. Doesn't + do anything yet. + + * dbus/dbus-sysdeps.c (_dbus_setenv): support unsetenv by + setting NULL value, and use system malloc not dbus_malloc() + when we have unavoidable memleakage. + + * dbus/dbus-bus.c (dbus_bus_get): fix bug where bus type of 0 + didn't work, and support DBUS_BUS_ACTIVATION. + + * bus/activation.c (child_setup): pass our well-known bus type to + the child + + * bus/config-parser.c: support to specify well-known type + + * doc/dbus-specification.sgml: document the env variables to + locate well-known buses and find service activator + +2003-04-02 Havoc Pennington + + * test/Makefile.am (all-local): add a rule to copy tests to + builddir, so we can have generated tests. Use this to remove the + silly hack for testing system.conf and session.conf. Will use this + shortly to generate .service files pointing to test binaries. + +2003-04-02 Havoc Pennington + + * dbus/dbus-string.c (set_length): fix a bug - we allocated max of + current alloc and needed new length, not max of the doubled + allocation and needed new length. Also, when building tests, + don't do the double-allocation stuff, just realloc every time. + +2003-04-02 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_file_get_contents): include filenames + in error messages + (_dbus_string_get_dirname): new + (_dbus_sysdeps_test): new + (_dbus_directory_open): include dirnames in error messages + + * bus/config-parser.c: interpret and and + relative to config file location if the given + filename is not absolute. + + * dbus/dbus-string.c (_dbus_string_find_byte_backward): new + +2003-04-02 Havoc Pennington + + * bus/connection.c (bus_transaction_send_error_reply): set sender + service for the error, and unref the reply on success + + * bus/activation.c: convert to use BusTransaction so OOM can be + handled correctly + (bus_activation_service_created): set sender of the message + +2003-04-01 Havoc Pennington + + * bus/config-parser.c, bus/bus.c: implement and + (at least mostly) + + * dbus/dbus-sysdeps.c (_dbus_change_identity): set the group ID + first, then the user ID + +2003-04-01 Havoc Pennington + + * dbus/dbus-server.c (dbus_server_set_auth_mechanisms): new + function + + * dbus/dbus-auth.c (_dbus_auth_set_mechanisms): new + + * dbus/dbus-internals.c (_dbus_dup_string_array): new function + + * dbus/dbus-sysdeps.c (_dbus_listen_unix_socket): chmod the + socket 0777, and unlink any existing socket. + + * bus/bus.c (bus_context_new): change our UID/GID and fork if + the configuration file so specifies; set up auth mechanism + restrictions + + * bus/config-parser.c (bus_config_parser_content): add support + for option and fill in code for + + * bus/system.conf.in: add to default configuration, + and limit auth mechanisms to EXTERNAL + + * doc/config-file.txt (Elements): add + + * dbus/dbus-sysdeps.c (_dbus_become_daemon): new function + (_dbus_change_identity): new function + +2003-03-31 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_connect_unix_socket) + (_dbus_listen_unix_socket): fix off-by-one error in null + termination spotted by Nalin + +2003-03-31 Havoc Pennington + + * dbus/dbus-keyring.c (_dbus_keyring_new_homedir): allow setting + DBUS_TEST_HOMEDIR when tests are enabled, so we can test without + having a real home directory available. + +2003-03-31 Havoc Pennington + + * bus/Makefile.am (install-data-hook): create /var/run/dbus + + * bus/messagebus.in: add init script for Red Hat /etc/init.d + + * configure.in: add support for specifying a style of init script + to install + +2003-03-31 Havoc Pennington + + Fix some annoying DBusString API and fix all affected code. + + * dbus/dbus-string.c (_dbus_string_init): get rid of annoying + max_length argument + (_dbus_string_get_data): change to return string instead of using + an out param + (_dbus_string_get_const_data): ditto + (_dbus_string_get_data_len): ditto + (_dbus_string_get_const_data_len): ditto + +2003-03-31 Havoc Pennington + + * bus/main.c (main): fix up the command line arguments to be nicer + +2003-03-31 Havoc Pennington + + * dbus/Makefile.am (INCLUDES): use EXPANDED_LOCALSTATEDIR to + define DBUS_SYSTEM_BUS_PATH as we want to compile in the same + final location that lands in the config file + + * bus/config-loader-expat.c (bus_config_load): fix type of + XML_Parser variable + + * doc/TODO: remove TODO item for dbus_bus_get() + + * dbus/dbus-bus.c (bus_data_free): add missing lock/unlock + +2003-03-31 Havoc Pennington + + * dbus/dbus-transport-unix.c (_dbus_transport_new_for_domain_socket) + (_dbus_transport_new_for_tcp_socket): these didn't need the "server" + argument since they are always client side + + * dbus/dbus-server.c (dbus_server_get_address): new function + + * bus/main.c (main): take the configuration file as an argument. + + * test/data/valid-config-files/debug-allow-all.conf: new file to + use with dispatch.c tests for example + + * bus/test-main.c (main): require test data dir + + * bus/bus.c (bus_context_new): change this to take a + configuration file name as argument + + * doc/config-file.txt (Elements): add + + * bus/system.conf, bus/session.conf: new files + + * dbus/dbus-bus.c (dbus_bus_get): look for system bus on + well-known socket if none set + + * configure.in: create system.conf and session.conf + +2003-03-30 Havoc Pennington + + * bus/config-parser.c: hacking + + * dbus/dbus-memory.c: don't use DBusList for the list of stuff + to shut down, since it could cause weirdness with the DBusList + lock + + * dbus/dbus-list.c (_dbus_list_test): add tests for the + link-oriented stack routines + (alloc_link): free the mempool if the first alloc from it fails + + * dbus/dbus-mempool.c (struct DBusMemBlock): fix alignment issue + + * dbus/dbus-string.c (UNICODE_VALID): sync new version of this + from GLib + (_dbus_string_skip_white): new + + * doc/config-file.txt (Elements): add + +2003-03-28 Havoc Pennington + + * dbus/dbus-string.c (_dbus_string_copy_data_len) + (_dbus_string_copy_data): new functions + +2003-03-28 Anders Carlsson + + * dbus/dbus-bus.c: (bus_data_free), (dbus_bus_get): + * dbus/dbus-bus.h: + Add dbus_bus_get. + + * dbus/dbus-memory.c: + Fix a doc comment. + +2003-03-28 Havoc Pennington + + * bus/test.c (bus_test_flush_bus): remove the sleep from here, + I think it may have just been superstition. Not sure. + + * dbus/dbus-string.c (_dbus_string_base64_decode): catch some OOM + failures that were not being handled. + + * dbus/dbus-auth.c (process_auth): fix a memleak in OOM handling + + * dbus/dbus-memory.c: add ability to set number of mallocs in a + row that will fail on out-of-memory. + + * dbus/dbus-internals.c (_dbus_test_oom_handling): convenience + function for testing out-of-memory handling. + + * bus/config-loader-expat.c (memsuite): don't wrap the dbus + allocation functions, they do map exactly to the expat ones. + +2003-03-27 Havoc Pennington + + * bus/config-loader-libxml.c (bus_config_load): add another error + check + +2003-03-26 Anders Carlsson + + * doc/TODO: + Add note about automatic service activation. + + * doc/dbus-specification.sgml: + Rename the specification and clarify a few things. + +2003-03-26 Anders Carlsson + + * Doxyfile.in: + * dbus/dbus-address.c: + * dbus/dbus-dict.c: + * dbus/dbus-marshal.c: + * dbus/dbus-server-debug-pipe.c: + * dbus/dbus-transport-unix.c: + Fix documentation warnings. + +2003-03-26 Havoc Pennington + + * bus/test-main.c, dbus/dbus-test.c (main): check memleaks + after every test so it's quick and easy to see which leaked, and + so we test multiple dbus_shutdown() calls + + * configure.in: change configure.in XML stuff to also support + expat + + * config-loader-libxml.c: some hacking + + * config-loader-expat.c: some hacking + + * config-parser.c: some hacking, plus tests + +2003-03-25 Havoc Pennington + + * throughout - add more _DBUS_ASSERT_ERROR_IS_CLEAR + + * configure.in: add --with-xml option to specify XML library, + right now only libxml is supported. + + * bus/config-loader-libxml.c, config-parser.c: sync some minor + nonworking code between home and work, still just stubs + +2003-03-24 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_set_fd_nonblocking): move to this + file + + * dbus/dbus-errors.c (dbus_set_error, dbus_set_error_const): allow + NULL argument for "message" if the error is a well-known one, + fill in a generic message in this case. + + * dbus/dbus-errors.h (DBusResultCode): Kill DBusResultCode in + favor of DBusError + + * bus/test.c (bus_test_flush_bus): add + + * bus/policy.c (bus_policy_test): test code stub + +2003-03-24 Havoc Pennington + + * bus/connection.c (bus_connections_setup_connection): set up + the "can this user connect" function, but it always returns + TRUE until we have a config file parser so we can have a config + file that allows connections. + +2003-03-23 Havoc Pennington + + * dbus/dbus-threads.c (dbus_mutex_new, dbus_condvar_new): with + DBUS_BUILD_TESTS, actually alloc/free a block of memory for + the mutex, so we can check for proper memory management + and OOM handling. + + * dbus/dbus-dataslot.c: remove the mutex from + DBusDataSlotAllocator and lock it manually when using it, + to simplify fitting it into the global slots framework. + + * dbus/dbus-threads.c (init_static_locks): rework how we're + handling global locks so they are easily shut down. + + * bus/policy.c (bus_policy_append_rule): fix + + * bus/test-main.c (main): check for memleaks + + * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): make + test suite check for memleaks + + * dbus/dbus-memory.c: add support in test mode for tracking + number of outstanding blocks + +2003-03-23 Havoc Pennington + + * bus/policy.c, bus/bus.c, bus/connection.c: implement allow/deny + policies code + + * dbus/dbus-hash.h: add ULONG hash keys + + * dbus/dbus-sysdeps.c (_dbus_get_groups): new + (_dbus_get_group_id): new function + +2003-03-20 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_set_unix_user_function): + new function + (dbus_connection_get_unix_user): new function + +2003-03-20 Havoc Pennington + + * bus/connection.c (bus_connection_send_oom_error): assert that + message has a sender + (connection_execute_transaction): ditto + (bus_connection_preallocate_oom_error): fix to set the sender, and + set recipient to the destination service, not the bus driver + + * bus/policy.c: hacking + + * dbus/dbus-message.c (dbus_message_service_is): new function + (dbus_message_sender_is): new + +2003-03-19 Havoc Pennington + + * bus/policy.c: start sketching code for policy restrictions on + what connections can do. + +2003-03-18 Havoc Pennington + + * doc/TODO: some notes on high-level todo items. Little nitpick + stuff is all in @todo, so no need to add it here. + + * doc/config-file.txt: some notes on how config file might look + +2003-03-18 Anders Carlsson + + * configure.in: 0.6 + + * NEWS: Update. + +2003-03-17 Havoc Pennington + + * dbus/dbus-internals.h: add gcc attributes so that + our printf-style functions warn on bad arguments to + format + + * dbus/dbus-sysdeps.c (_dbus_connect_tcp_socket): fix printf + format bug + + * dbus/dbus-message.c (_dbus_message_loader_queue_messages): fix + printf format bug + +2003-03-17 Havoc Pennington + + * bus/test-main.c (main): make it print something as it runs + so make check doesn't look stuck + + * doc/negotiation.txt, doc/dbus-sasl-profile.txt: remove + from CVS, now obsolete + +2003-03-17 Anders Carlsson + + * bus/dispatch.c: (bus_dispatch): + Refetch the service name since it may have been reallocated + when dbus_message_set_sender was called. + + * dbus/dbus-sysdeps.c: (_dbus_accept): + Add address and address length variables and use them to stop + valgrind from complaining. + +2003-03-17 Havoc Pennington + + All tests pass, no memleaks, no valgrind complaints. + + * bus/test.c: refcount handler_slot + + * bus/connection.c (bus_connections_new): refcount + connection_data_slot + + * dbus/dbus-auth-script.c (_dbus_auth_script_run): delete unused + bytes so that auth scripts pass. + + * bus/dispatch.c: init message_handler_slot so it gets allocated + properly + + * bus/dispatch.c (message_handler_slot_ref): fix memleak + + * dbus/dbus-server-debug-pipe.c (_dbus_server_debug_pipe_new): + dealloc server_pipe_hash when no longer used for benefit of + leak checking + + * dbus/dbus-auth.c (process_command): memleak fix + + * bus/dispatch.c (check_hello_message): memleak fix + +2003-03-16 Havoc Pennington + + * dbus/dbus-bus.c (ensure_bus_data): fix double-unref of the data slot + +2003-03-17 Anders Carlsson + + * bus/activation.c (bus_activation_activate_service): Append + the pending activation entry to the list of pending activations. + +2003-03-16 Havoc Pennington + + * bus/dispatch.c (bus_dispatch_test): remove double-unrefs of + connections + + * dbus/dbus-address.c (create_entry): fix OOM handling when + failing to alloc entry->method + +2003-03-16 Havoc Pennington + + * dbus/dbus-watch.c (_dbus_watch_new): handle failure to malloc + the watch + + * dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new): + add some missing dbus_set_result + + * bus/dispatch.c (bus_dispatch_add_connection): handle failure to + alloc the DBusMessageHandler + + * dbus/dbus-transport.c (_dbus_transport_disconnect): don't ref + the transport here, since we call this from the finalizer; it + resulted in a double-finalize. + + * dbus/dbus-transport.c (_dbus_transport_disconnect): fix a bug + where we tried to use transport->connection that was NULL, + happened when transport was disconnected early on due to OOM + + * bus/*.c: adapt to handle OOM for watches/timeouts + + * dbus/dbus-transport-unix.c: port to handle OOM during + watch handling + + * dbus/dbus-auth.c (_dbus_auth_get_unused_bytes): return a + reference to unused bytes instead of a copy + + * dbus/dbus-server.c (dbus_server_handle_watch): return FALSE for + out of memory + + * dbus/dbus-connection.c (dbus_connection_handle_watch): return + FALSE on OOM + + * dbus/dbus-timeout.c (dbus_timeout_handle): return FALSE for out + of memory + +2003-03-16 Anders Carlsson + + * doc/dbus-specification.sgml: + Document reply message for ActivateService. + +2003-03-16 Anders Carlsson + + * bus/activation.c: (bus_pending_activation_entry_free), + (bus_pending_activation_free), (bus_activation_new), + (bus_activation_unref), (bus_activation_service_created), + (bus_activation_activate_service): + * bus/activation.h: + * bus/bus.c: (bus_context_new): + * bus/desktop-file.c: (new_section): + * bus/driver.c: (bus_driver_send_service_deleted), + (bus_driver_handle_activate_service): + * bus/services.c: (bus_registry_new), (bus_registry_ensure): + * bus/services.h: + * dbus/dbus-connection.c: + (dbus_connection_send_with_reply_and_block): + * dbus/dbus-message.c: (dbus_message_append_args_valist): + * dbus/dbus-protocol.h: + Make activation work better. Now pending activations will be queued + and the daemon won't try to activate services that are already registered. + +2003-03-16 Havoc Pennington + + * dbus/dbus-bus.c (ensure_bus_data): handle failure to set + connection data + + * dbus/dbus-memory.c (_dbus_initialize_malloc_debug): support + DBUS_MALLOC_BACKTRACES to print trace when failing an alloc + +2003-03-16 Havoc Pennington + + * dbus/dbus-string.c (_dbus_string_validate_utf8): oops, unbreak + this. always run the test suite before commit... + + * bus/*: adapt to DBusConnection API changes + + * glib/dbus-gmain.c: adapt to DBusConnection API changes, + requires renaming stuff to avoid dbus_connection_dispatch name + conflict. + + * dbus/dbus-transport.c (_dbus_transport_queue_messages): new + function + + * dbus/dbus-message.c (_dbus_message_loader_queue_messages): + separate from _dbus_message_loader_return_buffer() + + * dbus/dbus-connection.c (dbus_connection_get_n_messages): remove + this, because it's now always broken to use; the number of + messages in queue vs. the number still buffered by the message + loader is undefined/meaningless. Should use + dbus_connection_get_dispatch_state(). + (dbus_connection_dispatch): rename from + dbus_connection_dispatch_message + +2003-03-16 Havoc Pennington + + * dbus/dbus-string.c (_dbus_string_validate_utf8): copy in a real + implementation + +2003-03-16 Anders Carlsson + + * dbus/dbus-connection.c: + (dbus_connection_send_with_reply_and_block): + Decrease connection->n_incoming when removing an entry + from the list. + * dbus/dbus-dict.c: (dbus_dict_entry_free), + (dbus_dict_set_boolean_array), (dbus_dict_set_int32_array), + (dbus_dict_set_uint32_array), (dbus_dict_set_double_array), + (dbus_dict_set_byte_array), (dbus_dict_set_string_array), + (dbus_dict_get_boolean_array), (dbus_dict_get_double_array), + (dbus_dict_get_byte_array): + Handle NULL arrays and strings. Also add support for byte arrays. + + * dbus/dbus-marshal.c: (_dbus_marshal_byte_array), + (_dbus_marshal_dict), (_dbus_demarshal_byte_array), + (_dbus_demarshal_int32_array), (_dbus_demarshal_uint32_array), + (_dbus_demarshal_double_array), (_dbus_demarshal_string_array), + (_dbus_demarshal_dict), (demarshal_and_validate_len), + (_dbus_marshal_validate_arg), (_dbus_marshal_test): + * dbus/dbus-marshal.h: + Add support for marshalling and demarshalling empty arrays and strings. + + * dbus/dbus-message.c: (dbus_message_append_args_valist), + (dbus_message_append_string_array), + (dbus_message_iter_get_boolean), + (dbus_message_iter_get_boolean_array), + (dbus_message_iter_get_int32_array), + (dbus_message_iter_get_uint32_array), + (dbus_message_iter_get_double_array), + (dbus_message_iter_get_byte_array), + (dbus_message_iter_get_string_array), (dbus_message_iter_get_dict), + (check_message_handling): + Add support for getting empty arrays and dicts. + + * dbus/dbus-string.c: (_dbus_string_validate_utf8): + Don't do any validation at all for now, that's better than just checking + for ASCII. + + * test/data/valid-messages/emptiness.message: + New test message with lots of empty arrays. + +2003-03-16 Havoc Pennington + + * dbus/dbus-connection.c + (_dbus_connection_queue_received_message_link): new function that + can't fail due to OOM + + * dbus/dbus-message.c (_dbus_message_loader_pop_message_link): + new function pops a message together with a list link + containing it. + + * dbus/dbus-transport-unix.c (queue_messages): use new link-based + message queuing functions to avoid needing to alloc memory + +2003-03-16 Havoc Pennington + + Oops - test code was only testing failure of around 30 of the + mallocs in the test path, but it turns out there are 500+ + mallocs. I believe this was due to misguided linking setup such + that there was one copy of dbus_malloc etc. in the daemon and one + in the shared lib, and only daemon mallocs were tested. In any + case, the test case now tests all 500+ mallocs, and doesn't pass + yet, though there are lots of fixes in this patch. + + * dbus/dbus-connection.c (dbus_connection_dispatch_message): fix + this so that it doesn't need to allocate memory, since it + has no way of indicating failure due to OOM (and would be + annoying if it did). + + * dbus/dbus-list.c (_dbus_list_pop_first_link): new function + + * bus/Makefile.am: rearrange to create two self-contained + libraries, to avoid having libraries with overlapping symbols. + that was resulting in weirdness, e.g. I'm pretty sure there + were two copies of global static variables. + + * dbus/dbus-internals.c: move the malloc debug stuff to + dbus-memory.c + + * dbus/dbus-list.c (free_link): free list mempool if it becomes + empty. + + * dbus/dbus-memory.c (_dbus_disable_mem_pools): new function + + * dbus/dbus-address.c (dbus_parse_address): free list nodes + on failure. + + * bus/dispatch.c (bus_dispatch_add_connection): free + message_handler_slot when no longer using it, so + memory leak checkers are happy for the test suite. + + * dbus/dbus-server-debug-pipe.c (debug_finalize): free server name + + * bus/bus.c (new_connection_callback): disconnect in here if + bus_connections_setup_connection fails. + + * bus/connection.c (bus_connections_unref): fix to free the + connections + (bus_connections_setup_connection): if this fails, don't + disconnect the connection, just be sure there are no side + effects. + + * dbus/dbus-string.c (undo_alignment): unbreak this + + * dbus/dbus-auth.c (_dbus_auth_unref): free some stuff we were + leaking + (_dbus_auth_new): fix the order in which we free strings + on OOM failure + + * bus/connection.c (bus_connection_disconnected): fix to + not send ServiceDeleted multiple times in case of memory + allocation failure + + * dbus/dbus-bus.c (dbus_bus_get_base_service): new function to + get the base service name + (dbus_bus_register_client): don't return base service name, + instead store it on the DBusConnection and have an accessor + function for it. + (dbus_bus_register_client): rename dbus_bus_register() + + * bus/dispatch.c (check_hello_message): verify that other + connections on the bus also got the correct results, not + just the one sending hello + +2003-03-15 Havoc Pennington + + Make it pass the Hello handling test including all OOM codepaths. + Now to do other messages... + + * bus/services.c (bus_service_remove_owner): fix crash when + removing owner from an empty list of owners + (bus_registry_ensure): don't leave service in the list of + a connection's owned services if we fail to put the service + in the hash table. + + * bus/connection.c (bus_connection_preallocate_oom_error): set + error flag on the OOM error. + + * dbus/dbus-connection.c (_dbus_connection_new_for_transport): + handle _dbus_transport_set_connection failure + + * dbus/dbus-transport-unix.c (_dbus_transport_new_for_fd): modify + to create watches up front and simply enable/disable them as + needed. + (unix_connection_set): this can now fail on OOM + + * dbus/dbus-timeout.c, dbus/dbus-watch.c: add concept + of enabling/disabling a watch or timeout. + + * bus/loop.c (bus_loop_iterate): don't touch disabled + watches/timeouts + + * glib/dbus-gmain.c: adapt to enable/disable watches and timeouts + +2003-03-15 Havoc Pennington + + * bus/dispatch.c (bus_dispatch_test): OK, now finally actually + write useful test code, after all that futzing around ;-) + + Test does not yet pass because we can't handle OOM in + _dbus_transport_messages_pending (basically, + dbus_connection_preallocate_send() does not prealloc the write + watch). To fix this, I think we need to add new stuff to + set_watch_functions, namely a SetEnabled function so we can alloc + the watch earlier, then enable it later. + + * dbus/Makefile.am (libdbus_convenience_la_SOURCES): move + dbus-memory.c to the convenience lib + + * bus/test.c: rename some static functions to keep them clearly + distinct from stuff in connection.c. Handle client disconnection. + +2003-03-14 Havoc Pennington + + * bus/dispatch.c (bus_dispatch_test): do test using debug-pipe + transport, tests more of the real codepath. Set up clients + with bus_setup_debug_client. + + * bus/test.c (bus_setup_debug_client): function to set up debug + "clients" on the main loop + + * dbus/dbus-transport.c (_dbus_transport_open): add debug-pipe + support + + * dbus/dbus-server.c (dbus_server_listen): add debug-pipe + server type + + * dbus/dbus-server-debug.c: support a debug server based on pipes + + * dbus/dbus-sysdeps.c (_dbus_full_duplex_pipe): new function + (_dbus_close): new function + + * configure.in: check for socketpair + +2003-03-14 Havoc Pennington + + * dbus/dbus-memory.c: add a "detect buffer overwrites on free" + cheesy hack + + * dbus/dbus-transport-debug.c: rework this a good bit to be + less complicated. hopefully still works. + + * dbus/dbus-server-debug.c (handle_new_client): remove timeout + manually + + * glib/dbus-gmain.c (timeout_handler): don't remove timeout + after running it + + * dbus/dbus-message.c (dbus_message_copy): rename from + dbus_message_new_from_message, fix it up to copy + all the message fields, add test case + + * bus/dispatch.c (bus_dispatch_test): add some more test code, + not quite passing yet + +2003-03-14 Havoc Pennington + + * bus/loop.c (bus_loop_iterate): add this so we can "run loop + until no work remains" in test code. (the large diff here + is just code movement, no actual changes) + + * dbus/dbus-server-debug.c (DEFAULT_INTERVAL): change interval to + 1, no point waiting around for test code. + (_dbus_server_debug_accept_transport): unref the timeout + after adding it (right?) + + * dbus/dbus-transport-debug.c (DEFAULT_INTERVAL): ditto + +2003-03-13 Havoc Pennington + + * dbus/dbus-timeout.c (_dbus_timeout_list_set_functions): handle + out of memory + + * dbus/dbus-watch.c (_dbus_watch_list_set_functions): handle out + of memory + + * dbus/dbus-connection.h: Make AddWatchFunction and + AddTimeoutFunction return a bool so they can fail on out-of-memory + + * bus/bus.c (bus_context_new): set up timeout handlers + + * bus/connection.c (bus_connections_setup_connection): set up + timeout handlers + + * glib/dbus-gmain.c: adapt to the fact that set_functions stuff + can fail + + * bus/bus.c (bus_context_new): adapt to changes + + * bus/connection.c: adapt to changes + + * test/watch.c: adapt to DBusWatch changes + + * bus/dispatch.c (bus_dispatch_test): started adding this but + didn't finish + +2003-03-14 Anders Carlsson + + * bus/dispatch.c (send_service_nonexistent_error): Fix typo. + +2003-03-13 Havoc Pennington + + * bus/test.c, bus/test.h, bus/Makefile.am, bus/test-main.c: + set up a test framework as for the library + +2003-03-12 Havoc Pennington + + Throughout: purge global variables, introduce BusActivation, + BusConnections, BusRegistry, etc. objects instead. + + * bus/bus.h, bus/bus.c: introduce BusContext as a global + message bus object + + * test/Makefile.am (TEST_BINARIES): disable bus-test for now, + going to redo this a bit differently I think + +2003-03-12 Havoc Pennington + + Mega-patch that gets the message bus daemon initially handling + out-of-memory. Work still needed. Also lots of random + moving stuff to DBusError instead of ResultCode. + + * dbus/dbus-list.c (_dbus_list_length_is_one): new function + + * dbus/dbus-connection.c + (dbus_connection_send_with_reply_and_block): use DBusError + + * dbus/dbus-bus.c: adapt to API changes, make it use DBusError not + DBusResultCode + + * dbus/dbus-connection.c (dbus_connection_send): drop the result + code here, as the only failure possible is OOM. + + * bus/connection.c (bus_connection_disconnect): + rename bus_connection_disconnected as it's a notification only + + * bus/driver.c (bus_driver_handle_acquire_service): don't free + "name" on get_args failure, should be done by get_args; + don't disconnect client for bad args, just return an error. + (bus_driver_handle_service_exists): ditto + + * bus/services.c (bus_services_list): NULL-terminate returned array + + * bus/driver.c (bus_driver_send_service_lost) + (bus_driver_send_service_acquired): send messages from driver to a + specific client to the client's unique name, not to the broadcast + service. + + * dbus/dbus-message.c (decode_header_data): reject messages that + contain no name field + (_dbus_message_get_client_serial): rename to + dbus_message_get_serial and make public + (_dbus_message_set_serial): rename from set_client_serial + (_dbus_message_set_reply_serial): make public + (_dbus_message_get_reply_serial): make public + + * bus/connection.c (bus_connection_foreach): allow stopping + iteration by returning FALSE from foreach function. + + * dbus/dbus-connection.c (dbus_connection_send_preallocated) + (dbus_connection_free_preallocated_send) + (dbus_connection_preallocate_send): new API for sending a message + without possibility of malloc failure. + (dbus_connection_send_message): rename to just + dbus_connection_send (and same for whole function family) + + * dbus/dbus-errors.c (dbus_error_free): make this reinit the error + + * dbus/dbus-sysdeps.c (_dbus_exit): new function + + * bus/activation.c: handle/return errors + + * dbus/dbus-errors.h: add more DBUS_ERROR #define + + * dbus/dbus-sysdeps.c (_dbus_directory_open) (_dbus_file_get_contents) + (_dbus_directory_get_next_file): use DBusError instead of DBusResultCode + (_dbus_result_from_errno): move to this file + +2003-03-10 Anders Carlsson + + * dbus/dbus-marshal.c: + (_dbus_marshal_set_string): + Take a length argument so we can marshal the correct string + length. + + (_dbus_marshal_dict), (_dbus_demarshal_dict), + (_dbus_marshal_get_arg_end_pos), (_dbus_marshal_validate_arg), + (_dbus_marshal_test): + * dbus/dbus-marshal.h: + Add support for marshalling and demarshalling dicts. + + * dbus/dbus-message-builder.c: (_dbus_message_data_load): + Add support for TYPE DICT. + + * dbus/dbus-message.c: (set_string_field): + Adjust header padding. + + (dbus_message_append_args_valist), (dbus_message_append_dict), + (dbus_message_get_args_valist), (dbus_message_iter_get_arg_type), + (dbus_message_iter_get_dict), (_dbus_message_loader_return_buffer), + (check_message_handling), (check_have_valid_message): + * dbus/dbus-message.h: + Add functions for setting and getting dicts. + + * dbus/dbus-protocol.h: + Add DBUS_TYPE_DICT. + + * dbus/dbus.h: + Add dbus-dict.h + + * doc/dbus-specification.sgml: + Add information about how dicts are marshalled. + + * test/data/invalid-messages/dict-with-nil-value.message: + * test/data/invalid-messages/too-short-dict.message: + * test/data/valid-messages/dict-simple.message: + * test/data/valid-messages/dict.message: + Add sample messages containing dicts. + +2003-03-08 Anders Carlsson + + * dbus/dbus-dict.h: Add DBUS_END_DECLS. + +2003-03-07 Anders Carlsson + + * dbus/Makefile.am: + * dbus/dbus-dict.c: (dbus_dict_entry_free), (dbus_dict_new), + (dbus_dict_get_keys), (insert_entry), (dbus_dict_set_boolean), + (dbus_dict_set_int32), (dbus_dict_set_uint32), + (dbus_dict_set_double), (dbus_dict_set_string), + (dbus_dict_set_boolean_array), (dbus_dict_set_int32_array), + (dbus_dict_set_uint32_array), (dbus_dict_set_double_array), + (dbus_dict_set_string_array), (_dbus_dict_test): + * dbus/dbus-dict.h: + Fix according to comments from Havoc. + +2003-03-06 Michael Meeks + + * configure.in: if we don't have kde-config, disable have_qt. + +2003-03-07 Anders Carlsson + + * dbus/Makefile.am: + Add dbus-dict.[ch] + + * dbus/dbus-dict.c: (dbus_dict_entry_free), (dbus_dict_new), + (dbus_dict_ref), (dbus_dict_unref), (dbus_dict_contains), + (dbus_dict_remove), (dbus_dict_get_value_type), + (dbus_dict_get_keys), (dbus_dict_put_boolean), + (dbus_dict_put_int32), (dbus_dict_put_uint32), + (dbus_dict_put_double), (dbus_dict_put_string), + (dbus_dict_put_boolean_array), (dbus_dict_put_int32_array), + (dbus_dict_put_uint32_array), (dbus_dict_put_double_array), + (dbus_dict_put_string_array), (dbus_dict_get_boolean), + (dbus_dict_get_int32), (dbus_dict_get_uint32), + (dbus_dict_get_double), (dbus_dict_get_string), + (dbus_dict_get_boolean_array), (dbus_dict_get_int32_array), + (dbus_dict_get_uint32_array), (dbus_dict_get_double_array), + (dbus_dict_get_string_array), (_dbus_dict_test): + * dbus/dbus-dict.h: + Add DBusDict implementation + + * dbus/dbus-test.c: (dbus_internal_do_not_use_run_tests): + * dbus/dbus-test.h: + Add _dbus_dict_test + +2003-03-04 Havoc Pennington + + * test/data/auth/*: adapt to changes + + * dbus/dbus-auth-script.c (_dbus_auth_script_run): add + USERID_BASE64 and change USERNAME_BASE64 to put in username not + userid + + * dbus/dbus-keyring.c (_dbus_keyring_validate_context): prevent + more stuff from being in a context name, to make the protocol + simpler to deal with + + * dbus/dbus-errors.c (dbus_error_has_name): new function + (dbus_error_is_set): new function + + * dbus/dbus-auth.c: replace DBUS_STUPID_TEST_MECH auth + with DBUS_COOKIE_SHA1, implement DBUS_COOKIE_SHA1 + + * dbus/dbus-connection.c (dbus_connection_flush): also read + messages during a flush operation + + * dbus/Makefile.am: remove dbus-md5 since it isn't currently used. + +2003-03-05 Anders Carlsson + + * configure.in: Check for gethostbyname on Solaris. + + * dbus/dbus-transport.c: (_dbus_transport_open): + Remove duplicate "tcp" entry. + + * doc/dbus-specification.sgml: + Clarify some things. + +2003-03-05 Anders Carlsson + + * dbus/dbus-auth.c: (send_rejected), (process_test_subdir): + * dbus/dbus-keyring.c: (_dbus_keyring_new_homedir), + (_dbus_keyring_test): + * dbus/dbus-md5.c: (_dbus_md5_compute): + * dbus/dbus-sha.c: (_dbus_sha_compute): + Plug memory leaks. + +2003-03-05 Anders Carlsson + + * README: Add some things. + +2003-03-04 Anders Carlsson + + * dbus/dbus-message.c (dbus_message_append_args_valist): Add a break; + after case DBUS_TYPE_BOOELAN. + +2003-03-02 Havoc Pennington + + * test/break-loader.c (randomly_set_extreme_ints): add test that + sets really huge and small integers + + * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): add check + that length of boolean array fits in the string, and that + string has room for boolean value in single-bool case. + + * dbus/dbus-message-builder.c (_dbus_message_data_load): add + optional value to "ALIGN" command which is what to fill the + alignment with. + + * test/data/valid-messages/no-padding.message: add regression + test for the message padding problem + +2003-03-02 Havoc Pennington + + * dbus/dbus-message.c (decode_header_data): fix to always init + message_padding, from Benjamin Dauvergne + +2003-03-02 Havoc Pennington + + * configure.in: 0.5 + + * NEWS: Update. + +2003-03-01 Joe Shaw + + * configure.in: Check for "struct cmsgcred" and try to access its + members for BSD-like unices. + + * dbus/dbus-sysdeps.c (read_credentials_byte): Fold this back into + _dbus_read_credentials_unix_socket(). + (_dbus_read_credentials_unix_socket): Use recvmsg() instead of + read() for reading the credential byte off the unix socket. Use + struct cmsgcred on systems that support it. + +2003-02-27 Alexander Larsson + + * glib/Makefile.am: + * configure.in: + Make gthreads-2.0 dependency optional. Don't build thread test if + its not found. + +2003-02-27 Havoc Pennington + + * dbus/dbus-connection.c + (dbus_connection_send_message_with_reply_and_block): fix doh! + doh! doh! bug that resulted in never removing a reply from the + queue, no wonder we called get_reply_serial so much ;-) + + * dbus/dbus-message.c (struct DBusMessage): cache reply serial + and client serial instead of demarshaling them every time + +2003-02-27 Havoc Pennington + + * dbus/dbus-marshal.c (_dbus_demarshal_int32): rewrite to be much + more inlined, using dbus-string-private.h, speeds things up + substantially + + * dbus/dbus-string.c (_dbus_string_free): apply align offset + when freeing the string + (_dbus_string_steal_data): fix for align offset + (undo_alignment): new function + +2003-02-26 Havoc Pennington + + All kinds of audit fixes from Owen, plus initial attempt to + handle unaligned memory returned from malloc. + + * dbus/dbus-string.c (_dbus_string_init): clamp max length to + leave room for align_offset and nul byte + (fixup_alignment): function to track an align_offset and + ensure real->str is aligned + (DBUS_GENERIC_STRING_PREAMBLE): len must be less than allocated, + to allow a nul byte plus align offset + (_dbus_string_lock): fix overflow issue + (_dbus_string_init_const_len): add assertions on sanity of len, + assign allocated to be ALLOCATION_PADDING larger than len + (set_length): fixup the overflow handling + (_dbus_string_get_data_len): fix overflow in assertion + (open_gap): detect overflow in size of gap to be opened + (_dbus_string_lengthen): add overflow check + (_dbus_string_align_length): fix overflow with _DBUS_ALIGN_VALUE + (_dbus_string_append): add overflow check + (_dbus_string_append_unichar): overflow + (_dbus_string_delete): fix overflow in assertion + (_dbus_string_copy_len): overflow in assertion + (_dbus_string_replace_len): overflows in assertions + (_dbus_string_find): change to implement in terms of + _dbus_string_find_to + (_dbus_string_find_to): assorted fixage + (_dbus_string_equal_c_str): assert c_str != NULL, + fix logic so the function works + (_dbus_string_ends_with_c_str): fix overflow thingy + (_dbus_string_base64_encode): overflow fix + (_dbus_string_validate_ascii): overflow + (_dbus_string_validate_nul): overflow + +2003-02-26 Havoc Pennington + + * dbus/dbus-marshal.c (_dbus_marshal_test): fix to work with DISABLE_ASSERTS + +2003-02-26 Alexander Larsson + + * configure.in: + Set DBUS_GLIB_THREADS_LIBS for apps using gthread-2.0 + + * dbus/dbus-connection.c: + * dbus/dbus-connection.h: + Fix _dbus_connection_acquire_io_path and _dbus_connection_acquire_dispatch. + Add dbus_connection_set_wakeup_main_function and use it when queueing + incoming and outgoing messages. + + + * dbus/dbus-dataslot.c: + Threadsafe usage of DBusDataSlotAllocator + + * dbus/dbus-message.c: (dbus_message_get_args_iter): + dbus_new can fail. + + * dbus/dbus-server-unix.c: + Add todo comment + + * glib/dbus-gmain.c: + Implement the new wakeup functions for glib. + + * glib/Makefile.am: + * glib/test-thread-client.c: + * glib/test-thread-server.c: + * glib/test-thread.h: + Initial cut at some thread test code. Not really done yet. + +2003-02-26 Havoc Pennington + + * dbus/dbus-connection.c + (dbus_connection_send_message_with_reply_and_block): fix crash + where we ref'd the outgoing message instead of the returned reply + + * dbus/dbus-transport-unix.c (do_authentication): check read watch + at the end of this function, so if we didn't need to read for + authentication, we reinstall it for receiving messages + + * dbus/dbus-message.c (dbus_message_new_reply): allow replies to + a NULL sender for peer-to-peer case + + * dbus/dbus-transport-unix.c (check_read_watch): handle + !authenticated case correctly + + * glib/dbus-gmain.c: add support for DBusServer + + * dbus/dbus-server.c: add data slot support + + * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): check + return values and handle errors + + * dbus/dbus-dataslot.c: factor out the data slot stuff from + DBusConnection + + * Doxyfile.in (INPUT): add glib subdir + + * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): rename + setup_with_g_main instead of hookup_with_g_main; write docs + +2003-02-24 Anders Carlsson + + * dbus/dbus-marshal.c: (_dbus_marshal_validate_arg): + * dbus/dbus-message-builder.c: (_dbus_message_data_load): + * dbus/dbus-message.c: (dbus_message_append_boolean), + (dbus_message_append_boolean_array), + (dbus_message_get_args_valist), (_dbus_message_test): + * dbus/dbus-message.h: + * doc/dbus-specification.sgml: + Various fixes as pointed out by Havoc. + + * test/data/invalid-messages/bad-boolean-array.message: + * test/data/invalid-messages/bad-boolean.message: + Add invalid boolean value test cases. + +2003-02-24 Anders Carlsson + + * dbus/dbus-internals.c: (_dbus_type_to_string): + * dbus/dbus-marshal.c: (_dbus_marshal_get_arg_end_pos), + (_dbus_marshal_validate_arg): + * dbus/dbus-message-builder.c: (_dbus_message_data_load): + * dbus/dbus-message.c: (dbus_message_append_args_valist), + (dbus_message_append_boolean), (dbus_message_append_boolean_array), + (dbus_message_get_args_valist), (dbus_message_iter_get_boolean), + (dbus_message_iter_get_int32), (dbus_message_iter_get_uint32), + (dbus_message_iter_get_double), + (dbus_message_iter_get_boolean_array), (message_iter_test): + * dbus/dbus-message.h: + * dbus/dbus-protocol.h: + * doc/dbus-specification.sgml: + * test/data/valid-messages/lots-of-arguments.message: + Add support for boolean and boolean array types. + +2003-02-23 Havoc Pennington + + * dbus/dbus-keyring.c: finish most of this implementation and + simple unit test + + * dbus/dbus-errors.c (dbus_set_error_const, dbus_set_error): make + these barf if the error isn't cleared to NULL + + * dbus/dbus-sysdeps.c (_dbus_delete_file): set error on failure + (_dbus_create_directory): new function + + * dbus/dbus-errors.c (dbus_set_error): fix warning + + * dbus/dbus-string.c (_dbus_string_hex_encode): new function + (_dbus_string_hex_decode): new function + (test_hex_roundtrip): test code + + * dbus/dbus-sha.c (_dbus_sha_compute): use dbus_string_hex_encode + + * dbus/dbus-md5.c (_dbus_md5_compute): use dbus_string_hex_encode + + * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): make this use + the save-to-temp/rename trick to atomically write the new file + (_dbus_string_parse_uint): new function + +2003-02-22 Havoc Pennington + + * test/Makefile.am (dist-hook): fix dist for test/data/sha-1 + +2003-02-22 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_iter_get_string_array): + (dbus_message_iter_get_byte_array): Fix up doxygen warnings + + * dbus/dbus-sha.c: add implementation of SHA-1 algorithm + + * dbus/test/data/sha-1: add US government test suite for SHA-1 + +2003-02-21 Anders Carlsson + + * dbus/dbus-marshal.c: (_dbus_demarshal_string_array): + Make string arrays NULL-terminated. + + * dbus/dbus-memory.c: (dbus_free_string_array): + * dbus/dbus-memory.h: + New function for freeing NULL-terminated string arrays. + + * dbus/dbus-message-builder.c: (append_quoted_string), + (_dbus_message_data_load): + Add support for array types. + + * dbus/dbus-message.c: (check_message_handling): + Add more types as test cases. + + * dbus/dbus-sysdeps.c: (_dbus_string_parse_int), + (_dbus_string_parse_double): + Add the start offset to the end offset. + + * test/data/valid-messages/lots-of-arguments.message: + New test message with lots of arguments. + +2003-02-21 Anders Carlsson + + * dbus/dbus-message.c: (dbus_message_append_nil), + (dbus_message_append_int32), (dbus_message_append_uint32), + (dbus_message_append_double), (dbus_message_append_string), + (dbus_message_append_int32_array), + (dbus_message_append_uint32_array), + (dbus_message_append_double_array), + (dbus_message_append_byte_array), + (dbus_message_append_string_array): + Fix all out-of-memory handling in these functions. + +2003-02-21 Anders Carlsson + + * dbus/dbus-message.c: (dbus_message_append_nil): + Fix a silly. + +2003-02-21 Anders Carlsson + + * dbus/dbus-message.c: (dbus_message_append_args_valist), + (dbus_message_append_nil), (dbus_message_append_int32_array), + (dbus_message_append_uint32_array), + (dbus_message_append_double_array), + (dbus_message_append_byte_array), + (dbus_message_append_string_array), (dbus_message_get_args_valist), + (dbus_message_iter_get_int32_array), + (dbus_message_iter_get_uint32_array), + (dbus_message_iter_get_double_array), + (dbus_message_iter_get_byte_array), + (dbus_message_iter_get_string_array): + + * dbus/dbus-message.h: + Add functions for appending and getting arrays. + +2003-02-21 Anders Carlsson + + * dbus/dbus-mempool.c (_dbus_mem_pool_new): Make the + element size at least 8 bytes, fixes mempool tests on + 64-bit machines. + +2003-02-20 Alexander Larsson + + * dbus/dbus-transport-unix.c (unix_do_iteration): + Unlock the connection mutex during a blocking select call. + Add todo about how we need a way to wake up the select. + + * dbus/dbus-connection-internal.h: + * dbus/dbus-connection.c: + Add _dbus_connection_lock and _dbus_connection_unlock. + +2003-02-19 Havoc Pennington + + * Doxyfile.in (PREDEFINED): put DOXYGEN_SHOULD_SKIP_THIS in + Doxyfile.in, not Doxyfile + + * dbus/dbus-keyring.c: do some hacking on this + + * dbus/dbus-sysdeps.c (_dbus_delete_file): new + + * dbus/dbus-errors.c (dbus_set_error_const): do not call + dbus_error_init + (dbus_set_error): remove dbus_error_init, check for message == + NULL *before* we sprintf into it, and add @todo about including + system headers in this file + + * dbus/dbus-sysdeps.c (_dbus_create_file_exclusively): new + + * dbus/dbus-errors.h (DBUS_ERROR_FAILED): add + + * dbus/dbus-sysdeps.c (get_user_info): break this function out to + get various bits of user information based on either username + or user ID + (_dbus_homedir_from_username): new function + +2003-02-19 Anders Carlsson + + * configure.in: + Add check for nonposix getpwnam_r + + * dbus/dbus-mempool.c: (_dbus_mem_pool_new): + Align the pool element size to a sizeof (void *) boundary. + + * dbus/dbus-sysdeps.c: (_dbus_setenv), (_dbus_connect_unix_socket), + (_dbus_listen_unix_socket), (_dbus_credentials_from_username): + General Solaris fixes. + + * test/data/valid-messages/simplest-manual.message: + Explicitly state that we want little-endian packing. + +2003-02-19 Mikael Hallendal + + * dbus/dbus-server.c (dbus_server_listen): Support tcp: addresses. + + * dbus/dbus-transport-unix.c (_dbus_transport_new_for_tcp_socket): + Added to create a transport connecting using a tcp/ip socket. + + * dbus/dbus-sysdeps.c (_dbus_connect_tcp_socket): Added to connect + to a tcp socket at given host and port. + (_dbus_listen_tcp_socket): added to listen on tcp socket for given + hostname and port. + + * dbus/dbus-server.c (dbus_server_listen): Support tcp: addresses. + + * dbus/dbus-server-unix.c (_dbus_server_new_for_tcp_socket): + Added to create a server listening on a TCP/IP socket. + +2003-02-19 Havoc Pennington + + Throughout: mop up all the Doxygen warnings and undocumented + stuff. + + * dbus/dbus-sysdeps.c (do_exec): do not use execvp, we don't want + to search any paths. + + * dbus/dbus-threads.c: move global mutex initializers to + dbus-internals.h, multiple prototypes was confusing doxygen + besides being kind of ugly + + * Doxyfile (PREDEFINED): have Doxygen define + DOXYGEN_SHOULD_SKIP_THIS so we can exclude things from + docs with #ifndef DOXYGEN_SHOULD_SKIP_THIS + (do not abuse the feature! it's for stuff like the autogenerated + macros in dbus-md5.c, not just for things you don't feel like + documenting...) + +2003-02-18 Havoc Pennington + + * dbus/dbus-string.c (_dbus_string_zero): new function + + * dbus/dbus-md5.c: include MD5 implementation by L. Peter Deutsch, + wrap it in some dbus-friendly API + + * dbus/dbus-types.h: add 16-bit types + +2003-02-18 Joe Shaw + + * dbus/dbus-auth.c (handle_server_data_stupid_test_mech): Just get + credentials from our currently running process. + (get_word): Fix a buglet where we were copying the entire length + instead of relative to our position. + + * dbus/dbus-hash.c (_dbus_hash_test): Don't try to allocate the + keys on the stack... it's 640k of data. + + * dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): Always + read the credentials byte off the socket, even if we don't have + SO_PEERCRED. + (_dbus_poll): Implement poll() using select() for systems which + don't have it. + + * glib/test-dbus-glib.c (main): Print out an error if no + parameters are given. + + * test/data/auth/fallback.auth-script: Added. Tests that a client + can fallback to a secondary auth mechanism if the first fails. + +2003-02-18 Havoc Pennington + + * AUTHORS: add Alex + +2003-02-17 Havoc Pennington + + * doc/dbus-specification.sgml: lots of cosmetic + cleanups/rearrangement, add assorted FIXME, change DBUS_ADDRESS + env variable to DBUS_BUS_ADDRESS, s/client/application/, + s/server/bus/ (except in authentication section). Add a section + "Message Bus Message Routing" + +2003-02-17 Anders Carlsson + + Release 0.4 + + * NEWS: Update + +2003-02-17 Anders Carlsson + + * doc/dbus-specification.sgml: + Specification updates. + +2003-02-17 Anders Carlsson + + * bus/activation.c: (bus_activation_init), (child_setup), + (bus_activation_activate_service): + * bus/activation.h: + * bus/main.c: (main): + Set DBUS_ADDRESS environment variable. + + * dbus/dbus-errors.c: (dbus_set_error): + Don't use va_copy since that's a C99 feature. + + * dbus/dbus-sysdeps.c: (_dbus_setenv), (do_exec), + (_dbus_spawn_async): + * dbus/dbus-sysdeps.h: + Add child_setup_func to _dbus_spawn_async. + + * doc/dbus-specification.sgml: + Update specification. + + * test/spawn-test.c: (setup_func), (main): + Fix test. + +2003-02-17 Alexander Larsson + + * dbus/dbus-connection.c (_dbus_connection_handler_destroyed_locked): + Added todo. + +2003-02-17 Anders Carlsson + + * doc/.cvsignore: + * doc/Makefile.am: + * doc/dbus-test-plan.sgml: + Add test plan document. + + * test/Makefile.am: + Fix distcheck. + +2003-02-17 Anders Carlsson + + * dbus/dbus-message.c: (decode_header_data), + (_dbus_message_loader_return_buffer): + Set the header padding amount when loading a message. + +2003-02-16 Anders Carlsson + + * bus/dispatch.c: (send_one_message): + Only send broadcast messages to registered connections. + + * dbus/dbus-message.c: (dbus_message_name_is): + * dbus/dbus-message.h: + New convenience function. + + * dbus/dbus-transport-debug.c: (do_reading): + Only dispatch one message per run. + + * test/Makefile.am: + * test/bus-test.c: (new_connection_callback), (die), + (test_hello_client1_handler), (test_hello_client2_handler), + (test_hello_replies), (main): + + * test/bus-test-loop.[ch]: + Add these. + +2003-02-16 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_dispatch_message): fix + backward conditional + +2003-02-16 Alexander Larsson + + * dbus/dbus-connection.c: + Implement sent_message_with_reply. (with_reply_and block is still + busted). + Made dispatch_message not lose message if OOM. + + * dbus/dbus-errors.h: + Add NoReply error (for reply timeouts). + +2003-02-16 Alexander Larsson + + * dbus/dbus-hash.c (_dbus_hash_table_unref): + Actually free keys and values when destroying hashtable. + +2003-02-16 Anders Carlsson + + * dbus/dbus-auth.c: (client_try_next_mechanism): + Plug a leak. + + * dbus/dbus-threads.c: (dbus_condvar_wait_timeout): + Return TRUE if there's no thread implementation around. + + * glib/dbus-gmain.c: (free_source), + (dbus_connection_hookup_with_g_main): + Make sure to remove the GSource when the connection is finalized. + +2003-02-16 Anders Carlsson + + * bus/dispatch.c: (bus_dispatch_message_handler): + * dbus/dbus-errors.h: + Return an error if someone tries to send a message to a service + that doesn't exist. + +2003-02-16 Anders Carlsson + + * bus/activation.c: (load_directory), (bus_activation_init), + (bus_activation_activate_service): + * bus/activation.h: + * bus/driver.c: + (bus_driver_handle_activate_service), (bus_driver_handle_message): + More work on the activation handling. + + * dbus/dbus-errors.h: + Add some error messages + + * dbus/dbus-message.c: (dbus_message_new_error_reply): + * dbus/dbus-message.h: + New function that creates an error message. + + * dbus/dbus-protocol.h: + Add ACTIVATE_SERVER message. + + * dbus/dbus-server-unix.c: (unix_handle_watch), + (_dbus_server_new_for_domain_socket): + Call _dbus_fd_set_close_on_exec. + + * dbus/dbus-sysdeps.c: (make_pipe), (do_exec), + (_dbus_spawn_async), (_dbus_disable_sigpipe), + (_dbus_fd_set_close_on_exec): + * dbus/dbus-sysdeps.h: + Add _dbus_fd_set_close_on exec function. Also add function that checks + that all open fds are set to close-on-exec and warns otherwise. + + * dbus/dbus-transport-unix.c: + (_dbus_transport_new_for_domain_socket): + Call _dbus_fd_set_close_on_exec. + +2003-02-16 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_set_change_sigpipe): + allow people to avoid setting SIGPIPE to SIG_IGN + (_dbus_connection_new_for_transport): disable SIGPIPE unless + we've been asked not to + +2003-02-15 Anders Carlsson + + * dbus/dbus-list.c: (_dbus_list_append_link), + (_dbus_list_prepend_link): + * dbus/dbus-memory.c: (dbus_malloc), (dbus_malloc0), + (dbus_realloc): + Warning fixes. + +2003-02-15 Anders Carlsson + + * bus/Makefile.am: + * bus/activation.c: (bus_activation_entry_free), + (add_desktop_file_entry), (load_directory), (bus_activation_init): + * bus/activation.h: + * bus/main.c: (main): + Add simple activation support, doesn't work yet though. + +2003-02-15 Zack Rusin + + * qt/dbus-qthread.cpp: small casting fix + +2003-02-15 Anders Carlsson + + * dbus/dbus-errors.c: (dbus_set_error): + * dbus/dbus-errors.h: + Add a few errors and make dbus_set_error void. + + * dbus/dbus-sysdeps.c: + (_dbus_errno_to_string), (close_and_invalidate), (make_pipe), + (write_err_and_exit), (read_ints), (do_exec), (_dbus_spawn_async): + * dbus/dbus-sysdeps.h: + Add _dbus_spawn_async. + + * test/spawn-test.c: (main): + Test for _dbus_spawn_async. + +2003-02-15 Anders Carlsson + + * dbus/dbus-internals.h: + Fix build without tests. + + * dbus/dbus-list.c: (alloc_link): + Fix a segfault when a malloc fails. + + * dbus/dbus-memory.c: (initialize_malloc_debug), (dbus_malloc), + (dbus_malloc0), (dbus_realloc): + Add support for malloc debugging. + +2003-02-15 Alexander Larsson + + * dbus/dbus-threads.c: + * dbus/dbus-threads.h: + Add condvars. Remove static mutext from API. + Implement static mutexes by initializing them from threads_init. + + * glib/dbus-gthread.c: + * qt/dbus-qthread.cpp: + Update with the thread api changes. + + + * dbus/dbus-list.c: + * dbus/dbus-list.h: + Turn StaticMutex into normal mutex + init function. + Export new functions _dbus_list_alloc_link, _dbus_list_free_link, + _dbus_list_append_link, _dbus_list_prepend_link + + + * dbus/dbus-sysdeps.c: + * dbus/dbus-sysdeps.h: + New type dbus_atomic_t, and new functions _dbus_atomic_inc, + _dbus_atomic_dec. Only slow fallback implementation at the moment. + + * dbus/dbus-protocol.h: + Add DBUS_MESSAGE_LOCAL_DISCONNECT define + + * dbus/dbus-message.c: + Make ref/unref atomic. + Fix some docs. + + * dbus/dbus-connection-internal.h: + * dbus/dbus-connection.c: + * dbus/dbus-connection.h: + Make threadsafe. + Change _peek to _borrow,_return & _steal_borrowed. + Change disconnect callback to event. + Make dbus_connection_dispatch_messages reentrant. + + * dbus/dbus-transport.c: + Don't ref the connection on calls to the transport + implementation. + + * dbus/dbus-message-handler.c: + Make threadsafe. + + * glib/dbus-gmain.c: + Don't use peek_message anymore + + * test/Makefile.am: + * test/debug-thread.c: + * test/debug-thread.h: + Simple thread implementation that asserts() on deadlocks in + single-threaded code. + + * test/bus-test.c: + (main) Call debug_threads_init. + + * test/watch.c: + Use disconnect message instead of disconnect callback. + + * bus/connection.c: + * bus/connection.h: + Don't call dbus_connection_set_disconnect_function. Instead export + bus_connection_disconnect. + + * bus/dispatch.c: + Call bus_connection_disconnect when we get a disconnected message. + +2003-02-15 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_new): fool around with the + docs + +2003-02-14 Havoc Pennington + + * dbus/dbus-mempool.c: fail if the debug functions so indicate + + * dbus/dbus-memory.c: fail if the debug functions indicate we + should + + * dbus/dbus-internals.c (_dbus_set_fail_alloc_counter) + (_dbus_decrement_fail_alloc_counter): debug functions to + simulate memory allocation failures + +2003-02-14 Havoc Pennington + + * dbus/dbus-errors.h (struct DBusError): add a word of padding + to DBusError + +2003-02-13 Anders Carlsson + + * bus/driver.c: (bus_driver_handle_hello): + * bus/driver.h: + * bus/services.c: (bus_service_lookup): + Reorder message sending so we get a more sane order. + + * test/bus-test.c: (message_handler): + Fix tyop. + +2003-02-13 Anders Carlsson + + * bus/driver.c: (bus_driver_send_service_deleted), + (bus_driver_send_service_created), (bus_driver_send_service_lost), + (bus_driver_send_service_acquired), (bus_driver_handle_hello), + (bus_driver_send_welcome_message), + (bus_driver_handle_list_services), + (bus_driver_handle_acquire_service), + (bus_driver_handle_service_exists): + * dbus/dbus-bus.c: (dbus_bus_register_client), + (dbus_bus_acquire_service), (dbus_bus_service_exists): + * dbus/dbus-errors.c: (dbus_result_to_string): + * dbus/dbus-errors.h: + * dbus/dbus-message.c: (dbus_message_append_args), + (dbus_message_append_args_valist), (dbus_message_get_args), + (dbus_message_get_args_valist), (dbus_message_get_args_iter), + (dbus_message_iter_get_arg_type), (dbus_message_iter_get_string), + (dbus_message_iter_get_byte_array), + (dbus_message_iter_get_string_array), (message_iter_test), + (check_message_handling), (_dbus_message_test): + * dbus/dbus-message.h: + * test/bus-test.c: (main): + Change fields to arguments in messages, so that they won't be + confused with header fields. + + * glib/test-dbus-glib.c: (main): + Remove append_fields from hello message. + +2003-02-13 Anders Carlsson + + * dbus/dbus-errors.c: + * dbus/dbus-message.c: + * dbus/dbus-string.c: + Documentation fixes. + +2003-02-13 Anders Carlsson + + * glib/dbus-gmain.c: (timeout_handler), (add_timeout), + (remove_timeout): + Implement support for timeouts in dbus-glib. + +2003-02-13 Anders Carlsson + + * dbus/dbus-message-builder.c: (_dbus_message_data_load): + * dbus/dbus-message.c: (process_test_subdir): + * test/break-loader.c: (find_breaks_based_on): + Plug some memory leaks. + +2003-02-13 Richard Hult + + * bus/main.c: Fix build. + + * dbus/dbus-errors.h: + * dbus/dbus-errors.c: Fix copyright for Anders. + +2003-02-13 Anders Carlsson + + * bus/Makefile.am: + Add utils.[ch] + + * bus/connection.c: (bus_connection_foreach): + Fix a warning. + + * bus/desktop-file.c: (grow_lines_in_section), (grow_sections), + (unescape_string), (new_section), (parse_section_start), + (parse_key_value), (report_error), (bus_desktop_file_load), + (bus_desktop_file_get_string): + * bus/desktop-file.h: + Use DBusError for error reporting. + + * bus/dispatch.c: (send_one_message), + (bus_dispatch_message_handler): + * bus/driver.c: (bus_driver_send_service_deleted), + (bus_driver_send_service_created), (bus_driver_send_service_lost), + (bus_driver_send_service_acquired), (bus_driver_handle_hello), + (bus_driver_send_welcome_message), + (bus_driver_handle_list_services), + (bus_driver_handle_acquire_service), + (bus_driver_handle_service_exists): + * bus/loop.c: (bus_loop_run): + * bus/main.c: + Use BUS_HANDLE_OOM instead of _DBUS_HANDLE_OOM. + + * bus/utils.c: (bus_wait_for_memory): + * bus/utils.h: + New files with general utility functions. + + * dbus/dbus-internals.h: + Remove _DBUS_HANDLE_OOM. + +2003-02-13 Anders Carlsson + + * dbus/dbus-errors.c: (dbus_result_to_string), (dbus_error_init), + (dbus_error_free), (dbus_set_error_const), (dbus_set_error): + * dbus/dbus-errors.h: + Add DBusError structure. + +2003-02-13 Anders Carlsson + + * test/data/valid-messages/standard-acquire-service.message: + * test/data/valid-messages/standard-hello.message: + * test/data/valid-messages/standard-list-services.message: + * test/data/valid-messages/standard-service-exists.message: + Add some standard messages. + +2003-02-13 Anders Carlsson + + * bus/driver.c: (bus_driver_send_welcome_message), + (bus_driver_handle_list_services), + (bus_driver_handle_acquire_service), + (bus_driver_handle_service_exists), (bus_driver_handle_message): + Update for API changes in libdbus. + + * dbus/dbus-message.c: (dbus_message_new_reply): + * dbus/dbus-message.h: + Remove the name argument. The spec states that replies shouldn't + have a name. + +2003-02-13 Anders Carlsson + + * bus/desktop-file.c: (parse_section_start), (parse_key_value), + (report_error), (bus_desktop_file_load), (lookup_section), + (lookup_line), (bus_desktop_file_get_raw), + (bus_desktop_file_get_string): + * bus/desktop-file.h: + Some fixes, and new functions for getting a key value from a section. + +2003-02-13 Havoc Pennington + + * test/data/auth/fail-after-n-attempts.auth-script: new test + + * dbus/dbus-auth.c (send_rejected): shutdown_mech() when we + reject the client. + +2003-02-13 Havoc Pennington + + * dbus/dbus-auth.c (handle_server_data_external_mech): args to + dbus_credentials_match were backward + + * dbus/dbus-auth-script.c (_dbus_auth_script_run): support + NO_CREDENTIALS and ROOT_CREDENTIALS + + * dbus/dbus-auth.c (_dbus_auth_do_work): move get_state() routine + into here. Never process more commands after we've reached an + end state; store further data as unused bytes. + + * test/data/auth/*: add more auth tests + + * dbus/dbus-auth-script.c (_dbus_auth_script_run): support EXPECT + command to match exact string and EXPECT_UNUSED to match unused + bytes + + * test/Makefile.am (dist-hook): fix to dist all the test stuff + +2003-02-12 Havoc Pennington + + * dbus/dbus-string.c (_dbus_string_pop_line): fix to also strip + \r off of popped lines + + * dbus/dbus-auth.c (_dbus_auth_test): write code to run auth + scripts + + * dbus/dbus-auth-script.c (_dbus_auth_script_run): when doing a + SEND, append \r\n + +2003-02-12 Havoc Pennington + + * dbus/Makefile.am: remove break-loader from the build, since it + moved. + + * configure.in: add --enable-gcov to turn on coverage profiling + flags and disable optimization + +2003-02-10 Havoc Pennington + + * dbus/dbus-auth-script.c, dbus/dbus-auth-script.h: sync + initial cut at test framework for DBusAuth from laptop. + Doesn't quite work yet but it compiles and I need to get + it off the 266mhz laptop. ;-) + + * dbus/dbus-server-debug.c (_dbus_server_debug_accept_transport): + fix a memleak in error case + +2003-02-12 Anders Carlsson + + * bus/Makefile.am: + * bus/desktop-file.c: + * bus/desktop-file.h: + Add a desktop file parser. + +2003-02-11 Zack Rusin + + * qt/message.[h|cpp]: sample implementation + of the KDE wrapper for DBusMessage + +2003-02-09 Zack Rusin + + * test/bus-test.c: make_it_compile + * doc/dbus-specification.sgml: minimal semantic fix + +2003-02-06 Anders Carlsson + + Release 0.3 + + * NEWS: Update + +2003-02-06 Anders Carlsson + + * dbus/Makefile.am: + * dbus/dbus-break-loader.c: + * test/Makefile.am: + * test/break-loader.c: + Move dbus-break-loader to test/ and rename it to break-loader. + +2003-02-02 Havoc Pennington + + * dbus/dbus-keyring.c, dbus/dbus-keyring.h: template files + for code to manage cookies in your home directory + + * dbus/dbus-sysdeps.c (_dbus_generate_random_bytes): new function + + * dbus/dbus-auth.c (get_state): impose a maximum number of tries + to authenticate, then disconnect the client. + +2003-02-03 Alexander Larsson + + * dbus/dbus-message.c (dbus_message_append_fields): + Correct docs. + +2003-02-02 Anders Carlsson + + * doc/dbus-specification.sgml: + Update address format section. + +2003-02-02 Anders Carlsson + + * test/Makefile.am: + * test/bus-test.c: (get_time), (add_timeout), (remove_timeout), + (message_handler), (new_connection_callback), (loop_quit), + (loop_run), (main): + Add bus test. + +2003-02-02 Anders Carlsson + + * bus/driver.c: (bus_driver_handle_service_exists): + Simplify the code a bit. + + * dbus/dbus-bus.c: (dbus_bus_service_exists): + Fix a silly. + +2003-02-02 Anders Carlsson + + * bus/Makefile.am: + Add libdbus-daemon.la and link to it. + +2003-02-01 James Willcox + + * bus/driver.c: (bus_driver_handle_own_service): + Actually include the service reply code in the message. + +2003-02-02 Anders Carlsson + + * bus/driver.c: (bus_driver_handle_service_exists): + Don't unref the incoming message. + +2003-02-02 Anders Carlsson + + * dbus/dbus.h: Add dbus-address.h and dbus-bus.h + +2003-02-02 Anders Carlsson + + * dbus/dbus-server.c: (dbus_server_listen): + * dbus/dbus-transport.c: (_dbus_transport_open): + ifdef out the calls to the debug transport and server. + +2003-02-02 Alexander Larsson + + * dbus/dbus-watch.c (dbus_watch_get_flags): + Add note in the docs that ERROR or HANGUP won't be returned + and are assumed always on. + + * glib/dbus-gmain.c (add_watch): + Always add IO_ERR | IO_HUP + + * dbus/dbus-message.h: + Add semicolon after dbus_message_iter_get_string_array(). + Makes qt code build again + +2003-02-01 Anders Carlsson + + * bus/driver.c: (create_unique_client_name), + (bus_driver_handle_hello): + Don't take a name, just use a numeric id to identify + each client. + + * dbus/Makefile.am: + * dbus/dbus-bus.c: (dbus_bus_register_client), + (dbus_bus_acquire_service), (dbus_bus_service_exists): + * dbus/dbus-bus.h: + Add new convenience functions for communicating with the bus. + + * dbus/dbus-message.h: + + * dbus/dbus-protocol.h: + Fix a typo. + +2003-02-01 Alexander Larsson + + * dbus/dbus-message.c (dbus_message_append_fields): + Add some more doc comments. + +2003-02-01 Havoc Pennington + + * dbus/dbus-break-loader.c (randomly_modify_length): change + a 4-byte value in the message as if it were a length + + * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): don't set + execute bit on saved files + +2003-02-01 Havoc Pennington + + * dbus/dbus-break-loader.c (main): new program to find messages + that break the loader. + + * dbus/dbus-sysdeps.c (_dbus_string_append_uint): new function + * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): new function + + * dbus/dbus-string.c (_dbus_string_set_byte): new + +2003-01-31 Havoc Pennington + + * dbus/dbus-message.c: refactor the test code to be more general, + in preparation for writing a "randomly permute test cases to + try to break the loader" program. + +2003-01-31 Havoc Pennington + + * doc/dbus-specification.sgml: work on the specification + + * dbus/dbus-message.c (_dbus_message_loader_return_buffer): check + the protocol version of the message. + + * dbus/dbus-protocol.h: drop special _REPLY names, the spec + no longer specifies that. + (DBUS_SERVICE_REPLY_SERVICE_EXISTS): fix flags (1/2/4/8 not + 1/2/3/4) + + * dbus/dbus-marshal.c (_dbus_marshal_get_arg_end_pos): add missing + "break" for DBUS_TYPE_NIL, remove @todo + +2003-01-31 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_set_is_error_reply): rename + just set_is_error/get_is_error as this is a commonly-used + function, and write docs. + +2003-01-31 Anders Carlsson + + * dbus/dbus-address.c: (dbus_address_entry_free): + Free key and value lists. + + * dbus/dbus-internals.c: (_dbus_type_to_string): + Add the types we didn't have. + + * dbus/dbus-marshal.c: (_dbus_marshal_get_arg_end_pos), + (_dbus_marshal_validate_arg): + Add NIL types. + + * dbus/dbus-message.c: (dbus_message_set_sender): + Remove todo about being able to set sender to NULL. + + (dbus_message_set_is_error_reply), + (dbus_message_get_is_error_reply): + * dbus/dbus-message.h: + New functions. + + * dbus/dbus-protocol.h: + Add error reply flag. + + * test/data/valid-messages/opposite-endian.message: + Add NIL type to test. + +2003-01-31 Havoc Pennington + + * doc/dbus-specification.sgml: fully specify the header. Add + flags and major protocol version, and change header/body len to + unsigned. + + * dbus/dbus-message-builder.c (append_saved_length): append length + as uint32 + + * dbus/dbus-message.c (dbus_message_create_header): change header + length and body length to unsigned. Add the new fields from the + spec + (_dbus_message_loader_return_buffer): unsigned header/body len + +2003-01-30 Havoc Pennington + + * dbus/dbus-auth.c: rework to use only REJECTED, no + MECHANISMS + + * doc/dbus-sasl-profile.txt: drop MECHANISMS and just + use REJECTED, suggested by Mark McLoughlin + +2003-01-30 Havoc Pennington + + * dbus/dbus-server.c (dbus_server_listen): @todo about how we need + a better way to report errors here. e.g. "unix address lacks + path" or something. also "no such file" when the path doesn't + exist, etc. + + * dbus/dbus-address.c (dbus_address_entries_free): add @todo about + leaking list nodes + (dbus_parse_address): add @todo about documenting address format, + and allowing , and ; to be escaped + +2003-01-30 Anders Carlsson + + * dbus/Makefile.am: + Add dbus-address.[ch] + + * dbus/dbus-address.c: (dbus_address_entry_free), + (dbus_address_entries_free), (create_entry), + (dbus_address_entry_get_method), (dbus_address_entry_get_value), + (dbus_parse_address), (_dbus_address_test): + * dbus/dbus-address.h: + New files for dealing with address parsing. + + * dbus/dbus-connection.c: + Document timeout functions. + + * dbus/dbus-message.c: + Document dbus_message_new_from_message. + + * dbus/dbus-server-debug.c: + Document. + + * dbus/dbus-server.c: (dbus_server_listen): + Parse address and use correct server implementation. + + * dbus/dbus-string.c: (_dbus_string_find_to), (_dbus_string_test): + * dbus/dbus-string.h: + New function with test. + + * dbus/dbus-test.c: (dbus_internal_symbol_do_not_use_run_tests): + * dbus/dbus-test.h: + Add address tests. + + * dbus/dbus-transport-debug.c: + Document. + + * dbus/dbus-transport.c: (_dbus_transport_open): + Parse address and use correct transport implementation. + +2003-01-30 Havoc Pennington + + * dbus/dbus-message.c: use message->byte_order instead of + DBUS_COMPILER_BYTE_ORDER throughout. + (dbus_message_create_header): pad header to align the + start of the body of the message to 8-byte boundary + + * dbus/dbus-marshal.h: make all the demarshalers take const + DBusString arguments. + + * dbus/dbus-message.c (_dbus_message_loader_return_buffer): + validate message args here, so we don't have to do slow validation + later, and so we catch bad messages as they are incoming. Also add + better checks on header_len and body_len. Also fill in + message->byte_order + + * dbus/dbus-string.c (_dbus_string_validate_utf8): new (not + implemented properly) + (_dbus_string_validate_nul): new function to check all-nul + + * dbus/dbus-marshal.c (_dbus_marshal_get_field_end_pos): rename + get_arg_end_pos and remove all validation + (_dbus_marshal_validate_arg): actually do validation here. + +2003-01-29 Havoc Pennington + + * dbus/dbus-message.c (check_message_handling): fix assertion + failure on set_client_serial + +2003-01-28 Havoc Pennington + + * dbus/dbus-server-debug.c: Add doc section comments + + * dbus/dbus-transport-debug.c: add doc section comments + +2003-01-28 Havoc Pennington + + * dbus/dbus-string.c (_dbus_string_base64_decode): append bytes in + the reverse order from how I had it + (_dbus_string_base64_encode): reverse encoding order. I was + basically byteswapping everything during encoding. + +2003-01-28 Anders Carlsson + + * dbus/dbus-connection-internal.h: + * dbus/dbus-connection.c: (_dbus_connection_add_timeout), + (_dbus_connection_remove_timeout): + Add functions for adding and removing timeouts. + + * dbus/dbus-message.c: (dbus_message_new_from_message): + Add new function that takes a message and creates an exact + copy of it, but with the refcount set to 1. + (check_message_handling): + Fix build error. + + * dbus/dbus-server-protected.h: + * dbus/dbus-server.c: (_dbus_server_init_base), + (_dbus_server_finalize_base), (_dbus_server_add_timeout), + (dbus_server_set_timeout_functions): + (_dbus_server_remove_timeout): + New functions so that a server can add and remove timeouts. + + (dbus_server_listen): + Add commented out call to dbus_server_debug_new. + + * dbus/dbus-timeout.c: (_dbus_timeout_new): + Actually set the handler, doh. + + * dbus/dbus-transport.c: (_dbus_transport_open): + Add commented out call to dbus_transport_debug_client_new. + + * dbus/Makefile.am: + Add dbus-transport-debug.[ch] and dbus-server-debug.[ch] + +2003-01-28 Havoc Pennington + + * dbus/dbus-message.c (check_message_handling): function to check + on the loaded message, iterates over it etc. + +2003-01-28 Havoc Pennington + + * test/Makefile.am (dist-hook): fix make distdir + + * dbus/Makefile.am (TESTS_ENVIRONMENT): fix make check + +2003-01-27 Havoc Pennington + + * dbus/dbus-mempool.c (time_for_size): replace printf with + _dbus_verbose + + * dbus/dbus-message-builder.c (_dbus_message_data_load): allow + empty lines; fix the SAVE_LENGTH stuff to be + START_LENGTH/END_LENGTH so it actually works; couple other + bugfixes + + * test/Makefile.am (dist-hook): add dist-hook for .message files + + * dbus/dbus-string.c (DBUS_STRING_COPY_PREAMBLE): source of a copy + can be constant or locked. + (_dbus_string_free): allow freeing a const string as + documented/intended + + * dbus/dbus-sysdeps.c (_dbus_concat_dir_and_file): utility + + * dbus/dbus-test-main.c (main): take an argument which is the + directory containing test data + + * dbus/dbus-message.c (_dbus_message_test): pass a test_data_dir + argument to this and load all the messages in test/data/ + checking that they can be loaded or not loaded as appropriate. + +2003-01-27 Anders Carlsson + + * bus/dispatch.c: (bus_dispatch_message_handler): + Dispatch messages sent to services. + + * bus/driver.c: (bus_driver_send_service_deleted), + (bus_driver_send_service_created), (bus_driver_send_service_lost), + (bus_driver_send_service_acquired): + Add helper functions for sending service related messages. + + (bus_driver_send_welcome_message): + Send HELLO_REPLY instead of WELCOME. + + (bus_driver_handle_list_services): + Send LIST_SERVICES_REPLY instead of SERVICES. + + (bus_driver_handle_own_service), + (bus_driver_handle_service_exists): + New message handlers. + + (bus_driver_handle_message): + Invoke new message handlers. + + (bus_driver_remove_connection): + Don't remove any services here since that's done automatically + by bus_service_remove_owner now. + + * bus/driver.h: + New function signatures. + + * bus/services.c: (bus_service_add_owner): + Send ServiceAcquired message if we're the only primary owner. + + (bus_service_remove_owner): + Send ServiceAcquired/ServiceLost messages. + + (bus_service_set_prohibit_replacement), + (bus_service_get_prohibit_replacement): + Functions for setting prohibit replacement. + + (bus_service_has_owner): + New function that checks if a connection is in the owner queue of + a certain service. + + * bus/services.h: + Add new function signatures. + + * dbus/dbus-list.c: (_dbus_list_test): + Add tests for _dbus_list_remove_last and traversing the list backwards. + + * dbus/dbus-list.h: + Fix a typo in _dbus_list_get_prev_link, if we're at the first element we can't + go any further, so return NULL then. + + * dbus/dbus-protocol.h: + Add new messages, service flags and service replies. + +2003-01-26 Havoc Pennington + + * dbus/dbus-message-builder.c: implement, completely untested. + + * test/data/*: add data to be used in testing. + ".message" files are our simple loadable text format. + ".message-raw" will be binary dumps of messages. + + * dbus/dbus-string.c (_dbus_string_starts_with_c_str): new + +2003-01-26 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_file_get_contents): new function + + * dbus/dbus-errors.c (dbus_result_to_string): add + file errors + + * dbus/dbus-message-builder.c: new file, will contain code to load + up messages from files. Not implemented yet. + +2003-01-26 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_set_sender): support deleting + the sender by setting to NULL + +2003-01-26 Havoc Pennington + + The unit tests pass, but otherwise untested. If it breaks, the + tests should have been better. ;-) + + * bus/driver.c (bus_driver_handle_hello): return if we disconnect + the connection. + + * dbus/dbus-message.c: redo everything so we maintain + message->header as the only copy of the various fields. + This avoids the possibility of out-of-memory in some cases, + for example dbus_message_lock() can't run out of memory anymore, + and avoids extra copying. Figured I may as well go ahead and do + this since it was busted for dbus_message_lock to not return + failure on OOM, and dbus_message_write_header was totally + unchecked for OOM. Also fixed some random other bugs. + + * dbus/dbus-marshal.c (_dbus_marshal_get_field_end_pos): verify + that strings are nul-terminated. Also, end_pos can be equal + to string length just not greater than, I think. + (_dbus_marshal_set_int32): new function + (_dbus_marshal_set_uint32): new function + (_dbus_marshal_set_string): new function + + * dbus/dbus-connection.c (_dbus_connection_new_for_transport): fix + a warning, init timeout_list to NULL + (dbus_connection_send_message): don't use uninitialized variable + "serial" + + * dbus/dbus-string.c (_dbus_string_replace_len): new function + +2003-01-26 Anders Carlsson + + * bus/driver.c: (bus_driver_handle_hello), + (bus_driver_send_welcome_message): + Plug leaks + +2003-01-26 Anders Carlsson + + * dbus/dbus-auth.c: (process_auth), (_dbus_auth_unref): + * dbus/dbus-connection.c: (_dbus_connection_new_for_transport), + (dbus_connection_unref): + * dbus/dbus-marshal.c: (_dbus_marshal_test): + * dbus/dbus-message.c: (dbus_message_unref), + Plug memory leaks. + + (dbus_message_get_fields): + Remove debugging printout. + + (_dbus_message_loader_return_buffer): + Don't store the header string. + + (_dbus_message_test): + Plug leaks. + +2003-01-26 Richard Hult + + * glib/dbus-gmain.c (dbus_connection_dispatch): Traverse a copy of + the file descriptor list, since it can change under us. + +2003-01-25 Anders Carlsson + + * glib/dbus-gmain.c: (dbus_connection_prepare), + (dbus_connection_check), (dbus_connection_dispatch), (add_watch), + (remove_watch), (dbus_connection_hookup_with_g_main): + Rewrite the glib handling to use its own GSource instead of a + GIOChannel so we can catch messages put in the queue while waiting + for a reply. + +2003-01-25 Anders Carlsson + + * bus/Makefile.am: + * bus/connection.c: (connection_disconnect_handler), + (connection_watch_callback), (bus_connection_setup): + * bus/dispatch.c: (send_one_message), + (bus_dispatch_broadcast_message), (bus_dispatch_message_handler), + (bus_dispatch_add_connection), (bus_dispatch_remove_connection): + * bus/dispatch.h: + * bus/driver.c: (bus_driver_send_service_deleted), + (bus_driver_send_service_created), (bus_driver_handle_hello), + (bus_driver_send_welcome_message), + (bus_driver_handle_list_services), (bus_driver_remove_connection), + (bus_driver_handle_message): + * bus/driver.h: + Refactor code, put the message dispatching in its own file. Use + _DBUS_HANDLE_OOM. Also send ServiceDeleted messages when a client + is disconnected. + +2003-01-25 Anders Carlsson + + * dbus/dbus-internals.h: + Add _DBUS_HANDLE_OOM macro, it doesn't do anything currently. + + * dbus/dbus-message.c: (dbus_message_get_sender): + * dbus/dbus-message.h: + Implement dbus_message_get_sender. + + * dbus/dbus-protocol.h: + Add message and service defines. + +2003-01-25 Anders Carlsson + + * dbus/dbus-connection.c: (dbus_connection_send_message): + * dbus/dbus-message-internal.h: + * dbus/dbus-message.c: (_dbus_message_get_client_serial), + (dbus_message_write_header): + Remove _dbus_messag_unlock and don't set the client serial on a + message if one already exists. + +2003-01-24 Havoc Pennington + + * dbus/dbus-list.c (alloc_link): put a thread lock on the global + list_pool + + * bus/driver.c (bus_driver_handle_list_services): fix a leak + on OOM + +2003-01-25 Anders Carlsson + + * dbus/dbus-list.c: (alloc_link), (free_link): + Use a memory pool for the links. + +2003-01-25 Anders Carlsson + + * bus/connection.c: (bus_connection_foreach): + * bus/connection.h: + Add new bus_connection_foreach function. + + * bus/driver.c: (send_one_message), (bus_driver_broadcast_message): + Add function that broadcasts a message to all clients. + + (bus_driver_send_service_created), (bus_driver_handle_hello), + (bus_driver_send_welcome_message), + (bus_driver_handle_list_services), (bus_driver_message_handler): + Implement functions that take care of listing services, and notifying + clients when new services are created. + + * bus/services.c: (bus_services_list): + * bus/services.h: + Add new function that returns an array of strings with the currently + registered services. + + * glib/dbus-glib.h: + * glib/dbus-gmain.c: + Update copyright year. + +2003-01-25 Anders Carlsson + + * dbus/dbus-connection.c: (dbus_connection_send_message): + Unlock the message in case it was sent earlier. + + (dbus_connection_send_message_with_reply_and_block): + Remove the reply message from the list. + + * dbus/dbus-marshal.c: (_dbus_demarshal_string_array): + Set array_len and new_pos correctly. + + (_dbus_marshal_test): + Remove debug output. + + * dbus/dbus-message-internal.h: + * dbus/dbus-message.c: (_dbus_message_get_reply_serial): + New function that returns the reply serial. + + (_dbus_message_unlock): + New function that unlocks a message and resets its header. + + (dbus_message_append_string_array), + (dbus_message_get_fields_valist), + (dbus_message_iter_get_field_type), + (dbus_message_iter_get_string_array), + (dbus_message_get_fields), + (dbus_message_append_fields_valist): + Handle string arrays. + + (dbus_message_set_sender): + Make this function public since the bus daemon needs it. + + (decode_header_data): + Set the reply serial to -1 initially. + + * dbus/dbus-message.h: + Add dbus_message_set_sender. + +2003-01-24 Havoc Pennington + + * doc/dbus-specification.sgml: add some stuff + +2003-01-22 Havoc Pennington + + * doc/dbus-specification.sgml: Start to document the protocol. + +2003-01-22 Havoc Pennington + + * dbus/dbus-connection.c + (dbus_connection_send_message_with_reply_and_block): add some @todo + + * bus/driver.c (bus_driver_add_connection): add a FIXME about memleak + +2003-01-21 Havoc Pennington + + (patch untested because can't compile) + + * bus/driver.c (create_unique_client_name): make this function + never recycle client names. Also, caller should initialize + the DBusString. + + * dbus/dbus-sysdeps.c (_dbus_get_current_time): new function + +2003-01-21 Anders Carlsson + + * dbus/dbus-marshal.c: (_dbus_marshal_double), + (_dbus_marshal_int32), (_dbus_marshal_uint32), + (_dbus_marshal_int32_array), (_dbus_marshal_uint32_array), + (_dbus_marshal_double_array), (_dbus_marshal_string_array), + (_dbus_demarshal_int32_array), (_dbus_demarshal_uint32_array), + (_dbus_demarshal_double_array), (_dbus_demarshal_string_array), + (_dbus_marshal_get_field_end_pos), (_dbus_marshal_test): + * dbus/dbus-marshal.h: + * dbus/dbus-protocol.h: + Add support for marshalling and demarshalling integer, double + and string arrays. + +2003-01-21 Anders Carlsson + + * bus/Makefile.am: + Add driver.[ch] + + * bus/connection.c: (connection_disconnect_handler): + Remove the connection from the bus driver's list. + + (connection_watch_callback): Dispatch messages. + + (free_connection_data): Free connection name. + + (bus_connection_setup): Add connection to the bus driver's list. + (bus_connection_remove_owned_service): + (bus_connection_set_name), (bus_connection_get_name): + Add functions for setting and getting the connection's name. + + * bus/connection.h: + Add function headers. + + * bus/driver.c: (create_unique_client_name), + (bus_driver_handle_hello_message), + (bus_driver_send_welcome_message), (bus_driver_message_handler), + (bus_driver_add_connection), (bus_driver_remove_connection): + * bus/driver.h: + * bus/main.c: + * bus/services.c: (bus_service_free): + * bus/services.h: + New file that handles communication and registreation with the bus + itself. + +2003-01-21 Anders Carlsson + + * dbus/dbus-connection.c: (dbus_connection_send_message): + Add a new client_serial parameter. + + (dbus_connection_send_message_with_reply): + Remove a @todo since we've implemented the blocking function. + + (dbus_connection_send_message_with_reply_and_block): + New function that sends a message and waits for a reply and + then returns the reply. + + * dbus/dbus-connection.h: + Add new functions. + + * dbus/dbus-errors.c: (dbus_result_to_string): + * dbus/dbus-errors.h: + Add new DBUS_RESULT. + + * dbus/dbus-message-internal.h: + * dbus/dbus-message.c: (_dbus_message_get_reply_serial), + (_dbus_message_set_sender), (dbus_message_write_header), + (dbus_message_new_reply), (decode_header_data), + (_dbus_message_loader_return_buffer), (_dbus_message_test): + * dbus/dbus-message.h: + Add new functions that set the reply serial and sender. + Also marshal and demarshal them correctly and add test. + + * dbus/dbus-protocol.h: + Add new DBUS_MESSAGE_TYPE_SENDER. + + * glib/dbus-glib.h: + * glib/dbus-gmain.c: (watch_callback), (free_callback_data), + (add_watch), (remove_watch), (add_timeout), (remove_timeout), + (dbus_connection_hookup_with_g_main): + * glib/test-dbus-glib.c: (main): + Rewrite to use GIOChannel and remove the GSource crack. + + * test/echo-client.c: (main): + * test/watch.c: (check_messages): + Update for changed APIs + +2003-01-19 Anders Carlsson + + * dbus/Makefile.am: Add dbus-timeout.[cħ] + + * dbus/dbus-connection.c: (_dbus_connection_new_for_transport): + Create a DBusTimeoutList. + (dbus_connection_set_timeout_functions): Add new function to + set timeout callbacks + + * dbus/dbus-connection.h: Add public DBusTimeout API. + + * dbus/dbus-message.c: (dbus_message_get_service): + * dbus/dbus-message.h: New function. + + * dbus/dbus-server.c: Fix small doc typo. + + * dbus/dbus-timeout.[ch]: New files for mainloop timeouts. + +2003-01-19 Anders Carlsson + + * dbus/dbus-string.c (_dbus_string_move_len): Don't delete all + of the string, just as long as specified. + +2003-01-19 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_get_is_authenticated): + new function + + * dbus/dbus-server.c (dbus_server_set_max_connections) + (dbus_server_get_max_connections, dbus_server_get_n_connections): + keep track of current number of connections, and add API for + setting a max (but haven't implemented enforcing the max yet) + +2003-01-18 Havoc Pennington + + * dbus/dbus-transport-unix.c (unix_do_iteration): only do the + reading/writing if read_watch != NULL or write_watch != NULL. + + * dbus/dbus-message.c (_dbus_message_loader_return_buffer): fix + the message loader code to actually load message->header and + message->body into the newly-created message. + + * dbus/dbus-transport-unix.c (check_write_watch): fix a mem leak + in OOM case + + * dbus/dbus-connection.c (dbus_connection_set_max_message_size) + (dbus_connection_get_max_message_size) + (dbus_connection_set_max_live_messages_size) + (dbus_connection_get_max_live_messages_size): implement some + resource limitation functions + + * dbus/dbus-resources.c: new file implementing some of the + resource limits stuff + + * dbus/dbus-message.c (dbus_message_iter_get_byte_array): add + missing docs, add @todo to handle OOM etc. + + * dbus/dbus-marshal.c (_dbus_demarshal_byte_array): add missing + docs + +2003-01-18 Havoc Pennington + + * dbus/dbus-connection.c (dbus_connection_unref): disconnect the + connection if it hasn't been already. + + * dbus/dbus-connection.h: kill off the idea of an ErrorFunction, + replace with DisconnectFunction. + +2003-01-18 Havoc Pennington + + Building --disable-verbose-mode --disable-asserts --disable-tests + cuts the library from 112K to 45K or so + + * configure.in: check for varargs macro support, + add --enable-verbose-mode, --enable-asserts. + + * dbus/dbus-internals.h (_dbus_assert): support + DBUS_DISABLE_ASSERT + (_dbus_verbose): support DBUS_ENABLE_VERBOSE_MODE + +2003-01-18 Havoc Pennington + + * dbus/dbus-test.c: include config.h so that tests actually run + + * dbus/dbus-string.c: add assertions that stuff is 8-byte aligned, + so the failure mode when that assumption fails will be plenty + obvious. + +2003-01-18 Havoc Pennington + + * configure.in: default --enable-tests to $USE_MAINTAINER_MODE + + * dbus/Makefile.am: fix it up so dubs-test-main.c is included in + the distribution + + * test/Makefile.am: don't use special variable "TESTS" for echo-* + since we don't want to use those in make check + +2003-01-15 Havoc Pennington + + Release 0.2 + + * NEWS: update + +2003-01-15 Havoc Pennington + + * test/Makefile.am: fix so that test source code ends up in the + distribution on make distcheck + +2003-01-15 Havoc Pennington + + Release 0.1. + + * NEWS: update + +2003-01-15 Havoc Pennington + + * dbus/dbus-test.c (dbus_internal_symbol_do_not_use_run_tests): + fix build when --disable-tests + + * Makefile.am (EXTRA_DIST): put HACKING in here + + * HACKING: document procedure for making a tarball release. + +2003-01-14 Anders Carlsson + + * bus/connection.c: (connection_error_handler), + (bus_connection_setup): + * bus/main.c: (main): + Make sure that the DBusConnectionData struct is NULLed + out to prevent a segfault. + + * dbus/dbus-errors.c: (dbus_result_to_string): + * dbus/dbus-errors.h: + * dbus/dbus-message.c: (dbus_message_get_fields), + (dbus_message_get_fields_valist), (_dbus_message_test): + * dbus/dbus-message.h: + Make dbus_message_get_fields return a result code so we can + track invalid fields as well as oom. + +2003-01-11 Havoc Pennington + + * configure.in: change --enable-test/--enable-ansi action-if-given + to enable_foo=$enableval instead of enable_foo=yes + +2003-01-08 Havoc Pennington + + * dbus/dbus-string.c (_dbus_string_align_length): new function + + * dbus/dbus-test-main.c: move main() for test app here + * dbus/dbus-test.c + (dbus_internal_symbol_do_not_use_run_tests): we have to export a + symbol to run tests, because dbus-test isn't in the main + library + + Code review nitpicks. + + * dbus/dbus-message.c (dbus_message_write_header): add newlines + for people with narrow emacs ;-). Assert client_serial was filled + in. Assert message->name != NULL. + (dbus_message_append_fields): have "first_field_type" arg separate + from va list, needed for C++ binding that also uses varargs IIRC + and helps with type safety + (dbus_message_new): add @todo about using DBusString to store + service/name internally + (dbus_message_new): don't leak ->service and ->name on OOM later + in the function + (dbus_message_unref): free the service name + (dbus_message_get_fields): same change to varargs + i.e. first_field_type + (_dbus_message_loader_return_buffer): assert that the message data + is aligned (if not it's a bug in our code). Put in verbose griping + about why we set corrupted = TRUE. + (decode_header_data): add FIXME that char* is evil. Was going to + add FIXME about evil locale-specific string.h strncmp, but just + switched to wacky string-as-uint32 optimization. Move check for + "no room for field name" above get_const_data_len() to avoid + assertion failure in get_const_data_len if we have trailing 2 + bytes or the like. Check for service and name fields being + provided twice. Don't leak service/name on error. Require field + names to be aligned to 4 bytes. + + * dbus/dbus-marshal.c: move byte swap stuff to header + (_dbus_pack_int32): uscore-prefix + (_dbus_unpack_int32): uscore-prefix + (_dbus_unpack_uint32): export + (_dbus_demarshal_string): add @todo complaining about use of + memcpy() + (_dbus_marshal_get_field_end_pos): add @todo about bad error + handling allowing corrupt data to go unchecked + +2003-01-08 Havoc Pennington + + * dbus/dbus-transport-unix.c (unix_do_iteration): add read/write + to the select() as needed for authentication. (should be using + _dbus_poll() not select, but for another day) + + * dbus/dbus.h: include dbus/dbus-protocol.h + +2003-01-08 Anders Carlsson + + * dbus/Makefile.am (dbusinclude_HEADERS): Install + dbus-connection.h + +2003-01-08 Anders Carlsson + + * dbus/dbus-internals.c: (_dbus_type_to_string): + New function that returns a string describing a type. + + * dbus/dbus-marshal.c: (_dbus_demarshal_byte_array): + * dbus/dbus-marshal.h: + * dbus/dbus-message.c: (dbus_message_get_fields_valist), + (dbus_message_iter_get_field_type), (dbus_message_iter_get_double), + (dbus_message_iter_get_byte_array): + * dbus/dbus-message.h: + Add new convenience functions for appending and getting message fields. + Also add demarshalling routines for byte arrays. + +2003-01-07 Anders Carlsson + + * dbus/dbus-connection-internal.h: + * dbus/dbus-connection.c: (_dbus_connection_new_for_transport), + (_dbus_connection_get_next_client_serial), + (dbus_connection_send_message): + * dbus/dbus-internals.h: + * dbus/dbus-marshal.c: (unpack_uint32), (dbus_unpack_int32), + (dbus_pack_int32), (_dbus_marshal_double), (_dbus_marshal_int32), + (_dbus_marshal_uint32), (_dbus_demarshal_double), + (_dbus_demarshal_int32), (_dbus_demarshal_uint32), + (_dbus_demarshal_string), (_dbus_marshal_get_field_end_pos), + (_dbus_verbose_bytes), (_dbus_marshal_test): + * dbus/dbus-marshal.h: + * dbus/dbus-message-internal.h: + * dbus/dbus-message.c: (_dbus_message_set_client_serial), + (dbus_message_write_header), (_dbus_message_lock), + (dbus_message_new), (dbus_message_ref), (dbus_message_unref), + (dbus_message_get_name), (dbus_message_append_int32), + (dbus_message_append_uint32), (dbus_message_append_double), + (dbus_message_append_string), (dbus_message_append_byte_array), + (dbus_message_get_fields_iter), (dbus_message_iter_ref), + (dbus_message_iter_unref), (dbus_message_iter_has_next), + (dbus_message_iter_next), (dbus_message_iter_get_field_type), + (dbus_message_iter_get_string), (dbus_message_iter_get_int32), + (dbus_message_iter_get_uint32), (dbus_message_iter_get_double), + (decode_header_data), (_dbus_message_loader_return_buffer), + (message_iter_test), (_dbus_message_test): + * dbus/dbus-message.h: + * dbus/dbus-protocol.h: + * dbus/dbus-test.c: (main): + * dbus/dbus-test.h: + * glib/test-dbus-glib.c: (message_handler), (main): + * test/echo-client.c: (main): + * test/watch.c: (check_messages): + Make messages sendable and receivable for real. + +2003-01-07 Anders Carlsson + + * dbus/dbus-marshal.c: (_dbus_marshal_double), + (_dbus_marshal_string), (_dbus_marshal_byte_array): + * dbus/dbus-message.c: (dbus_message_append_int32), + (dbus_message_append_uint32), (dbus_message_append_double), + (dbus_message_append_string), (dbus_message_append_byte_array): + Handle OOM restoration. + +2003-01-07 Anders Carlsson + + * dbus/dbus-marshal.c: (_dbus_marshal_string), + (_dbus_demarshal_string), (_dbus_marshal_test): + * dbus/dbus-marshal.h: + * dbus/dbus-message.c: (dbus_message_get_name), + Document these functions. + + (dbus_message_append_int32), (dbus_message_append_uint32), + (dbus_message_append_double), (dbus_message_append_string), + (dbus_message_append_byte_array): + * dbus/dbus-message.h: + Add functions for adding message fields of different types. + + * dbus/dbus-protocol.h: + Add the different types. + +2003-01-05 Havoc Pennington + + * bus/connection.c: implement routines for handling connections, + first thing is keeping a list of owned services on each connection + and setting up watches etc. + + * bus/services.c: implement a mapping from service names to lists + of connections + + * dbus/dbus-hash.c: add DBUS_HASH_POINTER + + * dbus/dbus-threads.c (dbus_static_mutex_lock): add functions + to use static mutexes for global data + + * dbus/dbus-connection.c (dbus_connection_set_data): add new + collection of functions to set/get application-specific data + on the DBusConnection. + +2003-01-04 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_sleep_milliseconds): new function + (_dbus_poll): new function + + * dbus/dbus-internals.h (_DBUS_STRUCT_OFFSET): new macro + copied from GLib + + * bus/loop.c: initial code for the daemon main loop + +2003-01-04 Havoc Pennington + + * test/watch.c (error_handler): make it safe if the error handler + is called multiple times (if we s/error handler/disconnect + handler/ we should just guarantee it's called only once) + + * dbus/dbus-transport.c (_dbus_transport_disconnect): call the + error handler on disconnect (it's quite possible we should + just change the error handler to a "disconnect handler," I'm + not sure we have any other meaningful errors) + + * configure.in: check for getpwnam_r + + * dbus/dbus-transport.c, dbus/dbus-transport-unix.c, + dbus/dbus-auth.c: add credentials support, add EXTERNAL auth + mechanism as in SASL spec, using socket credentials + + * dbus/dbus-sysdeps.c (_dbus_read_credentials_unix_socket): new function + (_dbus_send_credentials_unix_socket): new function + + * dbus/dbus-sysdeps.c (_dbus_accept_unix_socket): rename just + dbus_accept() + (_dbus_write): only check errno if <0 returned + (_dbus_write_two): ditto + +2003-01-02 Anders Carlsson + + * dbus/dbus-marshal.c: (_dbus_marshal_utf8_string), + (_dbus_marshal_byte_array), (_dbus_demarshal_utf8_string), + (_dbus_marshal_test): + * dbus/dbus-marshal.h: + Add _dbus_marshal_byte_array and rename _dbus_marshal_string + to _dbus_marshal_utf8_string. Also fix some tests. + +2002-12-28 Harri Porten + + * configure.in: added check for C++ compiler and a very cheesy + check for the Qt integration + + * Makefile.am (SUBDIRS): compile qt subdir if support is enabled + + * qt/Makefile.am: added + + * qt/.cvsignore: added + + * qt/dbus-qthread.cc, qt/dbus-qthread.cpp: renamed former to + latter, added #ifdef QT_THREAD_SUPPORT guard. + + * dbus/Makefile.am: added missing headers for make dist + +2002-12-28 Kristian Rietveld + + * dbus/Makefile.am: fixup export-symbols-regex. + +2002-12-27 Anders Carlsson + + * acinclude.m4: Add this file and put the + PKG_CHECK_MODULE macro in it. + +2002-12-27 Anders Carlsson + + * dbus/dbus-marshal.c: (_dbus_marshal_string), + (_dbus_demarshal_double), (_dbus_demarshal_int32), + (_dbus_demarshal_uint32), (_dbus_demarshal_string), + (_dbus_marshal_test): + Make the demarshalling routines align the pos argument. + Add string marshalling tests and fix the obvious bugs + discovered. + +2002-12-26 Havoc Pennington + + * dbus/dbus-auth.c: fixes fixes fixes + + * dbus/dbus-transport-unix.c: wire up support for + encoding/decoding data on the wire + + * dbus/dbus-auth.c (_dbus_auth_encode_data) + (_dbus_auth_decode_data): append to target string + instead of nuking it. + +2002-12-26 Havoc Pennington + + * dbus/dbus-marshal.h (DBUS_COMPILER_BYTE_ORDER): #ifdef + WORDS_BIGENDIAN then compiler byte order is DBUS_BIG_ENDIAN, + doh + + * dbus/dbus-marshal.c: Add macros to do int swapping in-place and + avoid swap_bytes() overhead (ignoring possible assembly stuff for + now). Main point is because I wanted unpack_uint32 to implement + _dbus_verbose_bytes + (_dbus_verbose_bytes): new function + + * dbus/dbus-string.c (_dbus_string_validate_ascii): new function + + * dbus/dbus-message.c (_dbus_message_loader_get_is_corrupted): add + mechanism to handle a corrupt message stream + (_dbus_message_loader_new): fix preallocation to only prealloc, + not prelengthen + + * dbus/dbus-string.c (_dbus_string_skip_blank): fix this function + (_dbus_string_test): enhance tests for copy/move and fix the + functions + + * dbus/dbus-transport-unix.c: Hold references in more places to + avoid reentrancy problems + + * dbus/dbus-transport.c: ditto + + * dbus/dbus-connection.c (dbus_connection_dispatch_message): don't + leak reference count in no-message case + + * test/watch.c (do_mainloop): handle adding/removing watches + during iteration over the watches. Also, ref the connection/server + stored on a watch, so we don't try to mangle a destroyed one. + + * dbus/dbus-transport-unix.c (do_authentication): perform + authentication + + * dbus/dbus-auth.c (get_state): add a state + AUTHENTICATED_WITH_UNUSED_BYTES and return it if required + (_dbus_auth_get_unused_bytes): append the unused bytes + to the passed in string, rather than prepend + + * dbus/dbus-transport.c (_dbus_transport_init_base): create + the auth conversation DBusAuth + + * dbus/dbus-transport-unix.c (_dbus_transport_new_for_fd) + (_dbus_transport_new_for_domain_socket): when creating a + transport, pass in whether it's a client-side or server-side + transport so we know which DBusAuth to create + +2002-12-03 Havoc Pennington + + * dbus/dbus-transport-unix.c (unix_finalize): finalize base + _after_ finalizing the derived members + (unix_connection_set): unref watch if we fail to add it + + * dbus/dbus-connection.c (dbus_connection_unref): delete the + transport first, so that the connection owned by the + transport will be valid as the transport finalizes. + + * dbus/dbus-transport-unix.c (unix_finalize): free the write_watch + if necessary, and remove watches from the connection. + + * dbus/dbus-watch.c (_dbus_watch_list_free): improve a comment + +2002-12-26 Anders Carlsson + + * dbus/dbus-marshal.c: (_dbus_marshal_string), + (_dbus_demarshal_double), (_dbus_demarshal_int32), + (_dbus_demarshal_uint32), (_dbus_demarshal_string), + (_dbus_marshal_test): + * dbus/dbus-marshal.h: + Add string marshal functions and have the demarshal functions + return the new position. + +2002-12-25 Havoc Pennington + + * doc/dbus-sasl-profile.txt: docs on the authentication protocol, + it is a simple protocol that just maps directly to SASL. + + * dbus/dbus-auth.h, dbus/dbus-auth.c: authentication protocol + initial implementation, not actually used yet. + + * dbus/dbus-string.c (_dbus_string_find): new function + (_dbus_string_equal): new function + (_dbus_string_base64_encode): new function + (_dbus_string_base64_decode): new function + +2002-12-25 Anders Carlsson + + * dbus/Makefile.am: + * dbus/dbus-marshal.c: (swap_bytes), (_dbus_marshal_double), + (_dbus_marshal_int32), (_dbus_marshal_uint32), + (_dbus_demarshal_double), (_dbus_demarshal_int32), + (_dbus_demarshal_uint32), (_dbus_marshal_test): + * dbus/dbus-marshal.h: + * dbus/dbus-protocol.h: + * dbus/dbus-test.c: (main): + * dbus/dbus-test.h: + Add un-optimized marshalling/demarshalling routines. + +2002-12-25 Harri Porten + + * qt/dbus-qt.h: adjusted ctor and getter to KDE/Qt conventions + +2002-12-24 Zack Rusin + + * qt/dbus-qthread.cc: adding - integrates QMutex into Dbus + * qt/dbus-qt.h: skeleton with two sample implemenatation of the + main loop stuff + +2002-12-24 Havoc Pennington + + * glib/dbus-gthread.c: fix include + + * glib/dbus-glib.h: rename DBusMessageHandler for now. + I think glib API needs to change, though, as you don't + want to use DBusMessageFunction, you want to use the + DBusMessageHandler object. Probably + dbus_connection_open_with_g_main_loop() + and dbus_connection_setup_g_main_loop() or something like that + (but think of better names...) that just create a connection + that has watch/timeout functions etc. already set up. + + * dbus/dbus-connection.c + (dbus_connection_send_message_with_reply): new function just to + show how the message handler helps us deal with replies. + + * dbus/dbus-list.c (_dbus_list_remove_last): new function + + * dbus/dbus-string.c (_dbus_string_test): free a string that + wasn't + + * dbus/dbus-hash.c: use memory pools for the hash entries + (rebuild_table): be more paranoid about overflow, and + shrink table when we can + (_dbus_hash_test): reduce number of sprintfs and write + valid C89. Add tests for case where we grow and then + shrink the hash table. + + * dbus/dbus-mempool.h, dbus/dbus-mempool.c: memory pools + + * dbus/dbus-connection.c (dbus_connection_register_handler) + (dbus_connection_unregister_handler): new functions + + * dbus/dbus-message.c (dbus_message_get_name): new + + * dbus/dbus-list.c: fix docs typo + + * dbus/dbus-message-handler.h, dbus/dbus-message-handler.c: + an object representing a handler for messages. + +2002-12-16 Anders Carlsson + + * glib/dbus-glib.h: + * glib/dbus-gthread.c: (dbus_gthread_init): + Don't use the gdbus prefix for public functions. + +2002-12-16 Anders Carlsson + + * Makefile.am: + * configure.in: + Add GLib checks and fixup .pc files + + * glib/Makefile.am: + * glib/dbus-glib.h: + * glib/dbus-gmain.c: (gdbus_connection_prepare), + (gdbus_connection_check), (gdbus_connection_dispatch), + (gdbus_add_connection_watch), (gdbus_remove_connection_watch), + (dbus_connection_gsource_new): + * glib/dbus-gthread.c: (dbus_gmutex_new), (dbus_gmutex_free), + (dbus_gmutex_lock), (dbus_gmutex_unlock), (dbus_gthread_init): + * glib/test-dbus-glib.c: (message_handler), (main): + Add GLib support. + +2002-12-15 Harri Porten + + * autogen.sh: check for libtoolize before attempting to use it + + * dbus/dbus-transport-unix.c: include for timeval + struct. + + * .cvsignore: ignore more stamp files + + * dbus/dbus-watch.c (_dbus_watch_list_new): fixed doc error + + * test/Makefile.am: added -I$(top_srcdir) to be able to compile + without make install. + +2002-12-15 Havoc Pennington + + * dbus/dbus-threads.c: add thread stubs that a higher library + layer can fill in. e.g. the GLib wrapper might fill them in with + GThread stuff. We still need to use this thread API to + thread-safe-ize the library. + +2002-12-12 Havoc Pennington + + * dbus/dbus-transport-unix.c, dbus/dbus-server-unix.c: use the + below new interfaces and include fewer system headers. + + * dbus/dbus-sysdeps.c (_dbus_read): new function + (_dbus_write): new function + (_dbus_write_two): new function + (_dbus_connect_unix_socket): new function + (_dbus_listen_unix_socket): new function + + * dbus/dbus-message-internal.h: change interfaces to use + DBusString + +2002-12-11 Havoc Pennington + + * dbus/dbus-types.h: add dbus_unichar + + * dbus/dbus-internals.c (_dbus_verbose): use _dbus_getenv + + * dbus/dbus-connection.c (dbus_connection_send_message): return + TRUE on success + + * dbus/dbus-transport.c: include dbus-watch.h + + * dbus/dbus-connection.c: include dbus-message-internal.h + + * HACKING: add file with coding guidelines stuff. + + * dbus/dbus-string.h, dbus/dbus-string.c: Encapsulate all string + handling here, for security purposes (as in vsftpd). Not actually + using this class yet. + + * dbus/dbus-sysdeps.h, dbus/dbus-sysdeps.c: Encapsulate all + system/libc usage here, as in vsftpd, for ease of auditing (and + should also simplify portability). Haven't actually moved all the + system/libc usage into here yet. + +2002-11-25 Havoc Pennington + + * dbus/dbus-internals.c (_dbus_verbose): fix to not + always print the first verbose message. + +2002-11-24 Havoc Pennington + + * test/echo-client.c, test/echo-server.c: cheesy test + clients. + + * configure.in (AC_CHECK_FUNCS): check for writev + + * dbus/dbus-message.c (_dbus_message_get_network_data): new + function + + * dbus/dbus-list.c (_dbus_list_foreach): new function + + * dbus/dbus-internals.c (_dbus_verbose): new function + + * dbus/dbus-server.c, dbus/dbus-server.h: public object + representing a server that listens for connections. + + * dbus/.cvsignore: create + + * dbus/dbus-errors.h, dbus/dbus-errors.c: + public API for reporting errors + + * dbus/dbus-connection.h, dbus/dbus-connection.c: + public object representing a connection that + sends/receives messages. (Same object used for + both client and server.) + + * dbus/dbus-transport.h, dbus/dbus-transport.c: + Basic abstraction for different kinds of stream + that we might read/write messages from. + +2002-11-23 Havoc Pennington + + * dbus/dbus-internals.h (_DBUS_INT_MAX): add _DBUS_INT_MIN + _DBUS_INT_MAX + + * dbus/dbus-test.c (main): add list test, and include + dbus-test.h as intended + + * dbus/dbus-hash.c (_dbus_hash_table_remove_string) + (_dbus_hash_table_remove_int): return value indicates + whether the entry existed to remove + + * dbus/dbus-list.c: add linked list utility class, + with docs and tests + + * dbus/dbus-hash.c: add TODO item about shrinking the hash bucket + array sometimes. + +2002-11-23 Havoc Pennington + + * Doxyfile.in (INCLUDE_FILE_PATTERNS): expand DBUS_BEGIN_DECLS/ + DBUS_END_DECLS to nothing, that should fix this once and for all + + * Doxyfile.in (JAVADOC_AUTOBRIEF): set to YES + + * dbus/dbus-message.c, dbus/dbus-hash.c: + add some missing @brief + +2002-11-23 Havoc Pennington + + * dbus/dbus-message.h: put semicolons after DEBUG_BEGIN_DECLS + to avoid confusing Doxygen + + * dbus/dbus-hash.c: @} not }@ + + * dbus/dbus-message.c (struct DBusMessage): split out + internals docs + +2002-11-23 Havoc Pennington + + * configure.in: pile on more warning flags if using gcc + + * Doxyfile.in (EXTRACT_STATIC): set to NO, so we don't have + to document static functions + + * configure.in: add summary to end of configure so it + looks nice and attractive + + * dbus/dbus-hash.c: finish implementation and write unit + tests and docs + + * configure.in: add --enable-tests to enable unit tests + + * dbus/dbus-test.c: test program to run unit tests + for all files in dbus/*, initially runs a test for + dbus-hash.c + + * dbus/dbus-internals.h: file to hold some internal utility stuff + +2002-11-22 Havoc Pennington + + * dbus/dbus-hash.c: copy in Tcl hash table, not yet + "ported" away from Tcl + + * dbus/dbus-types.h: header for types such as dbus_bool_t + +2002-11-22 Havoc Pennington + + * dbus/dbus.h: fixups for doc warnings + + * Doxyfile.in (FILE_PATTERNS): we need to scan .h to pick up + macros + (QUIET): make it quiet so we can see warnings + + * dbus/dbus-memory.c: teach D-BUS to allocate and free memory + +2002-11-22 Havoc Pennington + + * Makefile.am: include "Doxyfile" target in all-local + + * configure.in: generate the Doxyfile + + * Doxyfile.in: move Doxyfile here, so we can use + configure to generate a Doxyfile with the right + version number etc. + +2002-11-22 Havoc Pennington + + * dbus/dbus-message.c: move inline docs into .c file + + * Doxyfile (OUTPUT_DIRECTORY): move output to doc/api + so all docs are under doc/ + (MAN_EXTENSION): generate man pages. Use extension + ".3dbus" which matches ".3qt" on my system, + I guess this is OK, I don't know really. + (FILE_PATTERNS): look for .c files not .h, makes sense + for plain C I think + +2002-11-22 Havoc Pennington + + * Makefile.am (SUBDIRS): rename subdir "server" to "bus" + because any app can be a server, and any app can be a client, + the bus is a special kind of server. + +Thu Nov 21 23:35:31 2002 Zack Rusin + + * Doxyfile : adding. Still needs Makefile rules to be generated + automatically (just run "doxygen" in the toplevel dir for now to + generate docs) + + * dbus/dbus-message.h : Adding sample docs (javadoc since + resembles gtk-doc a little more) + + * dbus/dbus.h : Adding sample docs + +2002-11-21 Havoc Pennington + + * dbus/Makefile.am (INCLUDES): define DBUS_COMPILATION + so we can allow ourselves to include files directly, + instead of having to use dbus.h + + * dbus/dbus.h: fill in + + * dbus/dbus-message.h: sketch out a sample header file. + Include griping if you include it directly instead of + via dbus.h + + * dbus/dbus-macros.h: new file with macros for extern "C", + TRUE/FALSE, NULL, etc. + + * doc/file-boilerplate.c: put include guards in here + +2002-11-21 Havoc Pennington + + * doc/file-boilerplate.c: include both AFL and GPL boilerplate. + + * COPYING: include the GPL as well, and license code + under both AFL and GPL. + +2002-11-21 Havoc Pennington + + * acconfig.h: get rid of this + + * autogen.sh (run_configure): add --no-configure option + + * configure.in: remove AC_ARG_PROGRAM to make + autoconf complain less. add AC_PREREQ. + add AC_DEFINE third arg. + +2002-11-21 Anders Carlsson + + * doc/Makefile.am: + Fix references so we can distcheck. + +2002-11-21 Havoc Pennington + + * Initial module creation + diff --git a/ChangeLog.pre-1-2 b/ChangeLog.pre-1-2 new file mode 100644 index 00000000..b2204480 --- /dev/null +++ b/ChangeLog.pre-1-2 @@ -0,0 +1,2027 @@ +2008-04-04 John (J5) Palmieri + + * Released 1.2.1 + +2008-04-03 John (J5) Palmieri + + Patch from Sumit , comments added + + * dbus/dbus-transport.c(_dbus_transport_open): fix mem leak + +2008-04-03 John (J5) Palmieri + + * dbus/dbus-connection.c (dbus_connection_send): add documentation + to describe when to call dbus_connection_flush and + dbus_connection_unref after a call to dbus_connection_send is made + Initial wording by Stanislav Brabec + (fd.o bug#13558) + +2008-04-03 John (J5) Palmieri + + Patch from Kimmo Hämäläinen + + * bus/expirelist.c + (do_expiration_with_current_time): calculate correct min wait time + and next interval + (bus_expire_list_add, bus_expire_list_add_link): if the timeout is + disabled when we add an item to the expire list, enable the timeout + (do_expiration_with_current_time): only set timeout if there are + items to expire + +2008-04-01 Timo Hoenig + + Patch from Frederic Crozat + + * bus/dir-watch-inotify.c (bus_watch_directory): Only monitor + IN_CLOSE_WRITE, IN_DELETE, IN_MOVE_TO and IN_MOVE_FROM events. This + way, only atomic changes to configuration file are monitored. + * bus/dir-watch-inotify.c (_handle_inotify_watch): Fix typo in + _dbus_verbose function call + * bus/dir-watch-inotify.c (bus_drop_all_directory_watches): Use + _dbus_strerror instead of perror + +2008-03-04 Havoc Pennington + + * bus/connection.c, bus/expirelist.c: Make the BusExpireList + struct opaque, adding accessors for manipulating the list. In this + commit there should be no change in functionality or behavior. The + purpose of this change is to improve encapsulation prior to fixing + some bugs Kimmo Hämäläinen found where the timeout is not properly + updated, since we need to e.g. take some action whenever adding + and removing stuff from the expire list. + +2008-03-31 Colin Walters + + Patch from Owen Taylor + + * tools/dbus-launch-x11.c: Check for X11 events before + selecting (FDO bug #15293) + +2008-03-31 Colin Walters + + Patch from Owen Taylor + + * tools/dbus-launch-x11.c: Make sure we call XFlush() + on all code paths (FDO bug #15293) + +2008-03-27 Havoc Pennington + + * tools/dbus-send.c (append_dict): Do not provide a signature to + dbus_message_iter_open_container() when opening a dict entry. + +2008-03-26 Colin Walters + + Patch from Scott James Remnant + + * dbus/dbus-bus.c: Set default exit_on_disconnect after registration with + the bus, not before. This ensures that programs which wish to set + exit_on_disconnect to FALSE will not be terminated if the bus exits + during registration. (FDO Bug #15112) + +2008-03-04 John (J5) Palmieri + + * fix broken poll on Mac OSX - build patch by Benjamin Reed + * configure.in: check for OSX's deadlocking poll + * dbus/dbus-sysdeps-unix.c (_dbus_poll): if we have a broken poll + don't use poll + +2008-03-04 John (J5) Palmieri + + * check if the linker supports a flag instead of just checking for GNU + ld + * configure.in: move AM_PROG_LIBTOOL to the top + (ld_supports_flag): new function for checking if the linker supports + a given flag + +2008-03-04 John (J5) Palmieri + + * add a changelog for Benjamin Reed's git patch RANT: Change Logs are + handled by git and having an external changelog just screws up + merging. We should write down rules for doing git commit messages + and leave it at that. + * configure.in: Platform build fixes for Mac OS X + the Darwin linker does not understand the -z option; wrap it in + a check for $with_gnu_ld. + environ is only available at runtime, so you need to make a + reference to _NSGetEnviron instead for symbols to resolve properly. + +2008-03-04 John (J5) Palmieri + + * configure.in: add $THREAD_LIBS to DBUS_LAUNCHER_LIBS so we link + correctly + +2008-03-04 John (J5) Palmieri + + * tools/dbus-launch.c: wrap X'ism in #ifdef so we can compile + without X + +2008-02-28 John (J5) Palmieri + + * dbus/dbus-sysdeps-unix.c: define _AI_ADDRCONFIG as 0 if not + defined so that we can compile with an older glibc + +2008-02-26 John (J5) Palmieri + + * Released 1.1.20 + +2008-02-26 John (J5) Palmieri + + * CVE-2008-0595 - security policy of the type work as an implicit allow for + messages sent without an interface bypassing the default deny rules + and potentially allowing restricted methods exported on the bus to be + executed by unauthorized users. This patch fixes the issue. + * bus/policy.c (bus_client_policy_check_can_send, + bus_client_policy_check_can_receive): skip messages without an + interface when evaluating an allow rule, and thus pass it to the + default deny rules + +2008-02-26 John (J5) Palmieri + + * correctly unref connections without guids during shutdown + * dbus/dbus-connection.c (close_connection_on_shutdown): new method + split out from shared_connections_shutdown + (shared_connections_shutdown): shutdown all shared connections + without guids + (_dbus_connection_ref_unlocked): handle OOM when prepending no guid + connections to the shared_connections_no_guid list + * Patch by Kimmo Hämäläinen + +2008-02-21 John (J5) Palmieri + + * fix build against the latest gcc/glibc + * dbus/dbus-sysdeps-unix.c: define _GNU_SOURCE + * bus/selinux.c: include limits.h + * Patch by Matthias Clasen + +2008-02-21 John (J5) Palmieri + + * fixes dbus-launch so the bus goes away when X does + (Red Hat Bug #430412) + * tools/dbus-launch.c (main): set xdisplay = NULL + * Patch by Matthias Clasen + +2008-01-17 John (J5) Palmieri + + * Released 1.1.4 + +2008-01-17 Timo Hoenig + * fix inotify support + * bus/dir-watch-inotify.c (_handle_inotify_watch): fix reading of the + inotify events. Also, use ssize_t not size_t for 'ret'. + * bus/dir-watch-inotify.c (bus_watch_directory): watch not only for + IN_MODIFY but also for IN_CREATE and IN_DELETE + * bus/dir-watch-inotify.c (bus_drop_all_directory_watches): drop the + inotify watches more elegantly by closing inotify:_fd, set inotify_fd to + -1 after dropping the watches + +2008-01-15 John (J5) Palmieri + + * configure.in: post-release version bump + +2008-01-15 John (J5) Palmieri + + * Released 1.1.3 (1.2.0RC1) + +2008-01-15 John (J5) Palmieri + + * fix hacking to say git instead of cvs + +2008-01-15 John (J5) Palmieri + + * patch by Sébastien Couret <10function at gmail dot com> + + * dbus/dbus-marshal-recursive.c (all_reader_classes[]): wrap in + #ifndef DBUS_DISABLE_ASSERT since it is only used in asserts which + are noop + +2008-01-15 John (J5) Palmieri + + * patch by Magnus Henoch + + * dbus/dbus-auth.c (handle_server_data_external_mech): handle SASL + EXTERNAL's inital empty responce (FDO Bug #9945) + +2008-01-15 John (J5) Palmieri + + * bus/messagebus.in: add lsb headers (FDO Bug #11491) + +2008-01-15 John (J5) Palmieri + + * patch by Peter O'Gorman + + * dbus/dbus-spawn.c (babysit_signal_handler): check write return value + so we don't hang (FDO Bug #11665) + +2008-01-15 John (J5) Palmieri + + * patch by Peter O'Gorman + + * dbus/dbus-sysdeps.h: support for AIX poll implementation (FDO Bug + #11666) + +2008-01-15 John (J5) Palmieri + + * tests/name-test/run-test.sh: make more portable (FDO Bug #11667) + +2008-01-15 John (J5) Palmieri + + * patch by Kimmo Hämäläinen + + * dbus/dbus-connection.c (_dbus_connection_get_next_client_serial): + don't check for < 0 on an unsigned variable (FDO Bug #12924) + +2008-01-15 John (J5) Palmieri + + * patch by Kimmo Hämäläinen + + * bus/bus.c (setup_server): check failed allocation (FDO Bug #12920) + +2008-01-15 John (J5) Palmieri + + * patch by Kimmo Hämäläinen + + * dbus/dbus-spawn.c (_dbus_spawn_async_with_babysitter): the API + contract says sitter_p can be NULL, so let's check it (FDO Bug #12919) + +2008-01-15 John (J5) Palmieri + + * patch by Kimmo Hämäläinen + + * dbus/dbus-spawn.c (read_ints, read_pid): use correct ssize_t type + instead of size_t (FDO Bug #12862) + +2008-01-15 John (J5) Palmieri + + * patch by Kimmo Hämäläinen + + * dbus/dbus-errors.c (dbus_set_error): make sure to call va_end if we + hit an OOM error inside va_start (FDO Bug #12846) + +2008-01-15 John (J5) Palmieri + + * patch by Kimmo Hämäläinen + + * dbus/dbus-connection.c (dbus_connection_send_with_reply): + fix possible crash if pending_return is NULL (FDO Bug #12673) + +2008-01-15 John (J5) Palmieri + + * portions of patch submitted by Tim Mooney + + + * configure.in: never auto-select libxml (FDO Bug #12479) + +2008-01-15 John (J5) Palmieri + + * patches by Kimmo Hämäläinen + + * dbus/dbus-sysdeps-unix (_dbus_get_autolaunch_address): handle OOM + (FDO Bug #12945) + + * dbus/dbus-uuidgen.c (return_uuid): handle OOM (FDO Bug #12928) + + * dbus/dbus-misc.c (dbus_get_local_machine_id): handle OOM, fix return + value to return NULL not FALSE (FDO Bug #12946) + +2008-01-15 John (J5) Palmieri + + * bus/bus.c (bus_context_check_security_policy): rewrite selinux error + handling to not abort due to a NULL read and to set the error only if + it is not already set (Based off of FDO Bug #12430) + +2008-01-15 John (J5) Palmieri + + * patch by Kimmo Hämäläinen + + * dbus/dbus-internals.c (_dbus_read_uuid_file_without_creating, + _dbus_create_uuid_file_exclusively): add OOM handling (FDO Bug #12952) + +2008-01-15 John (J5) Palmieri + + * patch by Kimmo Hämäläinen + + * dbus/dbus-spawn.c (babysit, babysitter_iteration): add error + handling when polling (FDO Bug #12954) + +2008-01-15 John (J5) Palmieri + + * patch by Kimmo Hämäläinen + + * bus/config-parser.c (locate_attributes): remove dead code which + always evaluated to TRUE + + * dbus/dbus-shell.c (_dbus_shell_quote): remove unused code + +2008-01-14 John (J5) Palmieri + + * patch by Kimmo Hämäläinen + + * bus/connection.c (bus_connection_complete): plug a possible + BusClientPolicy leak (FDO Bug #13242) + +2008-01-14 John (J5) Palmieri + + * patch by Frederic Crozat (FDO Bz# + 13268) + + * add inotify support + + * bus/Makefile.am: add inotify module to the build + + * bus/dir-watch-inotify.c: inotify module based off the dnotify and + kqueue modules + + * configure.in: add checks and switch for inotify + also add a printout at the end of configure if inotify and kqueue + support is being built in (dnotify already had this) + +2008-01-14 John (J5) Palmieri + + * patch by Frederic Crozat + + * bus/dir-watch-dnotify.c (bus_watch_directory): watch for file + creates also + +2008-01-14 John (J5) Palmieri + + * patch by Kimmo Hämäläinen + + * dbus/dbus-transport-socket.c(do_reading): return message + loader buffer in case of OOM (FDO Bug#12666) + +2008-01-14 John (J5) Palmieri + + * configure.in: add warning to output when libxml is selected since + we don't have a libxml maintainer and expat works perfectly fine + for what we need an xml parser for + +2008-01-14 John (J5) Palmieri + + * Patch by Andrea Luzzardi : creates a + _dbus_geteuid function to fix EXTERNAL authentication in setuid + applications + + * dbus/dbus-sysdeps-unix.c (_dbus_geteuid): used to get the effective + uid of the running program + (_dbus_credentials_add_from_current_process): use geteuid instead of + getuid + (_dbus_append_user_from_current_process): use geteuid instead of + getuid + + * dbus/dbus-sysdeps-util-unix.c (_dbus_change_to_daemon_user): use + geteuid instead of getuid + (_dbus_unix_user_is_at_console): use geteuid instead of getuid + + * dbus/dbus-sysdeps-win.c (_dbus_geteuid): add a windows equivilant + that returns DBUS_UID_UNSET + +2007-12-18 Havoc Pennington + + * dbus/dbus-connection.c (_dbus_connection_block_pending_call): + fix location of curly braces + +2007-11-23 Sjoerd Simons + + * tools/dbus-launch.c: let both a normal dbus-launch and an + autolaunched bus save their parameters in X11 if possible. This makes + the autolaunch and non-autolaunch behaviour more similar. With the + exception that on a normal launch there will always be a new session + bus and not being able to save parameters is not fatal. This also + enables to launch programs directly with autolaunch (not very usefull + though). + +2007-10-31 Havoc Pennington + + * bus/selinux.c (log_audit_callback): rewrite to use + _dbus_string_copy_to_buffer_with_nul() + + * dbus/dbus-string.c (_dbus_string_copy_to_buffer): change to NOT + nul-terminate the buffer; fail an assertion if there is not enough + space in the target buffer. This fixes two bugs where + copy_to_buffer was used to copy the binary bytes in a UUID, where + nul termination did not make sense. Bug reported by David Castelow. + (_dbus_string_copy_to_buffer_with_nul): new function that always + nul-terminates the buffer, and fails an assertion if there is not + enough space in the buffer. + +2007-10-23 Havoc Pennington + + * bus/bus.c (bus_context_new): use the new name here + + * bus/selinux.c (bus_selinux_audit_init): rename from audit_init() + to avoid possible libc conflict, and declare it in .h file to + avoid a warning + +2007-10-19 Havoc Pennington + + * bus/bus.c (bus_context_new): put audit_init() in HAVE_SELINUX + +2007-10-19 Havoc Pennington + + * bus/bus.c (bus_context_new): put the audit_init() in here + instead, which I believe ends up being the same as where it was + before, though I'm not sure I understand why it goes here. + + * dbus/dbus-sysdeps-util-unix.c (_dbus_change_to_daemon_user): + remove audit_init() from here, this file can't depend on code in + bus/ directory + +2007-10-16 Simon McVittie + + * configure.in: *Actually* fix detection of i486 atomic ops - + my previous attempt at a fix would always enable them due to wrong + quoting. Patch from Colin Walters + +2007-10-11 Simon McVittie + + * configure.in: enable Autoconf's AC_C_INLINE to avoid compilation + failure with gcc -ansi + * dbus/dbus-macros.h, dbus/dbus-arch-deps.h.in: Use new macro + _DBUS_GNUC_EXTENSION (the same as G_GNUC_EXTENSION) to avoid -ansi + warnings about use of "long long". + * dbus/dbus-server-socket.c: remove unused variable when assertions + are disabled + * dbus/dbus-marshal-validate.c: avoid empty statements by removing + stray semicolons + * tools/dbus-launch.c: convert C++-style comment to C-style, add {} + for clarity + * .gitignore: ignore vi swapfiles + * dbus/dbus-errors.h, dbus/dbus-errors.c: Add DBUS_ERROR_INIT macro, + equivalent to calling dbus_error_init() on an uninitialized DBusError + * dbus/dbus-address.c, dbus/dbus-auth-script.c, dbus/dbus-auth-util.c, + dbus/dbus-connection.c, dbus/dbus-internals.c, dbus/dbus-keyring.c, + dbus/dbus-message-util.c, dbus/dbus-server.c, dbus/dbus-sha.c, + dbus/dbus-spawn-win.c, dbus/dbus-spawn.c, + dbus/dbus-sysdeps-util-win.c, dbus/dbus-transport-socket.c, + dbus/dbus-transport.c, dbus/dbus-userdb.c: use that macro instead of + calling dbus_error_init() where it's clearly equivalent + * configure.in, dbus/dbus-sysdeps.h, dbus/dbus-sysdeps-unix.c: Fix + detection of i486 atomic ops. Previously, the attempts to determine + support at compile-time on Darwin were causing the i486 atomic ops to + be used on *all* i386 or x86-64 GCC builds (AH_VERBATIM can't be + conditionalized like we were trying to). + +2007-10-10 Simon McVittie + + * dbus/dbus-errors.c, dbus/dbus-protocol.h: Add new error + org.freedesktop.DBus.Error.ObjectPathInUse + * dbus/dbus-object-tree.h, dbus/dbus-object-tree.c, + dbus/dbus-connection.c, dbus/dbus-connection.h: add new functions + dbus_connection_try_register_object_path and + dbus_connection_try_register_fallback, which raise ObjectPathInUse + rather than asserting, to make object path registration less painful + for bindings + * .gitignore: add various things that weren't in .cvsignore because + CVS implicitly ignored them; generally bring up to date + +2007-10-09 John (J5) Palmieri + + * tools/run-with-tmp-session-bus.sh: Fix env exports for better + portability (#9280) + * tools/dbus-send.1: Document syntax for container types in dbus-send + man file (#9553) - patch from Jack Spaar + + [Both OK for MIT/X11 relicensing -smcv] + +2007-10-09 Simon McVittie + + * doc/dbus-specification.xml: Specifically forbid empty structs (#7969) + * doc/dbus-specification.xml: Patches from Kristoffer Lundén to clarify + description of DBUS_COOKIE_SHA1 (#10184) and allowable contents of a + variant (#10185, amended as per Havoc's comments) + + [All of the above are OK for MIT/X11 licensing] + +2007-10-03 John (J5) Palmieri + + * dbus/dbus-internals.h: fd.o bug #11678 Don't error out if compiler + does not support vararg macros. _dbus_verbose is the only function + that does this so make it a noop if vararg macros are not supported + * bus/selinux.c, dbus/dbus-sysdeps-util-unix.c: fd.o bug #12429 + Reverse check to setpcap and only init audit if we were root + (patch by Dan Walsh , + https://bugs.freedesktop.org/show_bug.cgi?id=12429). Reverse + we_were_root check to setpcap if we were root. Also only init audit + if we were root. So error dbus message will not show up when policy + reload happens. dbus -session will no longer try to send audit + message, only system will. + * configure.in: fd.o bug #11872 improve linker test for --gc-sections. + Patch by Tim Mooney + * configure.in, dbus/dbus-sysdeps.c: fd.o bug #11872 fix clearenv for + systems that do not have it. Patch from Brian Cameron + * tools/dbus-launch.c: fd.o bug #12547 remove superfluous if. + Also convert tabs to spaces + * configure.in, bus/Makefile.am, dbus/Makefile.am: Correctly implement + -fPIC and -fPIE. For security reasons we want possition independent + code for libraries and possition independent executable for + executables. Before we were just enabling -fPIC. Now we correctly + enable -fPIC and -PIE for libdbus and the bus respectively. Proper + LD_FLAGS are set for each also. + +2007-09-20 Ryan Lortie + + Add argument path matching support. Bug #11066. + + * dbus/signals.c (struct DBusMatchRule, bus_match_rule_new, + bus_match_rule_set_arg, bus_match_rule_parse_arg_match, + match_rule_matches): Add support for parsing and matching on + arg0path='/some/path' type rules. + + * dbus/signals.h (bus_match_rule_set_arg): change to take const + DBusString instead of const char * for the string to match against. + + * dbus/dbus-bus.c: add a quick note to dbus_bus_add_match + documentation about the path matching. + + * doc/dbus-specification.xml: add a more detailed description of the + changes here. + +2007-09-19 Ryan Lortie + + Add support for compacting DBusStrings to release wasted memory. + + * dbus/dbus-string.[ch] (compact, _dbus_string_compact, + _dbus_string_lock): new compact function to free up allocated memory + that is no longer used. + + * dbus/dbus-message.c (load_message): call _dbus_string_compact on the + message loader buffer. + + * dbus/dbus-transport-socket.c (do_reading, do_writing): call + _dbus_string_compact on the incoming/outgoing "encoded" buffers. + + * dbus/dbus-string-util.c (_dbus_string_test): add a few tests for + string compacting. + +2007-09-13 Ryan Lortie + + * HACKING: add more explicit git branch/tag instructions + +2007-09-13 Ryan Lortie + + migrate from cvs to git (cvs2svn -> git-svnimport). + + * HACKING: update release/branch/tag instructions + * */.cvsignore: rename to .gitignore + + also, clean up tags and branch names to conform to HACKING + +2007-08-17 William Jon McCann + + * update-dbus-docs.sh: upload DTD to server + +2007-08-17 Havoc Pennington + + * tools/dbus-launch-x11.c (set_address_in_x11): fix from Michael + Lorenz to use long not int with XChangeProperty format 32 + + * dbus/dbus-sysdeps-util-unix.c + (_dbus_write_pid_to_file_and_pipe): factor this out, and use the + same code in _dbus_become_daemon (where the parent writes the pid + file and to the pid pipe) and in bus_context_new (where the daemon + writes its own pid file and to its own pid pipe) + + * bus/bus.c (bus_context_new): close the pid pipe after we print + to it. Also, don't write the pid to the pipe twice when we fork, + someone reported this bug a long time ago. + +2007-08-03 Havoc Pennington + + * configure.in: add major/minor/micro version number AC_SUBST + + * dbus/dbus-arch-deps.h.in (DBUS_MAJOR_VERSION, + DBUS_MINOR_VERSION, DBUS_MICRO_VERSION, DBUS_VERSION_STRING, + DBUS_VERSION): collection of macros to get version of library we + are compiled against. + + * dbus/dbus-misc.c (dbus_get_version): new function, to get + version of library we are linked against at runtime. + +2007-07-30 Havoc Pennington + + * bus/activation-helper.c (check_bus_name): don't use + _dbus_check_valid_bus_name() which is only around with + --enable-checks, instead use _dbus_validate_bus_name(). + Bug #11766 from Diego + +2007-07-27 Havoc Pennington + + * configure.in: post-release version bump + +2007-07-27 Havoc Pennington + + * release 1.1.2 + +2007-07-26 Havoc Pennington + + * bus/config-parser-trivial.c (check_return_values): disable a + test that hardcoded the bus user's name + + * bus/dispatch.c (bus_dispatch_test_conf): remove the "if + (!use_launcher)" around the tests, they were only failing because + we didn't pass through all the expected errors from the helper. + + * bus/activation-exit-codes.h + (BUS_SPAWN_EXIT_CODE_CHILD_SIGNALED): add a code for child segfaulting + (BUS_SPAWN_EXIT_CODE_GENERIC_FAILURE): make "1" be a generic + failure code, so if a third party launch helper were written it + could just always return 1 on failure. + +2007-07-24 Daniel P. Berrange + + * bus/dbus-daemon.1: Add docs on new syntax options for the bus + address strings + + * dbus/dbus-address.c: Allow * in addresses (for binding to all + addresses). + + * dbus/dbus-sysdeps.h: + * dbus/dbus-sysdeps-unix.c: Re-write to use getaddrinfo instead + of gethostbyname to enable protocol independant name lookup, + making IPv6 work + + * dbus/dbus-server-socket.h: + * dbus/dbus-server-socket.c: Add support for 'family' in the + address string to specify ipv4 vs ipv6. Use a port string to + allow for service resolution. Allow for binding to multiple + sockets at once in case of dual IPv4 & IPv6 stacks. + + * dbus/dbus-server-unix.c: Pass in an array of file descriptors + instead of a single one. + + * dbus/dbus-transport-socket.h: + * dbus/dbus-transport-socket.c: Add support for 'family' in the + address string to specify ipv4 vs ipv6. Use a port string to + allow for service resolution. + +2007-07-24 Havoc Pennington + + * configure.in: add AM_PROG_CC_C_O to allow per-target CPPFLAGS + + * bus/dispatch.c (bus_dispatch_test_conf): Fix up setting + TEST_LAUNCH_HELPER_CONFIG to include the full path, and enable + test shell_fail_service_auto_start when use_launcher==TRUE + + * bus/activation-helper-bin.c (convert_error_to_exit_code): pass + through the INVALID_ARGS error so the test suite works + + * bus/activation.c (handle_activation_exit_error): return + DBUS_ERROR_NO_MEMORY if we get BUS_SPAWN_EXIT_CODE_NO_MEMORY + + * dbus/dbus-spawn.c (_dbus_babysitter_get_child_exit_status): + return only the exit code of the child, not the entire thingy from + waitpid(), and make the return value indicate whether the child + exited normally (with a status code) + + * bus/bus.c (process_config_first_time_only): _dbus_strdup works + on NULL so no need to check + (process_config_every_time): move servicehelper init here, so we + reload it on HUP or config file change + + * bus/Makefile.am (install-data-hook): remove comment because + Emacs make mode seems to be grumpy about it + +2007-07-24 Richard Hughes + + * bus/Makefile.am: + * bus/test-system.c: (die), (check_memleaks), (test_pre_hook), + (test_post_hook), (main): + Add back the test-system.c file - not sure now this got ignored in the + diff. I blame git. + +2007-07-24 Richard Hughes + + * configure.in: + Use ustar to generate the tarball; this fixes the make distcheck + problem when the data files do not fit in the archive: + tar: dbus-1.1.2/test/data/valid-service-files/org.freedesktop.DBus. + TestSuiteShellEchoServiceFail.service.in: file name is too + long (max 99); not dumped + + We have to have the 'long' names as the service helper matches by + filename rather than by the name in the service file. + +2007-07-24 Richard Hughes + + * configure.in: + * test/Makefile.am: + * test/data/invalid-service-files-system/org.freedesktop.DBus.TestS + uiteNoExec.service.in: + * test/data/invalid-service-files-system/org.freedesktop.DBus.TestS + uiteNoService.service.in: + * test/data/invalid-service-files-system/org.freedesktop.DBus.TestS + uiteNoUser.service.in: + * test/data/valid-config-files-system/debug-allow-all-fail.conf.in: + * test/data/valid-config-files-system/debug-allow-all-pass.conf.in: + * test/data/valid-config-files/debug-allow-all-sha1.conf.in: + * test/data/valid-config-files/debug-allow-all.conf.in: + * test/data/valid-service-files-system/org.freedesktop.DBus.TestSui + teEchoService.service.in: + * test/data/valid-service-files-system/org.freedesktop.DBus.TestSui + teSegfaultService.service.in: + * test/data/valid-service-files-system/org.freedesktop.DBus.TestSui + teShellEchoServiceFail.service.in: + * test/data/valid-service-files-system/org.freedesktop.DBus.TestSui + teShellEchoServiceSuccess.service.in: + * test/data/valid-service-files/debug-echo.service.in: + * test/data/valid-service-files/debug-segfault.service.in: + * test/data/valid-service-files/debug-shell-echo-fail.service.in: + * test/data/valid-service-files/debug-shell-echo-success.service.in: + * test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoS + ervice.service.in: + * test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfa + ultService.service.in: + * test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShell + EchoServiceFail.service.in: + * test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShell + EchoServiceSuccess.service.in: + Add the data files needed by the system activation unit checks. + +2007-07-24 Richard Hughes + + * bus/dispatch.c: (check_segfault_service_no_auto_start), + (check_launch_service_file_missing), + (check_launch_service_user_missing), + (check_launch_service_exec_missing), + (check_launch_service_service_missing), (bus_dispatch_test_conf), + (bus_dispatch_test_conf_fail), (bus_dispatch_test): + Add unit tests for system activation. Most are copied from the + session activation tests, but some didn't apply when using a laucher. + +2007-07-24 Richard Hughes + + * bus/activation.c: (bus_activation_activate_service): + If the bus uses a service-laucher, then use the setuid laucher. + +2007-07-24 Richard Hughes + + * configure.in: + Add the needed library exports for the new laucher. + +2007-07-24 Richard Hughes + + * configure.in: + Check for -Wl,--gc-sections so we can really reduce the size of the + setuid binary. + +2007-07-24 Richard Hughes + + * bus/activation.c: (handle_activation_exit_error), + (babysitter_watch_callback): + Map the child exit status integer to a proper dbus error. + +2007-07-24 Richard Hughes + + * bus/bus.c: (process_config_first_time_only), + (process_config_every_time), (bus_context_unref), + (bus_context_get_servicehelper): + * bus/bus.h: + Add the concept of a service-helper and allow it's value to be read. + +2007-07-24 Richard Hughes + + * bus/activation.c: (bus_activation_entry_unref), + (update_desktop_file_entry): + Add the concept of, and read the value of user from the desktop file. + The user string is not required unless we are using system activation. + +2007-07-24 Richard Hughes + + * bus/activation.c: + * bus/desktop-file.h: + Move the defines into the header file, as we use these in the lauch + helper as well as the desktop file parsing. + +2007-07-24 Richard Hughes + + * bus/.cvsignore: + Add the autogenerated binary files. + +2007-07-24 Richard Hughes + + * bus/Makefile.am: + * bus/test.h: + Add the build glue for the lauch helper, and also add the launch-helper + OOM checks into make check. I've probably broken the build, give me 2. + +2007-07-24 Richard Hughes + + * bus/test-launch-helper.c: (die), (check_memleaks), + (test_post_hook), (bus_activation_helper_oom_test), (main): + Add a test wrapper to allow OOM checks on the launch helper. + +2007-07-24 Richard Hughes + + * bus/activation-helper-bin.c: (convert_error_to_exit_code), + (main): + * bus/activation-helper.c: (desktop_file_for_name), + (clear_environment), (check_permissions), (check_service_name), + (get_parameters_for_service), (switch_user), + (exec_for_correct_user), (check_bus_name), (get_correct_parser), + (launch_bus_name), (check_dbus_user), (run_launch_helper): + * bus/activation-helper.h: + Add the initial launch-helper. This is split into a main section and a + binary loader that allows us to lauch the main section in another test + harness to do stuff like OOM testing. No build glue yet. + +2007-07-24 Richard Hughes + + * bus/Makefile.am: + * bus/config-parser.c: (bus_config_parser_unref), + (start_busconfig_child), (bus_config_parser_end_element), + (servicehelper_path), (bus_config_parser_content), + (bus_config_parser_finished), + (bus_config_parser_get_servicehelper), + (test_default_session_servicedirs), + (test_default_system_servicedirs), (bus_config_parser_test): + * bus/config-parser.h: + Make the config-parser code use the common config code. + Also add the session and systemdirs stuff, and make the config parser + aware of the servicehelper field. + +2007-07-24 Richard Hughes + + * bus/system.conf.in: + Add new servicehelper fields to the default system.conf file. + +2007-07-24 Richard Hughes + + * bus/config-parser-trivial.c: (service_dirs_find_dir), + (service_dirs_append_link_unique_or_free), (bus_config_parser_new), + (bus_config_parser_unref), (bus_config_parser_start_element), + (bus_config_parser_end_element), (bus_config_parser_content), + (bus_config_parser_finished), (bus_config_parser_get_user), + (bus_config_parser_get_type), (bus_config_parser_get_service_dirs), + (check_return_values), (do_load), (check_loader_oom_func), + (process_test_valid_subdir), (make_full_path), (check_file_valid), + (bus_config_parser_trivial_test): + * bus/config-parser-trivial.h: + Add a security sensitive stripped down config parser for the setuid + launcher. This file only reads what it needs, and doesn't try to do + anything remotely clever like including external files. + It is not intended to validate the config file; it is expected that + config-parser will do that before the setuid program tries to read it. + +2007-07-24 Richard Hughes + + * bus/config-parser-common.c: + (bus_config_parser_element_name_to_type), + (bus_config_parser_element_type_to_name): + * bus/config-parser-common.h: + We don't want to run the whole config parser with all it's deps in the + setuid program. We need to implement a stripped down config parser just + for the launcher, and to do so I need some common functions and + defines; add them here. + +2007-07-24 Richard Hughes + + * dbus/dbus-sysdeps-unix.c: + (_dbus_get_standard_system_servicedirs): + * dbus/dbus-sysdeps-win.c: + Provide a way to get the standard system servicedirs, just like we do + for the session service dirs. These should be seporate, as there may + be a security issue starting up some session stuff as root. + The use-case for the same binary starting up per-system _and_ + per-session is also not valid. + +2007-07-24 Richard Hughes + + * bus/dbus-daemon.1.in: + Add standard_system_servicedirs and servicehelper into the man file + and explain what each does. + +2007-07-24 Richard Hughes + + * doc/busconfig.dtd: + Add servicehelper into the dtd, it will soon be a valid part of the + config file. + +2007-07-24 Richard Hughes + + * dbus/dbus-spawn.c: (read_data), + (_dbus_babysitter_get_child_exit_status): + * dbus/dbus-spawn.h: + Add a function so we can get access to the exit status of the launch + helper. + By providing the return code and not the error we can leave the + 'what does this mean?' to the bus launch code and not include it in the + dbus directory. + +2007-07-24 Richard Hughes + + * bus/activation-exit-codes.h: + Add defines which specify the output codes of the launch helper. + We have to use exit codes as this is the only way we can return failure + type without going grotty things like redirecting possibly-nonsecure + stderr into the error. + +2007-07-24 Richard Hughes + + * dbus/dbus-protocol.h: + Add new error names needed for the launch helper. + +2007-07-24 Richard Hughes + + * dbus/dbus-sysdeps.c: (_dbus_clearenv): + * dbus/dbus-sysdeps.h: + Add a wrapper for clearenv. + +2007-07-24 Richard Hughes + + * doc/system-activation.txt: + Add design document for the system activation parts. I'll shortly be + committing many patches that add system activation using a setuid + launcher into CVS, so expect things to be broken for a few hours. + +2007-07-19 Ralf Habacker + + * cmake/modules/FindKDEWIN.cmake: fixed comment + * cmake/modules/FindKDEWIN32.cmake: removed obsolate cmake module + +2007-07-18 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_get_cached) + (dbus_message_cache_or_finalize): don't mess with message from + message cache outside of the cache lock. Bug #9164 from Jonathan + Matthew. + +2007-07-13 Havoc Pennington + + * Add indent-tabs-mode: nil to all file headers. + +2007-07-12 Havoc Pennington + + * dbus/dbus-sysdeps-util.c (_dbus_sysdeps_test): invert the test + for parsing hex as double to be sure it fails to work + + * dbus/dbus-sysdeps.c (_dbus_string_parse_double): don't allow hex numbers. + +2007-07-10 Havoc Pennington + + * dbus/dbus-connection.c (struct DBusConnection): Fix from Olivier + Hochreutiner to avoid trying to protect individual bits in a word + with different locks (make dispatch_acquired and io_path_acquired + dbus_bool_t rather than bitfields) + +2007-07-09 Ralf Habacker + + * dbus/dbus-sysdeps-win.c,dbus-sysdeps-win.h,dbus-sysdeps-win-util.c, + dbus-sysdeps-spawn-win.c: synced with windbus sources + +2007-07-07 Ralf Habacker + + * dbus/dbus-sysdeps-win.c + (_dbus_getsid): remove unused jump label + (_dbus_read_credentials_socket): _dbus_string_init could fail, + check initialisation + (_dbus_get_working_dir, _dbus_init_working_dir): remove unused + functions + +2007-07-04 Ralf Habacker + + * cmake/modules/FindKDEWIN.cmake: search in \win32libs + for windows supplementary packages too + +2007-06-30 Ralf Habacker + + * cmake/dbus/CMakeLists.txt: handle userdb as unix file + +2007-06-30 Ralf Habacker + + * dbus/dbus-sysdeps-win.c,dbus/dbus-sysdeps-win.h: removed obsolate + DBusUserInfo code + +2007-06-30 Ralf Habacker + + * dbus/dbus-sysdeps-win.c (_dbus_daemon_init): reduced compiler warnings + +2007-06-23 Ralf Habacker + + * dbus/dbus-auth-script.c (_dbus_auth_script_run): added UNIX_ONLY and + WIN_ONLY commands for auth scripts + * test/data/auth/external-root.auth-script: limit execution to unix + +2007-06-21 Havoc Pennington + + * dbus/dbus-tranport.c (auth_via_default_rules): made the verbose spam + cross-platform + +2007-06-21 Havoc Pennington + + * dbus/dbus-watch.c (dbus_watch_get_fd): 1) its behavior should + not be the same as before, the ABI has never been declared stable + on Windows and 2) do not commit to cross-platform files without + posting the exact patch to the mailing list + + * dbus/dbus-sysdeps-util.c (_dbus_sysdeps_test): as I have pointed + out before, either 0xff needs to work on both platforms, or none + of the dbus code can rely on it working. That means the options + are 1) audit the code for anywhere that relies on 0xff working, if + none found ideally add a test that it *doesn't* work and make unix + reject it explicitly, but in any case this test would go away or + 2) make it work on Windows also, then we don't have to figure out + whether we rely on it. + + And in either case, post the exact patch to the mailing list and + don't just commit. + +2007-06-21 Ralf Habacker + + * cmake/CMakeLists.txt: added VERSION_PATCH to be able to + distinguish win32 binary release from dbus versioning + +2007-06-21 Ralf Habacker + + * dbus/dbus-sysdeps-win.c: deleted local DBusCredentials structure + (_dbus_getsid): new function + (_dbus_read_credentials_socket): used correct function + (_dbus_append_user_from_current_process, + _dbus_credentials_add_from_current_process): added real + sid reading + (_dbus_credentials_parse_and_add_desired,_dbus_parse_uid): + deleted + +2007-06-21 Ralf Habacker + + * dbus/dbus-sysdeps-util.c (_dbus_sysdeps_test): don't check + 0xff as floating point, this isn't supported on win32 math + implementation + +2007-06-21 Ralf Habacker + + * dbus/dbus-sysdeps-win.c (_dbus_homedir_from_username, + _dbus_homedir_from_current_process, _dbus_append_desired_identity): + removed obsolate functions + +2007-06-21 Ralf Habacker + + * dbus/dbus-sysdeps-win.c, dbus/dbus-sysdeps-util-win.c, + dbus/dbus-sysdeps-win.h: disabled uid/sid conversation stuff + implementation by Peter Kuemmel + +2007-06-21 Ralf Habacker + + * dbus/dbus-watch.c (dbus_watch_get_fd): this function is + deprecated and its behavior should be as before until all + client code is migrated. + +2007-06-19 Ralf Habacker + + * dbus/dbus-sysdeps-util-win.c, tools/dbus-launch-win.c: + msvc7.1 fixes by Jaroslaw Staniek tested with mingw + +2007-06-19 Ralf Habacker + + * dbus/dbus-sysdeps-win.c, dbus/dbus-sysdeps-spawn-win.c, + dbus/dbus-sysdeps-win.h: disabled DBusSocket implementation + by Peter Kuemmel + +2007-06-18 Ralf Habacker + + * dbus-win.patch: removed obsolate patches + +2007-06-18 Havoc Pennington + + * configure.in: bump version to 1.1.2 so CVS is higher than last + release (this is not the 1.1.2 release) + +2007-06-18 Havoc Pennington + + * Release 1.1.1 + +2007-06-18 Havoc Pennington + + * doc/dbus-specification.xml: document org.freedesktop.DBus.GetId() + + * bus/driver.c (bus_driver_handle_get_id): implement org.freedesktop.DBus.GetId() + + * bus/bus.c (bus_context_new): generate a unique ID for each bus context + + * dbus/dbus-connection.c (dbus_connection_get_server_id): new function + + * dbus/dbus-bus.c (dbus_bus_get_id): new function + + * dbus/dbus-server.c (dbus_server_get_id): new function + +2007-06-18 Havoc Pennington + + * dbus/dbus-sysdeps-unix.c (_dbus_read_credentials_socket): clean + this up a little bit, to try and understand why telnet'ing to a + server and sending a non-nul byte didn't disconnect immediately; + now it seems that it does disconnect immediately as it should, + though I don't understand what has changed. + +2007-06-18 Havoc Pennington + + * dbus/dbus-watch.c (dbus_watch_get_socket) + (dbus_watch_get_unix_fd): new API to match DBusConnection + (dbus_watch_get_fd): deprecate this + + Throughout: just s/dbus_watch_get_fd/dbus_watch_get_socket/g for + now since all the transports use sockets anyway + +2007-06-16 Ralf Habacker + + * dbus/dbus-macros.h, dbus/dbus-message.c, + dbus/dbus-message.h: renamed DBUS_GNUC_DEPRECATED + to DBUS_DEPRECATED and extended to msvc compiler + +2007-06-15 Ralf Habacker + + * cmake/CMakeLists.txt: use local include header first + + * dbus/dbus-sysdeps-win.c: mingw fix of DBusCredential struct + +2007-06-15 Ralf Habacker + + * cmake/ConfigureChecks.cmake,cmake/config.h.cmake: + added check for HAVE_ERRNO_H + + * cmake/dbus/CMakeLists.txt: added missing files + + * dbus/dbus-transport-win.c/.h: new files + + * dbus/dbus-sysdeps-win.c,.h: added required _unix functions + to make dbus compilable on win32 + + * dbus/dbus-sysdeps-win-utils.c,.h: moved some functions to + dbus-sysdeps-win.c + + * dbus-win.patch: removed applied or obsolate patches + + Note: dbus-win32 is now compilable, no guarantee that it runs + without any problems + +2007-06-15 Havoc Pennington + + * dbus/dbus-sysdeps-unix.c (_dbus_append_session_config_file) + (_dbus_append_system_config_file): new functions + + * bus/main.c (main): use _dbus_append_system_config_file() and + _dbus_append_session_config_file() + + * dbus/Makefile.am (INCLUDES): move DBUS_SYSTEM_CONFIG_FILE and + DBUS_SESSION_CONFIG_FILE into this makefile + +2007-06-15 Havoc Pennington + + * dbus/dbus-sysdeps.c (_dbus_set_errno_to_zero) + (_dbus_get_is_errno_nonzero, _dbus_get_is_errno_eintr) + (_dbus_strerror_from_errno): family of functions to abstract + errno, though these are somewhat bogus (really we should make our + socket wrappers not use errno probably - the issue is that any + usage of errno that isn't socket-related probably is not + cross-platform, so should either be in a unix-only file that can + use errno directly, or is a bug - these general errno wrappers + hide issues of this nature in non-socket code, while + socket-specific API changes would not since sockets are allowed + cross-platform) + +2007-06-14 Havoc Pennington + + * bus/dispatch.c (check_get_connection_unix_process_id): mop up + getpid() (noticed by Peter Kümmel) and adapt the test to + expect a "pid unknown" error when running on Windows. + +2007-06-14 Havoc Pennington + + * dbus/dbus-sysdeps-unix.c (_dbus_credentials_parse_and_add_user): + delete this function since it was effectively the same as + _dbus_credentials_add_from_username() + +2007-06-14 Havoc Pennington + + * dbus/dbus-auth.c: adapt to keyring changes + + * dbus/dbus-keyring.c: change to avoid using user ID and home + directory directly; instead use a + keyring-location-from-credentials function in dbus-sysdeps + + * fix to use _dbus_append_user_from_current_process() instead of + _dbus_username_from_current_process() or _dbus_append_desired_identity(). + +2007-06-14 Ralf Habacker + + * reverted global rename of function _dbus_username_from_current_process. + It needs too much tests to verify that the change does not break anything. + I had overseen that the signatures are different and requires non + trivial changes. + This is one *major* disadvantage of emulating oop functionality with c. + You are responsible for cleaning every object on every function return point + which could be a nightmare if you are not working with dbus all the days. + +2007-06-14 Ralf Habacker + + * dbus/dbus-auth.c (handle_client_initial_response_cookie_sha1_mech): + fixed usage of _dbus_append_desired_identity() + + * dbus/dbus-sysdeps.h (_dbus_username_from_current_process): removed prototype + +2007-06-14 Ralf Habacker + + * dbus/dbus-sysdeps.c: moved global lock system_users from dbus-userdb.c + +2007-06-14 Ralf Habacker + + * global rename of function _dbus_username_from_current_process + to _dbus_append_desired_identity. + Approved by Havoc Pennington + +2007-06-14 Ralf Habacker + + * dbus/dbus-sysdeps-win.c: disabled DBusUserInfo related code + (_dbus_append_desired_identity, _dbus_windows_user_is_process_owner): + new win32 functions as counterpart of unix related + (_dbus_send_credentials_socket,_dbus_read_credentials_socket): + renamed from ..._unix_socket + (_dbus_send_credentials_unix_socket): removed obsolate function + + * dbus/dbus-sysdeps-win-util.c: disabled DBusGroupInfo related code + (_dbus_verify_daemon_user,_dbus_change_to_daemon_user): + new win32 functions as counterpart of unix related + +2007-06-14 Simon McVittie + + * doc/dbus-specification.xml: say the protocol version is 1 instead of + 0 (patch from Kristoffer Lundén, fd.o#10033) and remove the FIXME + about removing protocol version from messages (as per Havoc's comment + on that bug) + +2007-06-14 Ralf Habacker + + * dbus/dbus-sysdeps-win.c (_dbus_pid_for_log,_dbus_flush_caches): + new win32 functions as counterpart of unix related + +2007-06-14 Ralf Habacker + + * cmake/modules/FindKDEWIN.cmake, + cmake/modules/FindKDEWIN_Packager.cmake, + cmake/modules/Win32Macros.cmake: new files from the + kdewin32 project + * cmake/CMakeLists.txt: cleaned support for kdewin installer and + win32 explorer wrapper + +2007-06-13 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_iter_open_container): Fix + broken return_if_fail (kind of scary that test suite does not + cover this) + +2007-06-13 Havoc Pennington + + * dbus/dbus-server-socket.c (_dbus_server_listen_socket): support + all_interfaces=true|false for tcp servers + + * dbus/dbus-sysdeps-unix.c (_dbus_listen_tcp_socket): support + inaddr_any flag + + * bus/selinux.c: fix some missing includes + + * dbus/dbus-server-socket.c (_dbus_server_listen_socket): allow + port to simply be omitted in addition to specifying 0 + +2007-06-13 Havoc Pennington + + * configure.ac, bus/selinux.c, dbus/dbus-sysdeps-unix-util.c: add + libaudit support, no clue what this means really but now we have + it. Patches from Fedora package. + + * bus/bus.c (bus_context_new): move selinux initialization after + changing to daemon user, patch from Fedora package + + * dbus/dbus-transport.c (auth_via_unix_user_function): fix a typo + +2007-06-12 Havoc Pennington + + * dbus/dbus-message.c (dbus_message_iter_open_container): improve + the checks/warnings for contained_signature a bit + +2007-06-12 Havoc Pennington + + * dbus/dbus-marshal-recursive.c (write_or_verify_typecode): + improve the warning a bit if you write extra data into a message + +2007-06-12 Havoc Pennington + + * dbus/dbus-auth.c (sha1_handle_second_client_response) + (handle_server_data_anonymous_mech): add the process ID from + socket credentials, if available, even if not using EXTERNAL + + * dbus/dbus-transport.c (auth_via_default_rules): support + allow_anonymous flag + + * dbus/dbus-connection.c (dbus_connection_get_is_anonymous) + (dbus_connection_set_allow_anonymous): new API for controlling + anonymous access + +2007-06-09 Havoc Pennington + + * dbus/dbus-string.c (_dbus_string_pop_line): fix this not to + think an empty line is the end of the file. + Also, fix some whitespace. + + * dbus/dbus-string-util.c: add more tests for + _dbus_string_pop_line() revealing that it thinks an empty line is + the end of the file, which broke dbus-auth-script.c so + it didn't really run the scripts + + * dbus/dbus-auth.c: add ANONYMOUS mechanism + + * dbus/dbus-auth-script.c (_dbus_auth_script_run): fix to detect + an empty/no-op auth script; add commands to check that we have or + don't have the expected credentials + +2007-06-09 Havoc Pennington + + * bus/policy.c (bus_policy_create_client_policy): gracefully + continue if the connection has no unix user - just don't apply + any unix user dependent rules. + + * bus/config-parser.c: remove dbus-userdb.h usage + + * bus/bus.c: remove dbus-userdb.h usage + + * dbus/dbus-transport.c (_dbus_transport_get_is_authenticated): + support Windows user function; also, fix the logic for checking + auth as root in the default auth code (broken in the previous + commit) + + * dbus/dbus-connection.c + (dbus_connection_set_windows_user_function): new function + (dbus_connection_get_windows_user): new function + +2007-06-09 Havoc Pennington + + * bus/dispatch.c (check_get_connection_unix_process_id): adapt + since sysdeps-unix.h stuff isn't included anymore + + * bus/bus.c (bus_context_new): use more abstract functions to + change user, so they can be no-ops on Windows + + * dbus/dbus-credentials.c, dbus/dbus-credentials.h, + dbus/dbus-credentials-util.c: new files containing a fully opaque + DBusCredentials data type to replace the old not opaque one. + + * configure.in (DBUS_UNIX): define DBUS_UNIX to match DBUS_WIN on + windows + + * dbus/dbus-userdb.h: prohibit on Windows, next step is to clean + up the uses of it in bus/*.c and factor out the parts of + cookie auth that depend on it + +2007-06-07 Havoc Pennington + + * dbus/dbus-message.c: improve some docs related to reading values + from a message iter + +2007-06-02 Ralf Habacker + + * cmake: added cygwin compile support + +2007-06-01 Ralf Habacker + + * tools/dbus-launch-win.c: new file, replaces script wrapper on win32. + + * cmake/dbus-launch.bat.cmake: removed obsolate file + +2007-05-31 Ralf Habacker + + * bus/main.c (main): uses _dbus_get_config_file_name() to detect + session.conf location on win32. + + * dbus-sysdeps-win.h (_dbus_get_config_file_name,_dbus_file_exists): + new prototyp, undefined interface after including windows.h because + it makes trouble when a paramater is named interface. + + * dbus-sysdeps-win.c (_dbus_get_install_root, + _dbus_get_config_file_name,_dbus_file_exists): new functions. + +2007-05-27 Ralf Habacker + + * bus/policy.c,dbus/dbus-internals.c: fixed inconsistant line endings + as reported by Peter Kümmel. + +2007-05-25 John (J5) Palmieri + + * Released 1.1.0 + +2007-05-25 John (J5) Palmieri + + * Split NEWS and ChangeLog into a .pre-1-0 file as per HACKING + We forgot to do this during the 1.0 release and it makes sense + now as we get ready to release the first 1.1.0 development tarball + +2007-05-25 John (J5) Palmieri + + * create directory test/data/valid-config-files/session.d so that + make check passes + +2007-05-25 John (J5) Palmieri + + * INSTALL: remove dependancies for bindings since they no longer + are a part of core + +2007-05-25 Ralf Habacker + + * dbus/dbus-server-win.c,dbus/dbus-server-win.h: new file + with empty function _dbus_server_listen_platform_specific(). + + * dbus/dbus-server.c (listen_funcs): uses + _dbus_server_listen_platform_specific on any platform. + +2007-05-25 Ralf Habacker + + * dbus/dbus-sysdeps-win.c (fill_win_user_info_homedir): not getting + user info from a domain controller isn't an error, the computer + may run in a non domain context. + +2007-05-25 Ralf Habacker + + * dbus/dbus-sysdeps-win.c (_dbus_full_duplex_pipe): fixed assertation. + +2007-05-24 Simon McVittie + + * bus/config-parser.c (test_service_dir_matches): fixed ordering for unix. + + * bus/config-parser.c (test_default_session_servicedirs): made allocation + of _progs platform independent. + +2007-05-23 Havoc Pennington + + * bus/Makefile.am (install-data-hook): create session.d + + * bus/session.conf.in: add session.d for the session bus, so + security policy can be extended + +2007-05-22 Ralf.Habacker + + * cmake/CMakeLists.txt: fixed creating of TEST_..._BINARY to make + bus-test able to find the binaries. + +2007-05-21 Simon McVittie + + * acinclude.m4, configure.in: In recent autotools, ${datadir} is + defined in terms of ${datarootdir}, so EXPANDED_DATADIR needs to be + expanded recursively. Rather than fixing configure.in to do this, I + grabbed the AS_AC_EXPAND macro from autostars.sf.net, which seems to be + commonly used. + +2007-05-21 Simon McVittie + + * update-dbus-docs.sh: Assorted improvements: + - Default user if $FDUSER is not set is the ssh default + (set in ~/.ssh/config or based on the local username), not a + hard-coded "johnp" + - Temporary checkout directory is created securely (preventing symlink + attacks), if mktemp(1) is available + - Use make -C rather than cd && make && cd .. + +2007-05-21 Simon McVittie + + * HACKING: Point to correct mailing list + +2007-05-21 Simon McVittie + + * doc/dbus-specification.xml: explicitly specify that STRING cannot + contain embedded NULs. + +2007-05-20 Ralf.Habacker + + * dbus/dbus-internal.c: fix inline problem on win32. + +2007-05-20 Ralf.Habacker + + * dbus/dbus-sysdeps-win.c (fill_win_user_info_homedir): not reaching + domain controller isn't an error, converted error message to verbose + message. + +2007-05-19 Ralf.Habacker + + * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): disabled + tests not running on wince. + +2007-05-19 Ralf.Habacker + + * dbus/dbus-internals.c (_dbus_verbose_init): win32 requires 'varname=' + to unset a environment variable. + +2007-05-19 Ralf.Habacker + + * dbus/dbus-sysdeps.c (_dbus_setenv): win32 requires 'varname=' + to unset a environment variable. + +2007-05-19 Ralf.Habacker + + * bus/policy.c (bus_policy_create_client_policy): + win32 temporary fix until the userdb stuff is ported completly. + +2007-05-19 Ralf.Habacker + + * dbus/dbus-server.c (listen_funcs): + _dbus_server_listen_platform_specific is empty on win32, + limited to unix only. + + * dbus/dbus-server.c (valid_addresses): limit unix + only addresses to unix. + +2007-05-18 Havoc Pennington + + * doc/dbus-specification.xml: add a GetAll to the Properties + interface. + +2007-05-17 Ralf.Habacker + + * bus\config-parser.c (test_default_session_servicedirs): + win32 fix. + +2007-05-17 Ralf.Habacker + + * configure.in: define constant DBUS_UNIX. + +2007-05-14 Ralf Habacker + + * dbus/dbus-sysdeps-win.c (_dbus_printf_string_upper_bound): + compile fix for MS Platform SDK 6 + patch from Michael Luschas + +2007-05-10 John (J5) Palmieri + + * dbus-1.pc.in: add daemondir to pc file + patch from Brian Cameron + +2007-05-04 Simon McVittie + + * doc/dbus-specification.xml: mention the reserved o.fd.DBus.Local + interface and the corresponding /o/fd/DBus/Local object path; + describe them as reserved and forbid using them in a sent message, + mentioning that in the reference implementation this will cause the + connection to be dropped. Patch approved by Havoc. + +2007-04-28 Ralf Habacker + + * cmake/: don't install test applications and service files, + moved CMAKE_DEBUG_POSTFIX to top level CMakeLists.txt + +2007-04-27 Havoc Pennington + + * dbus/dbus-sysdeps-unix.c (_dbus_open_socket): fix #10781 from + Tobias Nygren, checking pointer to fd vs. 0 rather than checking + the fd itself + +2007-04-26 Ralf Habacker + + * cmake/: added debug postfixes to debug exe's for + easier debugging. + * dbus\dbus-sysdeps-win.c (_dbus_win_set_error_from_win_error): + print error code in case no string message is available. + +2007-04-06 Simon McVittie + + * dbus/dbus-message-util.c, dbus/dbus-message.c, + dbus/dbus-message.h: Add API to convert a DBusMessage to/from a + byte array. Patch from Dafydd Harries , + approved by Havoc Pennington. + +2007-04-03 Timo Hoenig + + * dbus/dbus-address.c (dbus_parse_address): Do not accept zero- + length address. + * dbus/dbus-address.c (_dbus_address_test): Add test for zero- + length address. + +2007-03-25 Ralf.Habacker + + * cmake/dbus/CMakeLists.txt: debug postfix also for mingw. + +2007-03-16 Ralf.Habacker + + * cmake/modules/FindExpat.cmake: fix package detection on win32. + + * README.win: update install instructions. + +2007-03-16 Ralf.Habacker + + * dbus/dbus-sysdeps.h (_dbus_split_paths_and_append): + new prototyp + (_DBUS_PATH_SEPARATOR): new macro. + + * dbus/dbus-sysdeps.c (_dbus_split_paths_and_append): merged + from dbus/dbus-sysdeps-unix.c and dbus/dbus-sysdeps-win.c. + +2007-03-15 Ralf.Habacker + + * bus/config-parser.c, bus/policy.c, + bus/policy.h, bus/dbus-daemon.1.in, + bus/session.conf.in: added eavesdrop support + for replies - patch by olli.salli at collabora.co.uk + approved by Havoc Pennington. + +2007-03-15 Ralf.Habacker + + * dbus\dbus-sysdeps-win-thread.c: renamed to + dbus-sysdeps-thread-win.c, it is a platform depending file + similar to dbus-sysdeps-pthread.c. + +2007-03-15 Ralf.Habacker + + * cmake\doc\CMakeLists.txt: added prelimary xml doc + support, needs cmake Find script. + +2007-03-14 Ralf.Habacker + + * cmake: add doxygen support + +2007-03-14 Ralf.Habacker + + * cmake/config.h.cmake: WINCE fixes, defined DBUS_UNIX. + +2007-03-13 Ralf.Habacker + + * dbus/dbus-sysdeps-util-win.c (dbus_become_daemon): + win32 compile fix. + +2007-03-13 Ralf.Habacker + + * dbus-win.patch: removed obsolate patches. + +2007-03-13 Ralf.Habacker + + * dbus/dbus-sysdeps-win.c: added zero byte sending + and receiving after connection start up + +2007-03-11 Havoc Pennington + + * tools/dbus-launch.c (do_close_stderr): fix C89 problem and + formatting problem + + * Mostly fix the DBusPipe mess. + - put line break after function return types + - put space before parens + - do not pass structs around by value + - don't use dbus_strerror after calling supposedly cross-platform + api + - don't name pipe variables "fd" + - abstract special fd numbers like -1 and 1 + +2007-03-12 Ralf Habacker + + * dbus/dbus-sysdeps-win.h, dbus/dbus-sysdeps-win.c, + dbus/dbus-sysdeps-util-win.c: renamed functions + _dbus_xxx_file() to _dbus_file_xxx() to reflect + struct name DBusFile. + +2007-03-12 Ralf Habacker + + * dbus/dbus-sysdeps-util-unix.c (_dbus_become_daemon): + fix _dbus_pid_fd check. + +2007-03-10 Ralf Habacker + + * tools/dbus-print-message.c (print_message): + added printing of the reply serial to method returns and + errors, so you can actually figure out the message/reply + pairs - patch by olli.salli at collabora.co.uk. + +2007-03-10 Ralf Habacker + + * dbus-win.patch: removed committed patches. + +2007-03-10 Ralf Habacker + + * bus/bus.c, bus/bus.h, bus/main.c, bus/test.c, + dbus/dbus-sysdeps-unix.c, dbus/dbus-sysdeps-util-unix.c, + dbus/dbus-sysdeps-util-win.c, dbus/dbus-sysdeps-win.c, + dbus/dbus-sysdeps.h: renamed _dbus_xxx_pipe to _dbus_pipe_xxx, + completed _dbus_pipe support. + +2007-03-10 Ralf Habacker + + * dbus/dbus-sysdeps.h (_dbus_listen_tcp_socket): + changed type or port to pointer, because the port is given back. + + * dbus/dbus-server-socket.c (_dbus_server_new_for_tcp_socket): + implemented returning tcp port. Skipping port parameter + and non integer port values in config statement + needs more effort. + + * dbus/dbus-sysdeps-unix.c, dbus/dbus-sysdeps-win.c + (_dbus_listen_tcp_socket): return the real used tcp port. + + * bus/dbus-daemon.1.in: added tcp examples + +2007-03-09 Ralf Habacker + + * cmake/config.h.cmake: win32 msvc bug fix + +2007-03-09 Ralf Habacker + + * cmake/config.h.cmake: fixed DBUS_WINxx defines, + using _WINCE does not work. + +2007-03-08 Ralf Habacker + + * dbus-win.patch: removed _dbus_write_pipe() patch, it is now + committed. + +2007-03-08 Ralf Habacker + + * bus/bus.c, dbus/dbus-sysdeps-unix.c, dbus/dbus-sysdeps.h: + rename pipe related write() function calls to _dbus_write_pipe(). + +2007-03-08 Ralf Habacker + + * dbus-win.patch: added bus/config-loader-libexpat.c patch, + uses DBUS_WIN for alls win32 related #ifdefs, + some minor cleanups + +2007-03-08 Ralf Habacker + + * dbus-win.patch: updated patch for bus/dispatch.c. + +2007-03-08 Ralf Habacker + + * dbus-win.patch: dbus-connection.c (dbus_connection_get_unix_user, + dbus_connection_get_unix_process_id): Let return them valid user id's, + otherwise bus-test fails. How to replace on win32 ?. + + * dbus/dbus-sysdeps-win.c (fill_win_user_info_homedir): + fix memory leak. + +2007-03-08 Ralf Habacker + + * dbus/dbus-sysdeps-win.c (_dbus_win_set_error_from_win_error): + use dbus friendly error name. + (fill_win_user_info_homedir): print user name in error case too. + +2007-03-08 Ralf Habacker + + * cmake/ConfigureChecks.cmake: fixed socketpair check + +2007-03-08 Ralf Habacker + + * bus/dispatch.c: disabled segfault test on win32 for now + +2007-03-08 Ralf Habacker + + * configure.in, cmake/ConfigureChecks.cmake: added check + for setrlimit. + * test/test-segfault.c: only include setrlimit stuff only + when available. + +2007-03-07 Ralf Habacker + + * test/test-segfault.c: unix compile fix. + * dbus-win.patch: removed obsolate patches. + +2007-03-07 Ralf Habacker + + * bus/activation.c: removed obsolate include header. + * test/test-segfault.c: win32 compile fix, rlimit + isn't available on win32. + * dbus-win.patch: removed some more patches, they + are applied or obsolate + +2007-03-06 Ralf Habacker + + * bus-win.patch: fixes unix listen problems, dbus-test + now runs. + +2007-03-06 Ralf Habacker + + * cmake/dbus/CMakeLists.txt,cmake/bus/CMakeLists.txt, + cmake/CMakeLists.txt: win32 compile fix + +2007-03-04 Ralf Habacker + + * dbus-win.patch, README.win: added available win32 + patches from windbus project (http://sf.net/projects/windbus) + +2007-03-04 Ralf Habacker + + * bus/activation.c: (bus_activation_activate_service): + fixed call to _dbus_spawn_async_with_babysitter(). + +2007-03-04 Ralf Habacker + + * dbus/dbus-spawn.c,dbus/dbus-spawn.h (_dbus_spawn_async_with_babysitter): + added environment pointer as function parameter, used on win32. + + * test/spawn-test.c: fixed call to above mentioned function. + +2007-03-04 Ralf Habacker + + * configure.in,test/test-sleep-forever.c,test/test-names.c: + added configure check for unistd.h. + +2007-03-04 Ralf Habacker + + * test/Makefile.am: fixed test data copy problem in + out of source build, when sources came from svn or cvs. + +2007-03-03 Ralf Habacker + + * dbus/*-win.*,bus/*-win.*: added win32 platform related + files. These files are only added to the cmake build system. + The missing dbus-win.patch file will be added later. + +2007-03-03 Ralf Habacker + + * cmake: new directory, contains cmake build support. + See http://www.cmake.org for more informations. + Currently only unix will be buildable because some + win32 required files are still missing. + +2007-03-03 Thiago Macieira + + * dbus/dbus-sysdeps-unix.c: capture the dbus-launch stderr + output and add it to the DBusError message we return. + + * tools/dbus-launch.1: + * tools/dbus-launch.c: Add option --close-stderr to, well, + close stderr before starting dbus-daemon. + +2007-01-31 Havoc Pennington + + * bus/dbus-daemon.1.in: write a section in the man page on running + a test daemon for debugging purposes + +2007-01-26 Havoc Pennington + + * bus/session.conf.in: override all the default limits with much + higher limits on the session bus, there is no reason the session + bus should have low limits + + * bus/config-parser.c (bus_config_parser_new): increase default + limits so they are less likely to be hit; in particular the max + replies per connection was way too low + +2006-01-25 Simon McVittie + + * doc/dbus-tutorial.xml: Replace Python section of tutorial with + a pointer to the tutorial maintained as part of dbus-python + +2006-12-31 Ralf Habacker + + * dbus/dbus-sysdeps-unix.c: unix compile fix, moved + atomic_exchange_and_add() from dbus/dbus-sysdeps.c + to here, it's used by _dbus_atomic_inc() and _dbus_atomic_dec(). + +2006-12-31 Ralf Habacker + + * tools/dbus-monitor.c: gettimeofday() is not available + on windows so we have to provide our own. It's taken from + lgpl'd kdewin32 package. - Patches from Christian Ehrlicher + +2006-12-31 Ralf Habacker + + * dbus/dbus-sysdeps-unix.c: moved _dbus_atomic_inc/dec() + from dbus/dbus-sysdeps.c, windows version of _dbus_atomic_inc/dec() + is in dbus-sysdeps-win.c (not in this patch). + + * dbus/dbus-sysdeps.h: DBusAtomic::value is long on windows to fit + with InterlockedInc/Decrement. + - Patches from Christian Ehrlicher + +2006-12-31 Ralf Habacker + + * tools/dbus-send.c, tools/dbus-monitor.c: win32 compile fix. + +2006-12-31 Ralf Habacker + + * dbus/dbus-marshal-recursive.c (type DBusTypeReaderClass): + fix mispaced const statement. - Patch from Peter Kümmel + +2006-12-19 Ray Strode + + * bus/bus.c (process_config_every_time): + don't overwrite existing bus context activation object + until after we've checked that the new activation is + valid. + + * bus/main.c + (signal_handler), (handle_reload_watch): + don't call exit() on failure, instead make do and keep + going. + (close_reload_pipe): new function to turn off + hangup-causes-config-reload behavior if an unexpected + error occurs + +2006-12-13 Ralf Habacker + + * dbus/dbus-sysdeps-win-thread.c (_dbus_condvar_wait_win32): + correctness fix. - Patch from Christian Ehrlicher + +2006-12-13 Ralf Habacker + + * dbus/dbus-internals.h: msvc also knows about __FUNCTION__, + we should also use it. - Patch from Christian Ehrlicher + +2006-12-13 Ralf Habacker + + * dbus-sysdeps-util.c: added win32 related tests + +2006-12-12 Ralf Habacker + + * dbus/dbus-string.c (_dbus_string_pop_line), + bus/desktop-file.c (parse_section_start, + parse_comment_or_blank,parse_key_value,): uses + _dbus_string_find_eol() to support platform independent eol style. + +2006-12-12 Ralf Habacker + + * dbus/dbus-string.[ch] (_dbus_string_find_eol): new function. + * dbus/dbus-string-util.c (_dbus_string_test): added testcases for + _dbus_string_find_eol(). + Approved by: Havoc Pennington. + +2006-12-12 Tim Dijkstra + + * configure.in: Added switch to disable user_database caching. + + * dbus/dbus-userdb-util.c, dbus/dbus-userdb.c: Add ifdefs to + be able disable user_dabase caching. + +2006-12-12 Tim Dijkstra + + * bus/bus.c, bus/bus.h: Remove DBusUserDatabase from the BusContext + struct. It is unnecessary we have a global one already. Also remove + bus_context_get_user_database function, it is no longer needed. + Flush the global database on reload. + + * dbus/dbus-userdb-util.c: Replace _dbus_user_database_get_groups + with _dbus_groups_from_uid. It no longer needs a DBusUserDatabase. + + * dbus/dbus-userdb.c, dbus/dbus-userdb.h: + Add _dbus_user_database_flush_system. + Make more functions DBUS_USERDB_INCLUDES_PRIVATE. + Small unrelated change in _dbus_is_a_number: change + _dbus_string_parse_int to _dbus_string_parse_uint. + + * bus/connection.c: Change call to _dbus_user_database_get_groups to + _dbus_groups_from_uid. + + * bus/policy.c, bus/policy.h: Change call to + _dbus_user_database_get_groups to _dbus_groups_from_uid. Remove + DBusUserDatabase from bus_policy_allow_user prototype, it no longer + needs it. + +2006-12-12 John (J5) Palmieri + + * bus/signal.c: Fix match_rule_equal errata + (CVE-2006-6107 - Patch from Kimmo Hämäläinen + ) + +2006-11-19 Thiago Macieira + + * dbus/dbus-sysdeps-pthread.c (_dbus_pthread_mutex_lock, + _dbus_pthread_condvar_wait, + _dbus_pthread_condvar_wait_timeout): set pmutex->holder to + pthread_self() after coming back from a conditional variable + wait as well as in one codepath where it was forgotten. + Approved by: Havoc Pennington. + +2006-11-17 Havoc Pennington + + * update-dbus-docs.sh: allow setting fd.org username via env + variable. Make it run autogen with --enable-xml-docs=yes + --enable-doxygen-docs=yes so configure will fail if the required + tools are missing. + +2006-11-17 Havoc Pennington + + * doc/dbus-faq.xml: minor FAQ tweaks + +2006-11-14 Havoc Pennington + + * dbus/dbus-misc.c, dbus/dbus-misc.h: Move + dbus_get_local_machine_id() to its own file, no substantive + changes. There are a couple other things we might want to add that + are "misc" so moving out of dbus-connection.[hc] which is big + enough already. + +2006-11-14 Havoc Pennington + + * dbus/dbus-internals.c (_dbus_generate_uuid): The spec said the + UUID had the timestamp last, but the implementation had it first; + move it to last since I think it's a tiny bit nicer (easier to + compare at a glance, faster to sort, less code), and will not + cause any practical compatibility problems. Also, always convert + the timestamp to big endian. + + * doc/dbus-specification.xml: Clean up the docs on the UUID. + + * tools/dbus-uuidgen.1: more prominently say it is not suitable + as a replacement for regular uuidgen/RFC4122. + +2006-11-14 John (J5) Palmieri + + * dbus/dbus-threads.h: fix DBUS_THREAD_FUNCTIONS_ALL_MASK to have + the correct value so we don't assert when initalizing recursive threads + + * test/name-test/test-thread-init.c: call dbus_threads_init_default + instead of _dbus_threads_init_debug since it is more of a real world + test + diff --git a/Doxyfile.in b/Doxyfile.in new file mode 100644 index 00000000..80ee0d0a --- /dev/null +++ b/Doxyfile.in @@ -0,0 +1,181 @@ +# Doxyfile 0.1 + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = D-Bus +PROJECT_NUMBER = @VERSION@ +OUTPUT_DIRECTORY = doc/api +OUTPUT_LANGUAGE = English +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +INTERNAL_DOCS = NO +STRIP_CODE_COMMENTS = YES +CASE_SENSE_NAMES = YES +SHORT_NAMES = NO +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = YES +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = YES +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +ALIASES = +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = YES +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = @top_srcdir@/dbus +FILE_PATTERNS = *.c *.h +RECURSIVE = YES +#EXCLUDE = test + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = Makefile.* ChangeLog CHANGES CHANGES.* README \ + README.* *.png AUTHORS DESIGN DESIGN.* *.desktop \ + DESKTOP* COMMENTS HOWTO magic NOTES TODO THANKS + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = YES +MAN_OUTPUT = man +MAN_EXTENSION = .3dbus +MAN_LINKS = YES +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = "DBUS_BEGIN_DECLS=" \ + "DBUS_END_DECLS=" \ + "DOXYGEN_SHOULD_SKIP_THIS" \ + "DBUS_GNUC_DEPRECATED=" \ + "_DBUS_DEFINE_GLOBAL_LOCK(name)=" \ + "_DBUS_GNUC_PRINTF(from,to)=" +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +PERL_PATH = +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +TEMPLATE_RELATIONS = YES +HIDE_UNDOC_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 640 +MAX_DOT_GRAPH_HEIGHT = 1024 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/HACKING b/HACKING new file mode 100644 index 00000000..f1e9d765 --- /dev/null +++ b/HACKING @@ -0,0 +1,341 @@ +The guidelines in this file are the ideals; it's better to send a +not-fully-following-guidelines patch than no patch at all, though. We +can always polish it up. + +Mailing list +=== + +The D-Bus mailing list is dbus@lists.freedesktop.org; discussion +of patches, etc. should go there. + +Security +=== + +Most of D-Bus is security sensitive. Guidelines related to that: + + - avoid memcpy(), sprintf(), strlen(), snprintf, strlcat(), + strstr(), strtok(), or any of this stuff. Use DBusString. + If DBusString doesn't have the feature you need, add it + to DBusString. + + There are some exceptions, for example + if your strings are just used to index a hash table + and you don't do any parsing/modification of them, perhaps + DBusString is wasteful and wouldn't help much. But definitely + if you're doing any parsing, reallocation, etc. use DBusString. + + - do not include system headers outside of dbus-memory.c, + dbus-sysdeps.c, and other places where they are already + included. This gives us one place to audit all external + dependencies on features in libc, etc. + + - do not use libc features that are "complicated" + and may contain security holes. For example, you probably shouldn't + try to use regcomp() to compile an untrusted regular expression. + Regular expressions are just too complicated, and there are many + different libc's out there. + + - we need to design the message bus daemon (and any similar features) + to use limited privileges, run in a chroot jail, and so on. + +http://vsftpd.beasts.org/ has other good security suggestions. + +Coding Style +=== + + - The C library uses GNU coding conventions, with GLib-like + extensions (e.g. lining up function arguments). The + Qt wrapper uses KDE coding conventions. + + - Write docs for all non-static functions and structs and so on. try + "doxygen Doxyfile" prior to commit and be sure there are no + warnings printed. + + - All external interfaces (network protocols, file formats, etc.) + should have documented specifications sufficient to allow an + alternative implementation to be written. Our implementation should + be strict about specification compliance (should not for example + heuristically parse a file and accept not-well-formed + data). Avoiding heuristics is also important for security reasons; + if it looks funny, ignore it (or exit, or disconnect). + +Development +=== + +D-Bus uses Git as its version control system. The main repository is +hosted at git.freedesktop.org/dbus/dbus. To clone D-Bus, execute the +following command: + + git clone git://git.freedesktop.org/dbus/dbus +OR + git clone git.freedesktop.org:dbus/dbus + +The latter form is the one that allows pushing, but it also requires +an SSH account on the server. The former form allows anonymous +checkouts. + +D-Bus development happens in two branches in parallel: the current +stable branch, with an even minor number (like 1.0, 1.2 and 1.4), and +the next development branch, with the next odd number. + +The stable branch is named after the version number itself (dbus-1.2, +dbus-1.4), whereas the development branch is simply known as "master". + +When making a change to D-Bus, do the following: + + - check out the earliest branch of D-Bus that makes sense to have + your change in. If it's a bugfix, it's normally the current stable + branch; if it's a feature, it's normally the "master" branch. If + you have an important security fix, you may want to apply to older + branches too. + + - for large changes: + if you're developing a new, large feature, it's recommended + to create a new branch and do your development there. Publish + your branch at a suitable place and ask others to help you + develop and test it. Once your feature is considered finalised, + you may merge it into the "master" branch. + +- for small changes: + . make your change to the source code + . execute tests to guarantee that you're not introducing a + regression. For that, execute: make check + (if possible, add a new test to check the fix you're + introducing) + . commit your change using "git commit" + in the commit message, write a short sentence describing what + you did in the first line. Then write a longer description in + the next paragraph(s). + . repeat the previous steps if necessary to have multiple commits + + - extract your patches and send to the D-Bus mailing list for + review or post them to the D-Bus Bugzilla, attaching them to a bug + report. To extract the patches, execute: + git format-patch origin/master + + - once your code has been reviewed, you may push it to the Git + server: + git push origin my-branch:remote + OR + git push origin dbus-X.Y + OR + git push origin master + (consult the Git manual to know which command applies) + + - (Optional) if you've not worked on "master", merge your changes to + that branch. If you've worked on an earlier branch than the current + stable, merge your changes upwards towards the stable branch, then + from there into "master". + + . execute: git checkout master + . ensure that you have the latest "master" from the server, update + if you don't + . execute: git merge dbus-X.Y + . if you have any conflicts, resolve them, git add the conflicted + files and then git commit + . push the "master" branch to the server as well + + Executing this merge is recommended, but not necessary for all + changes. You should do this step if your bugfix is critical for the + development in "master", or if you suspect that conflicts will arise + (you're usually the best person to resolve conflicts introduced by + your own code), or if it has been too long since the last merge. + + +Making a release +=== + +To make a release of D-Bus, do the following: + + - check out a fresh copy from Git + + - verify that the libtool versioning/library soname is + changed if it needs to be, or not changed if not + + - update the file NEWS based on the ChangeLog + + - update the AUTHORS file based on the ChangeLog + + - add a ChangeLog entry containing the version number + you're releasing ("Released 0.3" or something) + so people can see which changes were before and after + a given release + + - the version number should have major.minor.micro even + if micro is 0, i.e. "1.0.0" and "1.2.0" not "1.0"/"1.2" + + - "make distcheck" (DO NOT just "make dist" - pass the check!) + + - if make distcheck fails, fix it. + + - once distcheck succeeds, "git commit -a". This is the version + of the tree that corresponds exactly to the released tarball. + + - tag the tree with "git tag -s -m 'Released X.Y.Z' dbus-X.Y.Z" + where X.Y.Z is the version of the release. If you can't sign + then simply created an unannotated tag: "git tag dbus-X.Y.Z". + + - bump the version number up in configure.in, and commit + it. Make sure you do this *after* tagging the previous + release! The idea is that git has a newer version number + than anything released. + + - merge the branch you've released to the chronologically-later + branch (usually "master"). You'll probably have to fix a merge + conflict in configure.in (the version number). + + - push your changes and the tag to the central repository with + git push origin master dbus-X.Y dbus-X.Y.Z + + - scp your tarball to freedesktop.org server and copy it + to /srv/dbus.freedesktop.org/www/releases/dbus. This should + be possible if you're in group "dbus" + + - update the wiki page http://www.freedesktop.org/Software/dbus by + adding the new release under the Download heading. Then, cut the + link and changelog for the previous that was there. + + - update the wiki page + http://www.freedesktop.org/Software/DbusReleaseArchive pasting the + previous release. Note that bullet points for each of the changelog + items must be indented three more spaces to conform to the + formatting of the other releases there. + + - post to dbus@lists.freedesktop.org announcing the release. + + +After making a ".0" stable release +=== + +After releasing, when you increment the version number in git, also +move the ChangeLog to ChangeLog.pre-X-Y where X-Y is what you just +released, e.g. ChangeLog.pre-1-0. Then create and cvs add a new empty +ChangeLog. The last entry in ChangeLog.pre-1-0 should be the one about +"Released 1.0". + +Add ChangeLog.pre-X-Y to EXTRA_DIST in Makefile.am. + +We create a branch for each stable release; sometimes the branch is +not done immediately, instead it's possible to wait until someone has +a not-suitable-for-stable change they want to make and then branch to +allow committing that change. + +The branch name should be dbus-X.Y-branch which is a branch that has +releases versioned X.Y.Z + +To branch: + git branch dbus-X.Y-branch +and upload the branch tag to the server: + git-push origin dbus-X.Y-branch + +To develop in this branch: + git-checkout dbus-X.Y-branch + +Environment variables +=== + +These are the environment variables that are used by the D-Bus client library + +DBUS_VERBOSE=1 +Turns on printing verbose messages. This only works if D-Bus has been +compiled with --enable-verbose-mode + +DBUS_MALLOC_FAIL_NTH=n +Can be set to a number, causing every nth call to dbus_alloc or +dbus_realloc to fail. This only works if D-Bus has been compiled with +--enable-tests. + +DBUS_MALLOC_FAIL_GREATER_THAN=n +Can be set to a number, causing every call to dbus_alloc or +dbus_realloc to fail if the number of bytes to be allocated is greater +than the specified number. This only works if D-Bus has been compiled with +--enable-tests. + +DBUS_TEST_MALLOC_FAILURES=n +Many of the D-Bus tests will run over and over, once for each malloc +involved in the test. Each run will fail a different malloc, plus some +number of mallocs following that malloc (because a fair number of bugs +only happen if two or more mallocs fail in a row, e.g. error recovery +that itself involves malloc). This env variable sets the number of +mallocs to fail. +Here's why you care: If set to 0, then the malloc checking is skipped, +which makes the test suite a heck of a lot faster. Just run with this +env variable unset before you commit. + +Tests +=== + +These are the test programs that are built if dbus is compiled using +--enable-tests. + +dbus/dbus-test +This is the main unit test program that tests all aspects of the D-Bus +client library. + +dbus/bus-test +This it the unit test program for the message bus. + +test/break-loader +A test that tries to break the message loader by passing it randomly +created invalid messages. + +test/name-test/* +This is a suite of programs which are run with a temporary session bus. +If your test involves multiple processes communicating, your best bet +is to add a test in here. + +"make check" runs all the deterministic test programs (i.e. not break-loader). + +"make check-coverage" is available if you configure with --enable-gcov and +gives a complete report on test suite coverage. You can also run +"test/decode-gcov foo.c" on any source file to get annotated source, +after running make check with a gcov-enabled tree. + +Patches +=== + +Please file them at http://bugzilla.freedesktop.org under component +dbus, and also post to the mailing list for discussion. The commit +rules are: + + - for fixes that don't affect API or protocol, they can be committed + if any one qualified reviewer other than patch author + reviews and approves + + - for fixes that do affect API or protocol, two people + in the reviewer group have to review and approve the commit, and + posting to the list is definitely mandatory + + - if there's a live unresolved controversy about a change, + don't commit it while the argument is still raging. + + - regardless of reviews, to commit a patch: + - make check must pass + - the test suite must be extended to cover the new code + as much as reasonably feasible (see Tests above) + - the patch has to follow the portability, security, and + style guidelines + - the patch should as much as reasonable do one thing, + not many unrelated changes + No reviewer should approve a patch without these attributes, and + failure on these points is grounds for reverting the patch. + +The reviewer group that can approve patches: + +Havoc Pennington +Michael Meeks +Alexander Larsson +Zack Rusin +Joe Shaw +Mikael Hallendal +Richard Hult +Owen Fraser-Green +Olivier Andrieu +Colin Walters +Thiago Macieira +John Palmieri +Scott James Remnant +Will Thompson +Simon McVittie + + diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..744851d4 --- /dev/null +++ b/INSTALL @@ -0,0 +1,234 @@ + DBus Installation + ================= + +Quick start +=========== + +DBus uses GNU AutoTools for its build system, thus the basic install +procedure can be summarized as: + + ./configure --prefix=/usr + make + su make install + +The configure script will automatically determine whether to try and +build bindings for GLib, Qt, Qt3, Python and Mono based on what tools +are installed on the host system. The default build behaviour can be +overridden using the --enable-XXX/--disable-XXX arguments to configure. +A typical scenario in which it is desirable to override automatic +detection, is during packaging of binary builds, where a predictable +dependancy chain is required. For more details on GNU AutoTools +installation, consult the generic instructions later in this document + +External software dependancies +============================== + +The only fundamental requirement to build DBus is an XML parser, +however, there are a number of other software packages which (if +present) will enhance functionality. + +Core library +------------ + + Requisite: + + - Gettext + - expat or libxml-2 + + NB, expat is the recommended XML parser because it has more robust + handling of OOM conditions. + + Optional: + + - libselinux (for SELinux integration) + - dnotify (for automatic service file reload) + - doxygen (for API documentation) + - xmlto (for Spec & other XML documentation) + +==================================================================== + +The rest of this document contains the generic GNU AutoTools install +insructions.... + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..ac31a7fc --- /dev/null +++ b/Makefile.am @@ -0,0 +1,59 @@ +SUBDIRS=dbus bus doc tools test +DIST_SUBDIRS=dbus bus doc tools test + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = dbus-1.pc + +DISTCLEANFILES = \ + dbus-1.pc + +EXTRA_DIST = \ + HACKING \ + dbus-1.pc.in \ + cleanup-man-pages.sh \ + ChangeLog.pre-1-0 \ + NEWS.pre-1-0 \ + ChangeLog.pre-1-2 \ + NEWS.pre-1-2 + +all-local: Doxyfile + +if DBUS_GCOV_ENABLED +clean-gcov: + find -name "*.da" -o -name "*.gcov" | xargs rm || true + +clean-bbg: + find -name "*.bbg" -o -name "*.bb" | xargs rm || true + +GCOV_DIRS=dbus bus + +## .PHONY so it always rebuilds it +.PHONY: coverage-report.txt +coverage-report.txt: + BBG_FILES=`find $(GCOV_DIRS) -name "*.bbg" -o -name "*.gcno"` ; \ + C_FILES= ; \ + for F in $$BBG_FILES ; do \ + F_nolibs=`echo $$F | sed -e 's/.libs\///g'` ; \ + C=`echo $$F_nolibs | sed -e 's/.bbg/.c/g' | sed -e 's/.gcno/.c/g'` ; \ + B=`basename $$F .bbg` ; \ + D=`dirname $$F` ; \ + DA=`echo $$F | sed -e 's/.bbg/.da/g'` ; \ + DA_libs=`echo $$D/.libs/$$B/.da` ; \ + if test -e $$DA || test -e $$DA_libs; then \ + C_FILES="$$C_FILES $$C" ; \ + fi ; \ + done ; \ + echo $$C_FILES ; \ + $(top_builddir)/test/decode-gcov --report $$C_FILES > coverage-report.txt + +check-coverage: clean-gcov all check coverage-report.txt + cat coverage-report.txt + +else +coverage-report.txt: + echo "Need to reconfigure with --enable-gcov" + +check-coverage: + echo "Need to reconfigure with --enable-gcov" + +endif diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 00000000..a7aba5f5 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,971 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Doxyfile.in \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/config.h.in $(srcdir)/dbus-1.pc.in \ + $(top_srcdir)/configure \ + $(top_srcdir)/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in \ + $(top_srcdir)/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in \ + $(top_srcdir)/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in \ + $(top_srcdir)/test/data/valid-config-files-system/debug-allow-all-fail.conf.in \ + $(top_srcdir)/test/data/valid-config-files-system/debug-allow-all-pass.conf.in \ + $(top_srcdir)/test/data/valid-config-files/debug-allow-all-sha1.conf.in \ + $(top_srcdir)/test/data/valid-config-files/debug-allow-all.conf.in \ + $(top_srcdir)/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in \ + $(top_srcdir)/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in \ + $(top_srcdir)/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in \ + $(top_srcdir)/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in \ + $(top_srcdir)/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in \ + $(top_srcdir)/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in \ + $(top_srcdir)/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in \ + $(top_srcdir)/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in \ + $(top_srcdir)/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in \ + $(top_srcdir)/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in \ + AUTHORS COPYING ChangeLog INSTALL NEWS compile config.guess \ + config.sub depcomp install-sh ltmain.sh missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = Doxyfile dbus-1.pc \ + test/data/valid-config-files/debug-allow-all.conf \ + test/data/valid-config-files/debug-allow-all-sha1.conf \ + test/data/valid-config-files-system/debug-allow-all-pass.conf \ + test/data/valid-config-files-system/debug-allow-all-fail.conf \ + test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service \ + test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service \ + test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service \ + test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service \ + test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service \ + test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service \ + test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service \ + test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service \ + test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service \ + test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service \ + test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service \ + test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service \ + test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(pkgconfigdir)" +DATA = $(pkgconfig_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir dist dist-all distcheck +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d "$(distdir)" \ + || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr "$(distdir)"; }; } +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DBUS_BINDIR = @DBUS_BINDIR@ +DBUS_BUS_CFLAGS = @DBUS_BUS_CFLAGS@ +DBUS_BUS_LIBS = @DBUS_BUS_LIBS@ +DBUS_CLIENT_CFLAGS = @DBUS_CLIENT_CFLAGS@ +DBUS_CLIENT_LIBS = @DBUS_CLIENT_LIBS@ +DBUS_CONSOLE_AUTH_DIR = @DBUS_CONSOLE_AUTH_DIR@ +DBUS_CONSOLE_OWNER_FILE = @DBUS_CONSOLE_OWNER_FILE@ +DBUS_DAEMONDIR = @DBUS_DAEMONDIR@ +DBUS_DATADIR = @DBUS_DATADIR@ +DBUS_HAVE_INT64 = @DBUS_HAVE_INT64@ +DBUS_INT16_TYPE = @DBUS_INT16_TYPE@ +DBUS_INT32_TYPE = @DBUS_INT32_TYPE@ +DBUS_INT64_CONSTANT = @DBUS_INT64_CONSTANT@ +DBUS_INT64_TYPE = @DBUS_INT64_TYPE@ +DBUS_LAUNCHER_CFLAGS = @DBUS_LAUNCHER_CFLAGS@ +DBUS_LAUNCHER_LIBS = @DBUS_LAUNCHER_LIBS@ +DBUS_LIBEXECDIR = @DBUS_LIBEXECDIR@ +DBUS_MAJOR_VERSION = @DBUS_MAJOR_VERSION@ +DBUS_MICRO_VERSION = @DBUS_MICRO_VERSION@ +DBUS_MINOR_VERSION = @DBUS_MINOR_VERSION@ +DBUS_PATH_OR_ABSTRACT = @DBUS_PATH_OR_ABSTRACT@ +DBUS_SESSION_SOCKET_DIR = @DBUS_SESSION_SOCKET_DIR@ +DBUS_SYSTEM_BUS_DEFAULT_ADDRESS = @DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ +DBUS_SYSTEM_PID_FILE = @DBUS_SYSTEM_PID_FILE@ +DBUS_SYSTEM_SOCKET = @DBUS_SYSTEM_SOCKET@ +DBUS_TEST_CFLAGS = @DBUS_TEST_CFLAGS@ +DBUS_TEST_LIBS = @DBUS_TEST_LIBS@ +DBUS_UINT64_CONSTANT = @DBUS_UINT64_CONSTANT@ +DBUS_USER = @DBUS_USER@ +DBUS_VERSION = @DBUS_VERSION@ +DBUS_X_CFLAGS = @DBUS_X_CFLAGS@ +DBUS_X_LIBS = @DBUS_X_LIBS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPANDED_BINDIR = @EXPANDED_BINDIR@ +EXPANDED_DATADIR = @EXPANDED_DATADIR@ +EXPANDED_LIBDIR = @EXPANDED_LIBDIR@ +EXPANDED_LIBEXECDIR = @EXPANDED_LIBEXECDIR@ +EXPANDED_LOCALSTATEDIR = @EXPANDED_LOCALSTATEDIR@ +EXPANDED_SYSCONFDIR = @EXPANDED_SYSCONFDIR@ +FGREP = @FGREP@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML_CFLAGS = @LIBXML_CFLAGS@ +LIBXML_LIBS = @LIBXML_LIBS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_AGE = @LT_AGE@ +LT_CURRENT = @LT_CURRENT@ +LT_REVISION = @LT_REVISION@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIC_CFLAGS = @PIC_CFLAGS@ +PIC_LDFLAGS = @PIC_LDFLAGS@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +R_DYNAMIC_LDFLAG = @R_DYNAMIC_LDFLAG@ +SECTION_FLAGS = @SECTION_FLAGS@ +SECTION_LDFLAGS = @SECTION_LDFLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TEST_BUS_BINARY = @TEST_BUS_BINARY@ +TEST_EXIT_BINARY = @TEST_EXIT_BINARY@ +TEST_INVALID_SERVICE_DIR = @TEST_INVALID_SERVICE_DIR@ +TEST_INVALID_SERVICE_SYSTEM_DIR = @TEST_INVALID_SERVICE_SYSTEM_DIR@ +TEST_LAUNCH_HELPER_BINARY = @TEST_LAUNCH_HELPER_BINARY@ +TEST_PRIVSERVER_BINARY = @TEST_PRIVSERVER_BINARY@ +TEST_SEGFAULT_BINARY = @TEST_SEGFAULT_BINARY@ +TEST_SERVICE_BINARY = @TEST_SERVICE_BINARY@ +TEST_SHELL_SERVICE_BINARY = @TEST_SHELL_SERVICE_BINARY@ +TEST_SLEEP_FOREVER_BINARY = @TEST_SLEEP_FOREVER_BINARY@ +TEST_SOCKET_DIR = @TEST_SOCKET_DIR@ +TEST_VALID_SERVICE_DIR = @TEST_VALID_SERVICE_DIR@ +TEST_VALID_SERVICE_SYSTEM_DIR = @TEST_VALID_SERVICE_SYSTEM_DIR@ +VERSION = @VERSION@ +XMKMF = @XMKMF@ +XMLTO = @XMLTO@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = dbus bus doc tools test +DIST_SUBDIRS = dbus bus doc tools test +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = dbus-1.pc +DISTCLEANFILES = \ + dbus-1.pc + +EXTRA_DIST = \ + HACKING \ + dbus-1.pc.in \ + cleanup-man-pages.sh \ + ChangeLog.pre-1-0 \ + NEWS.pre-1-0 \ + ChangeLog.pre-1-2 \ + NEWS.pre-1-2 + +@DBUS_GCOV_ENABLED_TRUE@GCOV_DIRS = dbus bus +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +Doxyfile: $(top_builddir)/config.status $(srcdir)/Doxyfile.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +dbus-1.pc: $(top_builddir)/config.status $(srcdir)/dbus-1.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-config-files/debug-allow-all.conf: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-config-files/debug-allow-all.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-config-files/debug-allow-all-sha1.conf: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-config-files/debug-allow-all-sha1.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-config-files-system/debug-allow-all-pass.conf: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-config-files-system/debug-allow-all-pass.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-config-files-system/debug-allow-all-fail.conf: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-config-files-system/debug-allow-all-fail.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service: $(top_builddir)/config.status $(top_srcdir)/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service: $(top_builddir)/config.status $(top_srcdir)/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service: $(top_builddir)/config.status $(top_srcdir)/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @$(am__cd) '$(distuninstallcheck_dir)' \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile $(DATA) config.h all-local +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(pkgconfigdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr \ + distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-pkgconfigDATA + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-pkgconfigDATA + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am all-local am--refresh check check-am clean \ + clean-generic clean-libtool ctags ctags-recursive dist \ + dist-all dist-bzip2 dist-gzip dist-lzma dist-shar dist-tarZ \ + dist-xz dist-zip distcheck distclean distclean-generic \ + distclean-hdr distclean-libtool distclean-tags distcleancheck \ + distdir distuninstallcheck dvi dvi-am html html-am info \ + info-am install install-am install-data install-data-am \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-pkgconfigDATA \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-pkgconfigDATA + + +all-local: Doxyfile + +@DBUS_GCOV_ENABLED_TRUE@clean-gcov: +@DBUS_GCOV_ENABLED_TRUE@ find -name "*.da" -o -name "*.gcov" | xargs rm || true + +@DBUS_GCOV_ENABLED_TRUE@clean-bbg: +@DBUS_GCOV_ENABLED_TRUE@ find -name "*.bbg" -o -name "*.bb" | xargs rm || true + +@DBUS_GCOV_ENABLED_TRUE@.PHONY: coverage-report.txt +@DBUS_GCOV_ENABLED_TRUE@coverage-report.txt: +@DBUS_GCOV_ENABLED_TRUE@ BBG_FILES=`find $(GCOV_DIRS) -name "*.bbg" -o -name "*.gcno"` ; \ +@DBUS_GCOV_ENABLED_TRUE@ C_FILES= ; \ +@DBUS_GCOV_ENABLED_TRUE@ for F in $$BBG_FILES ; do \ +@DBUS_GCOV_ENABLED_TRUE@ F_nolibs=`echo $$F | sed -e 's/.libs\///g'` ; \ +@DBUS_GCOV_ENABLED_TRUE@ C=`echo $$F_nolibs | sed -e 's/.bbg/.c/g' | sed -e 's/.gcno/.c/g'` ; \ +@DBUS_GCOV_ENABLED_TRUE@ B=`basename $$F .bbg` ; \ +@DBUS_GCOV_ENABLED_TRUE@ D=`dirname $$F` ; \ +@DBUS_GCOV_ENABLED_TRUE@ DA=`echo $$F | sed -e 's/.bbg/.da/g'` ; \ +@DBUS_GCOV_ENABLED_TRUE@ DA_libs=`echo $$D/.libs/$$B/.da` ; \ +@DBUS_GCOV_ENABLED_TRUE@ if test -e $$DA || test -e $$DA_libs; then \ +@DBUS_GCOV_ENABLED_TRUE@ C_FILES="$$C_FILES $$C" ; \ +@DBUS_GCOV_ENABLED_TRUE@ fi ; \ +@DBUS_GCOV_ENABLED_TRUE@ done ; \ +@DBUS_GCOV_ENABLED_TRUE@ echo $$C_FILES ; \ +@DBUS_GCOV_ENABLED_TRUE@ $(top_builddir)/test/decode-gcov --report $$C_FILES > coverage-report.txt + +@DBUS_GCOV_ENABLED_TRUE@check-coverage: clean-gcov all check coverage-report.txt +@DBUS_GCOV_ENABLED_TRUE@ cat coverage-report.txt + +@DBUS_GCOV_ENABLED_FALSE@coverage-report.txt: +@DBUS_GCOV_ENABLED_FALSE@ echo "Need to reconfigure with --enable-gcov" + +@DBUS_GCOV_ENABLED_FALSE@check-coverage: +@DBUS_GCOV_ENABLED_FALSE@ echo "Need to reconfigure with --enable-gcov" + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NEWS b/NEWS new file mode 100644 index 00000000..e69de29b diff --git a/NEWS.pre-1-0 b/NEWS.pre-1-0 new file mode 100644 index 00000000..7105bc51 --- /dev/null +++ b/NEWS.pre-1-0 @@ -0,0 +1,614 @@ +D-Bus 1.0.0 (08 November 2006) +== +- Documents updated with API/ABI garuntees +- Added missing patch FreeBSD need to run out of the box +- dbus-monitor now has a profile mode +- AUTHORS file updated with names from the ChangeLog + Thanks to everyone who helped get us here + +D-Bus 1.0 RC 3 (0.95) (02 November 2006) +== +- DBUS_API_SUBJECT_TO_CHANGE no longer needs to be defined when building apps +- ./configure checks now work when cross compiling +- dbus-uuidgen --ensure is now run in the init script so there is no need to + run it in a post script +- dbus-uuidgen now writes out to /var/lib/dbus to work with systems that do not + have a writable /etc. Packages should install and own the /var/lib/dbus + directory +- recursive locks are now used when dbus_threads_init_default is called +- standard_session_servicedirs tag added to the session.conf + under a normal build this specifies these service directories: + /usr/local/share/dbus-1/services + /usr/share/dbus-1/services + $HOME/.local/share/dbus-1/services +- fixed crash when a service directory is specified more than once +- fixed a crash in *BSD when watching config directories for changes +- fixed Irix build by using dirp->__dd_fd to get the file descriptor +- cleaned up the LOCAL_CREDS vs CMGCRED credential code so *BSD's don't + crash here anymore +- dbus_message_iter_get_array_len deprecated +- cleanup-man-pages.sh added so packagers can clean up Doxygen man page output + from 7 to 2 megs +- large documentation improvements +- numerous bug fixes + +D-Bus 1.0 RC 2 (0.94) (14 October 2006) +== +- dbus-uuidgen binary added for future remote machine identification + packagers should call dbus-uuidgen --ensure in their post +- GetMachineId peer method added to the bus API +- dbus_connection_set_route_peer_messages API added to let the bus send + peer messages directly to an app +- Autolaunch abilities added to dbus-launch with the --autolaunch flag + This feature allows libdbus to start a session bus if none can be found + This is an internal feature and should not be used by scripts + DBUS_SESSION_BUS_ADDRESS is still the correct way to specify a session bus +- dbus-launch now prints out a simple key value pairs instead of shell scripts + if one of the shell flags aren't used +- support DBUS_BLOCK_ON_ABORT env variable to cause blocking waiting for gdb +- weak ref are now held for shared connections so the right things happen + this fixes some pretty major bugs with the way connections were handled +- Some refactoring for Windows (doesn't effect Unix) +- Solaris build fixes +- MacOSX build fixes +- Cross compile build fixes. We now assume getpwnam_r is posix and va_lists + can be copied by value since we can't check this in a cross compile. If + this is not true for a particular target is up to the developer to patch. +- Bug fixing all around + +D-Bus 1.0 RC 1 (0.93) (14 September 2006) +== +- dbus_threads_init_default added for initalizing threads without the need for + bindings +- Filters are now properly removed +- dbus_connection_open now holds a hard ref to shared connections +- We now print out a warning and do nothing when someone tries to close a + shared connection +- The --introspect switch has been added to the bus for printing out + introspection data without actually running the bus +- LOCAL_CREDS socket credentials are now supported for systems which + support it such as NetBSD +- Generalize kqueue support so it works with NetBSD as well as FreeBSD +- Numerous bug fixes and memory leaks patched + +D-Bus 0.92 (18 August 2006) +== +- Proper thread locking added to pending calls +- Threading semantics changed from init early to init before the second thread + is started +- Correctly error out when an application tries to acquire or release the + org.freedesktop.DBus name instead of sending false result codes +- kqueue directory watching code can now be used to monitor config file changes + on FreeBSD +- --with-dbus-daemondir configure switch added so the daemon can be installed + separate from the user binaries +- Makefiles fixed for cygwin +- Various fixes for the ongoing Windows port +- Fixed docs and comments to use the D-Bus spelling instead of D-BUS +- Many memleaks and bugs fixed + +D-Bus 0.91 (24 July 2006) +== +- Remove some lingering bits left over from the bindings split +- Fix assertion causing D-Bus applications to crash when checks are enabled +- Fix a timeout bug which would block applications from being auto started + +D-Bus 0.90 (17 July 2006) +== +- API/ABI freeze for 1.0 +- Bindings are now split out into seperate packages +- ListActivatableNames added as a method on the bus +- Removed deprecated dbus_connection_disconnect (use dbus_connection_close) +- Shared connections are now unreffed on disconnect +- Fixed pending calls for threaded enviornments +- Pending calls get timed out on connection disconnect +- dbus_connection_send_with_reply returns TRUE and a NULL pending call + if you call it on a connection object which has been disconnected already + (it returns FALSE on Out of Memory errors only) +- dbus-monitor now correctly catches methods, not just signals +- dbus-monitor now prints object paths + +D-BUS 0.62 (12 June 2006) +== +- Doc fixes +- Added support for all data-types for the dbus tools +- Fixed eavesdropping on method calls (dbus-monitor) +- Fixed silent dropping of method calls with interface=NULL +- Fixed console ownership problems in Solaris +- Fixed installation of dbus-signature.h and #include it in dbus/dbus.h +- Flush the user database cache on config reload +- GLib bindings: + - Fix memory leaks + - Fix properties in DBusGProxy so that they can be given in any + order + - Added lots of assertions to ensure correct use + - Remove duplicated code + - Fix static string pointer uses in GPtrArray-based collections +- Python bindings: + - Remove reference to sys/cdefs.h +- Qt4 bindings: + - Code reorganized + - Added the dbusidl2cpp, dbuscpp2xml and dbus tools + - Added example programs (ping-pong, complex ping-pong, listnames, chat) + - Updated selftests + - Fixed compilation and .moc- and .ui-file processing and cleaning + - Made central classes derive from QObject + - Enhance error reporting + - Many bugfixes +- Mono bindings: + - Minor bugfixes + +D-BUS 0.61 (24 Febuary 2006) +== +- Documentation all around +- dbus-launch now produces correct sh and csh syntax +- Nested arrays now work correctly +- GLib bindings: + - Inheriting from DBusGProxy is now possible + - GPtrArrays can now be marshalled + - org.freedesktop.DBus.GLib.ClientCSymbol annotation added + - Openning connections to arbitrary addresses now supported +- Python bindings: + - sender_keyword and path_keyword keywords added to signal listener API + - Byte types now demarshal to unsigned char + - calling methods now do the correct thing +- Qt bindings: + - both Qt3 and Qt4 bindings can be built at the same time + - Use the standard org.freedesktop.DBus.Method.NoReply annotation + for the "async" calls instead of creating one for us. +- Mono bindings: + - 64bit arch fixes +- Massive bug fixing all around + +D-BUS 0.60 (30 November 2005) +== + +- major ABI/API changes - sonames changed +- RequestName queuing behavior has changed (refer to dbus-specification) + - DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT has been removed and + DBUS_NAME_FLAG_ALLOW_REPLACEMENT has been added to the flags +- signals emitted by the bus now show up in the introspect data +- auth EXTERNAL now supported on BSD varients +- ReleaseName method added to the bus to allow a service + to remove itself as owner of a bus name +- dbus_connection_read_write added for getting messages off the bus + in the absence of a mainloop +- Qt4 bindings added and the Qt3 bindings have been depricated +- python bindings: + - marshal using introspect data if available + - better exception handling and propigation + - private connections are now supported + - UTF-8 cleanups + - out_signature added to method decorators for specifying + how the return values should be marshaled + - sender_keyword added to method decorators for specifying + and argument to provide the unique name of the method caller + - async_callbacks added to method decorators + - multiple inheritance of classes now supported +- GLib bindings: + - respect NoReply annotations + - dbus_g_method_return_get_reply and dbus_g_method_return_send_reply + added to the lowlevel code for use when the dbus-glib marshalling + code is not adiquate +- numerous bug fixes all around + +D-BUS 0.50 (06 September 2005) +=== +This is a minor release from 0.36.2. The series number has changed +not because of any technical reasons but as an indication that we +are moving closer to 1.0. It is hoped that this will be the last +series to see major changes, most of which will be isolated to the +GLib and Python bindings, as we transition to concentrate more on +bug busting and code auditing. + +- D-Bus builds on the Cygwin platform +- Makefile cleanups +- Various bug fixes +- Optimization of the dbus object tree +- Memleaks and GIL crasher bugs have been fixed in the Python bindings + +D-BUS 0.36.2 (29 August 2005) +=== +- Security: Restrict other users from connecting to another users + session bus + +D-BUS 0.36.1 (24 August 2005) +=== +- Python Bindings: + - fixed to work with hal-device-manager + - For 64bit builds everything is installed to lib64/python2.4/ + since Python can't handle multilib + +D-BUS 0.36 (23 August 2005) +=== +- Maximum sized of cached messages have been reduced to 10K +- Match rules now allow matching on arguments inside the message +- introspect.xsl XSLT style sheet added for formatting introspection + data into XHTML for analysis +- Python bindings: + - now have working type objects for explicit + typecasting + - Variant type has been added + - Dictionaries, Variants and Arrays can all be passed the signiture or + type(s) of their children + - the optional timeout= keyword has been added when making method calls + - match on args has been implemented + - a .pth file has been added for dealing with libraries and python files + being in different directories such as in 64bit installs + - various bug fixes +- GLib bindings: + - deeply recursive types now supported + - many symbols are no longer exported as part of the public API + - various memleak and other bug fixes + +D-BUS 0.35.2 (17 July 2005) +=== +- Rename Unix Security Context to SELinux Security Context in API +- Fixed more dist errors that distcheck didn't pick up on +- Fixed various bugs in the python bindings that prevented them from working + +D-BUS 0.35.1 (16 July 2005) +=== +- Fixed dist error where python/dbus_bindings.pxd was being shipped + instead of dbus_bindings.pxd.in +- Use this instead of the 0.35 tarball + +D-BUS 0.35 (15 July 2005) +=== +- --with-dbus-user added to the configure scripts for configuring the + user the system bus runs on +- --with-console-auth-dir added to configure scripts for configuring the + directory to look in for console user locks +- service files for auto-starting D-Bus services now has the ability to pass + in command line arguments to the executable +- Huge auto-start bug squashed which caused some services not to start when + requested in rapid succession +- SE-Linux security contexts can now be appended to messages for inspection + by services that enforce their own security policies +- Colin says the GLib binding are ready for general consumption +- New GLib tutorial +- New GLib example code +- Python bindings are now version (0,42,0) +- Python bindings API has changed on the service side +- dbus.service has been split out as a seperate module +- dbus.service.Service is renamed to dbus.service.BusName +- dbus.service.Object has swapped the bus_name and object_path constructor + parameters to make it easier to do inheritance over the bus +- dbus.glib has been seperated out in order to lessen the dependency on glib + and to allow other mainloops to be integrated with the bindings including + a planned generic mainloop for non-gui apps. +- Python bindings now aquire the GIL when calling back into the python + interpreter. Fixes crashes when using threading and other random segfaults. +- New Python tutorial +- Numerous D-Bus bug fixes all around + +D-BUS 0.34 (15 June 2005) +=== +- dbus_connection_disconnect is deprecated in favor of dbus_connection_close +- The bus can now use D_NOTIFY (if available) to check when configuration files + have changed and reload them +- New dbus_message_has_path/member/interface API added +- The Ping message from the org.freedesktop.DBus.Peer interface is now handled +- Complete glib bindings overhaul (and are still under construction) +- Tutorial now has an updated GLib section +- GLib bindings can now send/receive hash tables, arrays and other complex types +- Python bindings overhaul (most public facing API's done) +- Python bindings have been split up into separate files +- Python added new type classes for hinting to the marshaler what type + to send over the wire +- Python bindings now have decorators for specifying exported methods and signals +- Numerous bug fixes + +D-BUS 0.33 (25 Apr 2005) +=== + +- downgrade requirement from GTK+-2.6 to 2.4 for building gtk components +- python binding API's have been overhalled to be more "pythonic" and cleaner +- python bindings now export dbus.version which is set to (0,40,0) +- python bindings now implement the org.freedesktop.DBus.Introspectable interface +- python binding match rules are now more flexable +- make check has been fixed +- many, many major bug fixes + +D-BUS 0.32 (29 Mar 2005) +=== + +- mono bindings now compiles correctly +- mono binding cleanups +- glib bindings generates wrappers for bus methods in dbus-glib-bindings.h +- glib binding cleanus +- users and groups can now be specified by UID and GID in config files +- numerous memory leak fixes +- various other fixes + +D-BUS 0.31 (07 Mar 2005) +=== + +- land the new message args API and recursive type system +- add docs and fixed Doxygen warnings throught source +- split out some functions not needed in libdbus to *-util.c source files +- take out type convienience functions +- libdbus now back below 150K +- booleans are now 32-bit instead of 8-bit +- specification updated +- grand renaming to strip out the use of "service" + just say "name" instead (or "bus name" when ambiguous) +- rename dbus-daemon-1 to dbus-daemon throughout +- rename activation to auto-start +- auto-start on by default now +- note that libdbus is the low-level API +- python bindings updated to the new API +- mono bindings updated to the new API +- add 16 bit types +- dictionaries are now ARRAYS of DICT_ENTRY +- dbus-glib-tool renamed to dbus-binding-tool +- massive rewrite of the glib bindings +- saner names for the dbus interface, object path and service defines +- new functions for handling type signitures +- bump sonames for libdbus and libdbus-glib +- various small fixes + +D-BUS 0.23 (11 Jan 2005) +=== + +- add setgroups() to drop supplementary groups +- updated SELinux support +- add an "at console" security policy +- fix a bug where org.freedesktop.DBus wasn't recognized as an existing + service. +- error out if --enable-mono is explicitly set and mono libs can't be found +- set the max_match_rules_per_connection limit from the config file. +- removed dbus_bug_get_with_g_main since it's been replaced by + dbus_g_bus_get +- fix fd leaks in socket code +- lots and lots of mono binding updates, including fixes to make it + compatible with Mono 1.1.3 +- added --nofork option to override config file setting at runtime +- added support for int64 and uint64 to the python bindings +- lots of python binding updates +- config file DTD updates +- use SerivceOwnerChanges signal instead of ServiceCreated and + ServiceDeleted +- fixes to the authentication code +- new init script for Slackware +- print out the pid even when --fork is passed +- increase preallocation sizes in DBusMessage to heavily reduce + reallocs +- lots of performance enhancements +- lots more small bug fixes + +D-BUS 0.22 +=== + +- add --reply-timeout to dbus-send +- fix a memleak +- fix Solaris/Forte build +- switch to AFL 2.1 rather than 2.0 to address patent termination clause + concerns +- add SELinux support +- mostly repair libxml backend for config parser, still doesn't + pass out of memory tests +- fix distcheck to include language bindings +- add GetConnectionUnixUser method on bus driver +- also for UnixProcessID +- lots of Python, Mono, other binding fixes +- change GLib bindings to not include dbus/dbus.h (fully encapsulate libdbus) +- pass paths as strings, not arrays of string +- add message signature header field +- cleanups to marshaling code +- clean up authentication code +- reload conf files on SIGHUP +- rename SERVICE/SENDER_SERVICE to DESTINATION/SENDER +- fix circular conf file inclusion +- allow empty arrays +- tons of other small bugfixes + +D-BUS 0.21 +=== + +- implement "auto activation" flag on messages, so the destination + service can be launched automatically +- fix a bug in custom type marshaling +- optimize case where multiple apps activate the same service + (avoid "thundering herd") +- add dynamic service file discovery/reloading +- fix a busy loop when blocking for a reply +- fix a 64-bit crash involving varargs +- fix a bus crash when processing an AcquireService +- allow appending TYPE_BYTE via append_args_valist +- fix dicts-inside-dicts +- enhancements to Python and Qt bindings + +D-BUS 0.20 +=== + +This release lands some very large API changes and numerous bugfixes. +The list of changes is too large to fully document here; please refer +to the documentation, and message-bus-list archives. + +D-BUS 0.13 +=== + +This is probably the last release before landing the large API changes +on the "dbus-object-names" branch. + +- fix system bus to always use filesystem socket; anyone + can create any abstract socket, which isn't secure + since if you can crash the system bus you'd be able + to replace it. +- add DTD for configuration file +- improve specification a bit + +D-BUS 0.12 +=== + +- fix "service messagebus status" on Red Hat +- fix demarshaling of DBUS_TYPE_NAMED +- fix "eval `dbus-launch --exit-with-session`" to exit properly +- fix build without --prefix +- useless fooling with Mono bindings +- useless fooling with gcj bindings +- fix srcdir != builddir +- fix various compiler warnings and other issues +- add get/set data to DBusMessage +- fix headers for C++ +- OS X build fixes +- abstract domain sockets support (Linux only) +- add dbus-cleanup-sockets utility for people + not using linux +- be consistent about defaulting to --session/--system + with command line tools +- merge in policies from included config files +- fix build on non-x86 +- docs updates +- lots of other bugfixes + +D-BUS 0.11 +=== + +- add --enable-docs to turn off/on the docbook stuff + (doesn't cover doxygen stuff yet) +- make people define DBUS_API_SUBJECT_TO_CHANGE + and read warning in README so they don't + expect the API to be frozen already +- rename .pc files to "dbus-1.pc" instead of + "dbus-1.0.pc" etc. - this will require changing + pkg-config invocations +- some docs cleanups +- add man pages for all executables +- allow send to/from bus driver in the default system.conf +- fix user lookup bug +- implement dbus-launch to launch the session message bus +- fix some thread deadlocks +- some performance profiling/optimization +- add dbus_bus_activate_service() function +- fix some minor bugs here and there +- install Red Hat initscript in the right place + +D-BUS 0.10 +=== + +- reversed order of args to dbus_message_new() +- renamed dbus_message_name_is() and some other + functions +- change DBusWatch to have dbus_watch_handle() + similar to dbus_timeout_handle(), drop + connection/server-specific handle routines +- change message serials to be unsigned +- implemented // features for + config file; system bus now has a deny-all policy + by default. +- system.conf has system.d + so packages can install additions to the default + policy to the messages they need. e.g. + CUPS might install a cups.conf - see + test/data/valid-config-files/system.d/test.conf + for an example. +- add timeouts for authentication, activation +- add glib-style "checks" on public API, enable + those by default, disable assertions by default +- add GMainContext argument to GLib setup functions, + can be NULL for default context. Needed for threads. +- add 64-bit integer type +- validate type of standard message header fields +- consider messages in the org.freedesktop.Local + namespace to be invalid (to avoid fake disconnect + messages for example) +- fix assorted memory leaks and other bugs in + the SHA-1 auth mechanism +- cache user database information (groups user is + in, etc.) helps a lot with NIS +- always store uid_t, pid_t, gid_t in "ulong" + rather than "int" +- implement config file settings for which + users can connect +- SHA-1 unit test +- dbus-send, dbus-monitor command line utilities +- fixed lots of misc crashes and other bugs + +D-BUS 0.9 +=== + +- implemented a test case for service activation, + and fixed many bugs exposed by that +- implemented recursive argument marshaling/demarshaling + for messages, allowing multidimensional arrays +- fixed up integration of message dispatch with + main loop by adding a callback on change of + dispatch status +- add a pidfile feature to daemon +- some build fixes +- clean up unix domain sockets on exit +- add --print-address and the ability + to create a random server address + in a temporary directory + +D-BUS 0.8 +=== + +- fix dumb bug in 0.7 + +D-BUS 0.7 +=== + +- implement configuration file used to control bus characteristics +- implement daemon mode, changing user ID, and other system + bus features +- add init scripts for systemwide bus +- add "make check-coverage" target to check test coverage +- more test suite additions +- many, many bugfixes +- many API changes/fixes + +D-BUS 0.6 +=== +- Vastly improved bus daemon test suite +- Lots of misc. bugfixes and memory leak fixes +- Support for marshalling key/value data +- Activation improvements. + +D-BUS 0.5 +=== + +- Specification updates +- port to OS X and other BSD variants +- port to Solaris +- Partial work on cookie-based authentication +- Thread safety fixes +- Lots of misc. bugfixes +- Support for more array types +- Add data slots to DBusServer +- DBusString security audit fixes +- Fix for systems (or valgrind) with unaligned malloc blocks + +D-BUS 0.4 +=== + +- Preliminary activation support. +- Better authentication test suite +- Bus test program +- Specification updates +- Thread safety +- Bug fixes + +D-BUS 0.3 +=== + + - Preliminary limitations + - Message sending works + - Bus client + - Array marshalling/demarshalling + - Services + - Better OOM handling in the bus + - In-proc debug transport + - Transport/server address support + +D-BUS 0.2 +=== + + - Include test code in the tarball. + +D-BUS 0.1 +=== + + - Initial release. diff --git a/NEWS.pre-1-2 b/NEWS.pre-1-2 new file mode 100644 index 00000000..d9898f8e --- /dev/null +++ b/NEWS.pre-1-2 @@ -0,0 +1,153 @@ +D-Bus 1.2.1 (04 April) +== +- Due to issues putting the re-licensing effort on hold indefinitely, it has + been decided to move to 1.2.x versioning scheme. Being that 1.1.20 is + considered to also be 1.2.0 and this being the second release in the 1.2.x + stable series we have versioned this release 1.2.1. This release contains a + number of bug fixes identified after 1.1.20. +- compiles under some older versions of glibc +- compiles without X support once again +- fix stuck server grab if dbus-launch is run in an existing D-Bus X session +- various Mac OSX build fixes added +- don't use the broken poll call on Mac OSX +- better checks for linker flag support should allow D-Bus to link under + various linkers +- exit_on_disconnect is set after the connection registers with a bus so we + don't exit if we get a disconnect during the handshake +- dicts now work correctly with dbus-send +- inotify backend is now less aggressive +- pending calls expire correctly +- memleak of uuid when the bus is autolaunched fixed + +D-Bus 1.1.20 - "Conisten Water" (27 Febuary) +== + +- This is the next generation supported STABLE release of D-Bus. For all + intents and purposes this is the 1.2.0 release WITHOUT the planned X11/MIT + license change due to a couple of license holders who have yet to respond. + For the most part this license change is being persued to simplify licensing + issues and fix a couple of licensing courner cases. When this happens D-Bus + will be released under the 1.2.0 version. + +- D-Bus 1.0.x effectively goes into security fix mode and will only be + updated for major issues. + +- Fixed CVE-2008-0595 - security policy of the type work as an implicit allow for + messages sent without an interface bypassing the default deny rules and + potentially allowing restricted methods exported on the bus to be executed + by unauthorized users. + +- Fixes dbus-launch so the session bus goes away so does D-Bus + +- Builds against latest gcc/glibc changes + +- Correctly unref connections without guids during shutdown + +- About the name: Submitted by Greg K Nicholson, Conisten Water is a lake in + Cumbria, England where several water speed records have been broken. Between + 1956 and 1959 Sir Malcolm's son Donald Campbell set four successive records on the lake in Bluebird K7, a hydroplane. + (Wikipedia http://en.wikipedia.org/wiki/Coniston_Water#Waterspeed_record) + +D-Bus 1.1.4 - 1.2.0RC2 (17 January 2007) +== +- Fixes inotify support + +D-Bus 1.1.3 - 1.2.0RC1 (15 January 2007) +== + +- This release is intended to be Release Candidate 1 of major release + D-Bus 1.2.0. If nothing is found to be wrong with this release it + will become 1.2.0 within a week. If we need to make major changes + we will release an RC2 and start the process over again. + +- This is a development release, so API's may still change if problems + are found (though this is extreamly unlikely). + +- DTD for the introspection format is fixed and uploaded to the servers + +- Sources now reside in a git repository at + http://gitweb.freedesktop.org/?p=dbus/dbus.git;a=summary + +- Argument path matching of the type arg0path='/aa/bb/' is now supported + (see the specification for more information) + +- New error org.freedesktop.DBus.Error.ObjectPathInUse added + +- Autolaunched busses now save their parameters in X11 if possible making them + behave closer to busses launched through the normal mechanisms + +- inotify is now the default backend for watching configuration file changes + +- More support for the AIX platform has been added + +- Numerous bug fixes and performance enhancements + +D-Bus 1.1.2 (27 July 2007) +== + +- This release is intended to be a feature complete beta for stable + release 1.2.0, please test it. 1.2.0 will follow pretty soon if no + major problems are found. We'll do more betas if significant + changes are made. + +- This is a development release, so API's may still change if problems + are found (though we will try hard not to). + +- The system bus now supports starting services on demand. This uses a + setuid helper program because system bus daemon runs as a nobody + user, while services it launches may need to run as a different + user. + + ***Extra eyes auditing the setuid helper are encouraged and would be + timely right now, before 1.2.0*** + + A design doc is available in doc/system-activation.txt + +- The TCP address format has been enhanced, such that TCP may be + actually usable. The dbus-daemon man page describes the new + elements in the address format. 1.1.1 had added an all_interfaces + flag to the format, which has been removed in favor of a cleaner + approach. + +- Some thread-related bugs have been fixed, these are important fixes + if you are using multiple threads with libdbus, and not important + otherwise. + + +D-Bus 1.1.1 (18 June 2007) +== +- This is a development release, unless you need specific + functionality please use the stable releases as API's may change + (though we will try hard not to) +- The bus daemon now generates a globally-unique ID for itself, which is available + using the convenience function dbus_bus_get_id(). Use this as a unique ID + for a user's session, for example. +- dbus_server_get_id(), dbus_connection_get_server_id() now available to access + the unique ID of a particular address +- dbus_watch_get_fd() deprecated since it had unclear cross-platform semantics. + dbus_watch_get_unix_fd() and dbus_watch_get_socket() replace it. +- support ANONYMOUS mechanism for authentication, which allows a client to + authenticate as nobody in particular +- add API dbus_connection_set_allow_anonymous() which will allow the message + stream to begin if the client auths as anonymous (otherwise, the client + will be dropped unless they auth as a user). +- the ANONYMOUS support means you can now use D-Bus (without a bus daemon) as + a protocol for a network service provided to anonymous Internet or LAN + clients +- many internal changes to better support the Windows port, though the + port is still not complete in this release +- some improved documentation and return_if_fail checks +- some small bug fixes + +D-Bus 1.1.0 (25 May 2007) +== +- first release in the development series, unless you need specific + functionality please use the stable releases as API's may change + (though we will try hard not to) +- better eavesdropping support now picks up reply messages for debugging +- .pc file now lists the directory the daemon is installed into (daemondir) +- GetAll call added to the properties interface +- support for message serialization added for use with external transports like + TUBES!!! +- many bugs fixed diff --git a/README b/README new file mode 100644 index 00000000..ec63a98a --- /dev/null +++ b/README @@ -0,0 +1,153 @@ +Sections in this file describe: + - introduction and overview + - low-level vs. high-level API + - version numbers + - options to the configure script + - ABI stability policy + +Introduction +=== + +D-Bus is a simple system for interprocess communication and coordination. + +The "and coordination" part is important; D-Bus provides a bus daemon that does things like: + - notify applications when other apps exit + - start services on demand + - support single-instance applications + +See http://www.freedesktop.org/software/dbus/ for lots of documentation, +mailing lists, etc. + +See also the file HACKING for notes of interest to developers working on D-Bus. + +If you're considering D-Bus for use in a project, you should be aware +that D-Bus was designed for a couple of specific use cases, a "system +bus" and a "desktop session bus." These are documented in more detail +in the D-Bus specification and FAQ available on the web site. + +If your use-case isn't one of these, D-Bus may still be useful, but +only by accident; so you should evaluate carefully whether D-Bus makes +sense for your project. + +Note: low-level API vs. high-level binding APIs +=== + +A core concept of the D-Bus implementation is that "libdbus" is +intended to be a low-level API. Most programmers are intended to use +the bindings to GLib, Qt, Python, Mono, Java, or whatever. These +bindings have varying levels of completeness and are maintained as +separate projects from the main D-Bus package. The main D-Bus package +contains the low-level libdbus, the bus daemon, and a few command-line +tools such as dbus-launch. + +If you use the low-level API directly, you're signing up for some +pain. Think of the low-level API as analogous to Xlib or GDI, and the +high-level API as analogous to Qt/GTK+/HTML. + +Version numbers +=== + +D-Bus uses the common "Linux kernel" versioning system, where +even-numbered minor versions are stable and odd-numbered minor +versions are development snapshots. + +So for example, development snapshots: 1.1.1, 1.1.2, 1.1.3, 1.3.4 +Stable versions: 1.0, 1.0.1, 1.0.2, 1.2.1, 1.2.3 + +All pre-1.0 versions were development snapshots. + +Development snapshots make no ABI stability guarantees for new ABI +introduced since the last stable release. Development snapshots are +likely to have more bugs than stable releases, obviously. + +Configuration flags +=== + +These are the dbus-specific configuration flags that can be given to +the ./configure program. + + --enable-tests enable unit test code + --enable-verbose-mode support verbose debug mode + --enable-asserts include assertion checks + --enable-checks include sanity checks on public API + --enable-xml-docs build XML documentation (requires xmlto) + --enable-doxygen-docs build DOXYGEN documentation (requires Doxygen) + --enable-gcov compile with coverage profiling instrumentation (gcc only) + --enable-abstract-sockets + use abstract socket namespace (linux only) + --enable-selinux build with SELinux support + --enable-dnotify build with dnotify support (linux only) + --enable-kqueue build with kqueue support (*BSD only) + --with-xml=libxml/expat XML library to use + --with-init-scripts=redhat Style of init scripts to install + --with-session-socket-dir=dirname Where to put sockets for the per-login-session message bus + --with-test-socket-dir=dirname Where to put sockets for make check + --with-system-pid-file=pidfile PID file for systemwide daemon + --with-system-socket=filename UNIX domain socket for systemwide daemon + --with-console-auth-dir=dirname directory to check for console ownerhip + --with-dbus-user= User for running the DBUS daemon (messagebus) + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-tags[=TAGS] include additional configurations [automatic] + --with-x use the X Window System + + +API/ABI Policy +=== + +Now that D-Bus has reached version 1.0, the objective is that all +applications dynamically linked to libdbus will continue working +indefinitely with the most recent system and session bus daemons. + + - The protocol will never be broken again; any message bus should + work with any client forever. However, extensions are possible + where the protocol is extensible. + + - If the library API is modified incompatibly, we will rename it + as in http://ometer.com/parallel.html - in other words, + it will always be possible to compile against and use the older + API, and apps will always get the API they expect. + +Interfaces can and probably will be _added_. This means both new +functions and types in libdbus, and new methods exported to +applications by the bus daemon. + +The above policy is intended to make D-Bus as API-stable as other +widely-used libraries (such as GTK+, Qt, Xlib, or your favorite +example). If you have questions or concerns they are very welcome on +the D-Bus mailing list. + +NOTE ABOUT DEVELOPMENT SNAPSHOTS AND VERSIONING + +Odd-numbered minor releases (1.1.x, 1.3.x, 2.1.x, etc. - +major.minor.micro) are devel snapshots for testing, and any new ABI +they introduce relative to the last stable version is subject to +change during the development cycle. + +Any ABI found in a stable release, however, is frozen. + +ABI will not be added in a stable series if we can help it. i.e. the +ABI of 1.2.0 and 1.2.5 you can expect to be the same, while the ABI of +1.4.x may add more stuff not found in 1.2.x. + +NOTE ABOUT STATIC LINKING + +We are not yet firmly freezing all runtime dependencies of the libdbus +library. For example, the library may read certain files as part of +its implementation, and these files may move around between versions. + +As a result, we don't yet recommend statically linking to +libdbus. Also, reimplementations of the protocol from scratch might +have to work to stay in sync with how libdbus behaves. + +To lock things down and declare static linking and reimplementation to +be safe, we'd like to see all the internal dependencies of libdbus +(for example, files read) well-documented in the specification, and +we'd like to have a high degree of confidence that these dependencies +are supportable over the long term and extensible where required. + +NOTE ABOUT HIGH-LEVEL BINDINGS + +Note that the high-level bindings are _separate projects_ from the +main D-Bus package, and have their own release cycles, levels of +maturity, and ABI stability policies. Please consult the documentation +for your binding. diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 00000000..5dac6478 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,133 @@ + +dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not) +dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page +dnl also defines GSTUFF_PKG_ERRORS on error +AC_DEFUN([PKG_CHECK_MODULES], [ + succeeded=no + + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + if test "$PKG_CONFIG" = "no" ; then + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + PKG_CONFIG_MIN_VERSION=0.9.0 + if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then + AC_MSG_CHECKING(for $2) + + if $PKG_CONFIG --exists "$2" ; then + AC_MSG_RESULT(yes) + succeeded=yes + + AC_MSG_CHECKING($1_CFLAGS) + $1_CFLAGS=`$PKG_CONFIG --cflags "$2"` + AC_MSG_RESULT($$1_CFLAGS) + + AC_MSG_CHECKING($1_LIBS) + $1_LIBS=`$PKG_CONFIG --libs "$2"` + AC_MSG_RESULT($$1_LIBS) + else + $1_CFLAGS="" + $1_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + ifelse([$4], ,echo $$1_PKG_ERRORS,) + fi + + AC_SUBST($1_CFLAGS) + AC_SUBST($1_LIBS) + else + echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." + echo "*** See http://www.freedesktop.org/software/pkgconfig" + fi + fi + + if test $succeeded = yes; then + ifelse([$3], , :, [$3]) + else + ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4]) + fi +]) + + + +dnl a macro to check for ability to create python extensions +dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE]) +dnl function also defines PYTHON_INCLUDES +AC_DEFUN([AM_CHECK_PYTHON_HEADERS], +[AC_REQUIRE([AM_PATH_PYTHON]) +AC_MSG_CHECKING(for headers required to compile python extensions) +dnl deduce PYTHON_INCLUDES +py_prefix=`$PYTHON -c "import sys; print sys.prefix"` +py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` +PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" +if test "$py_prefix" != "$py_exec_prefix"; then + PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" +fi +AC_SUBST(PYTHON_INCLUDES) +dnl check if the headers exist: +save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" +AC_TRY_CPP([#include ],dnl +[AC_MSG_RESULT(found) +$1],dnl +[AC_MSG_RESULT(not found) +$2]) +CPPFLAGS="$save_CPPFLAGS" +]) + + +dnl as-ac-expand.m4 0.2.0 -*- autoconf -*- +dnl autostars m4 macro for expanding directories using configure's prefix + +dnl (C) 2003, 2004, 2005 Thomas Vander Stichele + +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + +dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR) + +dnl example: +dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir) +dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local + +AC_DEFUN([AS_AC_EXPAND], +[ + EXP_VAR=[$1] + FROM_VAR=[$2] + + dnl first expand prefix and exec_prefix if necessary + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + dnl if no prefix given, then use /usr/local, the default prefix + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + dnl if no exec_prefix given, then use prefix + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + dnl loop until it doesn't change anymore + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + dnl clean up + full_var=$new_full_var + AC_SUBST([$1], "$full_var") + + dnl restore prefix and exec_prefix + prefix=$prefix_save + exec_prefix=$exec_prefix_save +]) diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 00000000..fd78ef0c --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,9032 @@ +# generated automatically by aclocal 1.11.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.63],, +[m4_warning([this file was generated for autoconf 2.63. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that 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 GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 56 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl +_LT_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\[$]0 --fallback-echo"')dnl " + lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` + ;; +esac + +_LT_OUTPUT_LIBTOOL_INIT +]) + + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +cat >"$CONFIG_LT" <<_LTEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate a libtool stub with the current configuration. + +lt_cl_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AS_SHELL_SANITIZE +_AS_PREPARE + +exec AS_MESSAGE_FD>&1 +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +if test "$no_create" != yes; then + lt_cl_success=: + test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" + exec AS_MESSAGE_LOG_FD>/dev/null + $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false + exec AS_MESSAGE_LOG_FD>>config.log + $lt_cl_success || AS_EXIT(1) +fi +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_XSI_SHELLFNS + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES +# -------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX +# ----------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_SHELL_INIT + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[_LT_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +[$]* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(lt_ECHO) +]) +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], + [An echo program that does not interpret backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[AC_CHECK_TOOL(AR, ar, false) +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1]) + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line __oline__ "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[[3-9]]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method == "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC*) + # IBM XL 8.0 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac +AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE(int foo(void) {}, + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + ) + LDFLAGS="$save_LDFLAGS" + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], + [[If ld is used when linking, flag to hardcode $libdir into a binary + during linking. This must work even if $libdir does not exist]]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [fix_srcfile_path], [1], + [Fix the shell variable $srcfile for the compiler]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_PROG_CXX +# ------------ +# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ +# compiler, we have our own version here. +m4_defun([_LT_PROG_CXX], +[ +pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) +AC_PROG_CXX +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_CXX + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_CXX], []) + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[AC_REQUIRE([_LT_PROG_CXX])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 will use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + xl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=echo + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +]) +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_PROG_F77 +# ------------ +# Since AC_PROG_F77 is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_F77], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) +AC_PROG_F77 +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_F77 + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_F77], []) + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_REQUIRE([_LT_PROG_F77])dnl +AC_LANG_PUSH(Fortran 77) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${F77-"f77"} + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_PROG_FC +# ----------- +# Since AC_PROG_FC is broken, in that it returns the empty string +# if there is no fortran compiler, we have our own version here. +m4_defun([_LT_PROG_FC], +[ +pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) +AC_PROG_FC +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi +popdef([AC_MSG_ERROR]) +])# _LT_PROG_FC + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([_LT_PROG_FC], []) + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_REQUIRE([_LT_PROG_FC])dnl +AC_LANG_PUSH(Fortran) + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + CC=${FC-"f95"} + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC="$lt_save_CC" +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC="$lt_save_CC" +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_XSI_SHELLFNS +# --------------------- +# Bourne and XSI compatible variants of some useful shell functions. +m4_defun([_LT_PROG_XSI_SHELLFNS], +[case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $[*] )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +dnl func_dirname_and_basename +dnl A portable version of this function is already defined in general.m4sh +dnl so there is no need for it here. + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[[^=]]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$[@]"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]+=\$[2]" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$[1]=\$$[1]\$[2]" +} + +_LT_EOF + ;; + esac +]) + +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [0], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) + +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) + +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# Generated from ltversion.in. + +# serial 3017 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.2.6b]) +m4_define([LT_PACKAGE_REVISION], [1.3017]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.2.6b' +macro_revision='1.3017' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) + +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 4 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 10 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless `enable' is passed literally. +# For symmetry, `disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], +[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_PROG_CC_C_O +# -------------- +# Like AC_PROG_CC_C_O, but changed for automake. +AC_DEFUN([AM_PROG_CC_C_O], +[AC_REQUIRE([AC_PROG_CC_C_O])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +dnl Make sure AC_PROG_CC is never called again, or it will override our +dnl setting of CC. +m4_define([AC_PROG_CC], + [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# (`yes' being less verbose, `no' or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], +[ --enable-silent-rules less verbose build output (undo: `make V=1') + --disable-silent-rules verbose build output (undo: `make V=0')]) +case $enable_silent_rules in +yes) AM_DEFAULT_VERBOSITY=0;; +no) AM_DEFAULT_VERBOSITY=1;; +*) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([acinclude.m4]) diff --git a/bus/Makefile.am b/bus/Makefile.am new file mode 100644 index 00000000..ad49e6dd --- /dev/null +++ b/bus/Makefile.am @@ -0,0 +1,234 @@ + +configdir=$(sysconfdir)/dbus-1 + +INCLUDES=-I$(top_srcdir) $(DBUS_BUS_CFLAGS) @PIE_CFLAGS@ \ + -DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\" \ + -DDAEMON_NAME=\"dbus-daemon\" -DDBUS_COMPILATION + +EFENCE= + +CONFIG_IN_FILES= \ + session.conf.in \ + system.conf.in + +config_DATA= \ + session.conf \ + system.conf + +if DBUS_USE_LIBXML +XML_SOURCES=config-loader-libxml.c +endif +if DBUS_USE_EXPAT +XML_SOURCES=config-loader-expat.c +endif + +if DBUS_BUS_ENABLE_KQUEUE +DIR_WATCH_SOURCE=dir-watch-kqueue.c +else +if DBUS_BUS_ENABLE_INOTIFY +DIR_WATCH_SOURCE=dir-watch-inotify.c +else +if DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX +DIR_WATCH_SOURCE=dir-watch-dnotify.c +else +DIR_WATCH_SOURCE=dir-watch-default.c +endif +endif +endif + +BUS_SOURCES= \ + activation.c \ + activation.h \ + activation-exit-codes.h \ + bus.c \ + bus.h \ + config-parser.c \ + config-parser.h \ + config-parser-common.c \ + config-parser-common.h \ + connection.c \ + connection.h \ + desktop-file.c \ + desktop-file.h \ + $(DIR_WATCH_SOURCE) \ + dir-watch.h \ + dispatch.c \ + dispatch.h \ + driver.c \ + driver.h \ + expirelist.c \ + expirelist.h \ + policy.c \ + policy.h \ + selinux.h \ + selinux.c \ + services.c \ + services.h \ + signals.c \ + signals.h \ + test.c \ + test.h \ + utils.c \ + utils.h \ + $(XML_SOURCES) + +dbus_daemon_SOURCES= \ + $(BUS_SOURCES) \ + main.c + +dbus_daemon_LDADD= \ + $(EFENCE) \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(DBUS_BUS_LIBS) + +dbus_daemon_LDFLAGS=@R_DYNAMIC_LDFLAG@ @SECTION_LDFLAGS@ @PIE_LDFLAGS@ + +LAUNCH_HELPER_SOURCES= \ + $(XML_SOURCES) \ + config-parser-common.c \ + config-parser-common.h \ + config-parser-trivial.c \ + config-parser-trivial.h \ + desktop-file.c \ + desktop-file.h \ + utils.c \ + utils.h \ + activation-exit-codes.h \ + activation-helper.h \ + activation-helper.c + +## This is the installed launch helper with the setuid checks +dbus_daemon_launch_helper_SOURCES= \ + activation-helper-bin.c \ + $(LAUNCH_HELPER_SOURCES) + +dbus_daemon_launch_helper_LDADD= \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(DBUS_LAUNCHER_LIBS) + +dbus_daemon_launch_helper_LDFLAGS=@R_DYNAMIC_LDFLAG@ @SECTION_LDFLAGS@ + +## we build another binary so we can do the launch testing without root privs. +## DO NOT INSTALL THIS FILE +dbus_daemon_launch_helper_test_SOURCES= \ + activation-helper-bin.c \ + $(LAUNCH_HELPER_SOURCES) + +dbus_daemon_launch_helper_test_LDADD= \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(DBUS_LAUNCHER_LIBS) + +dbus_daemon_launch_helper_test_LDFLAGS=@R_DYNAMIC_LDFLAG@ @SECTION_LDFLAGS@ +dbus_daemon_launch_helper_test_CPPFLAGS= \ + -DACTIVATION_LAUNCHER_TEST + +## we build yet another binary so we can do the OOM tests +## DO NOT INSTALL THIS FILE +bus_test_launch_helper_SOURCES= \ + test-launch-helper.c \ + $(LAUNCH_HELPER_SOURCES) + +bus_test_launch_helper_LDADD= \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(DBUS_LAUNCHER_LIBS) + +bus_test_launch_helper_LDFLAGS=@R_DYNAMIC_LDFLAG@ @SECTION_LDFLAGS@ +bus_test_launch_helper_CPPFLAGS= \ + -DACTIVATION_LAUNCHER_TEST \ + -DACTIVATION_LAUNCHER_DO_OOM + +## note that TESTS has special meaning (stuff to use in make check) +## so if adding tests not to be run in make check, don't add them to +## TESTS +if DBUS_BUILD_TESTS +TESTS_ENVIRONMENT=DBUS_TEST_DATA=$(top_builddir)/test/data DBUS_TEST_HOMEDIR=$(top_builddir)/dbus DBUS_FATAL_WARNINGS=1 DBUS_BLOCK_ON_ABORT=1 +TESTS=bus-test bus-test-system bus-test-launch-helper +else +TESTS= +endif + +## we use noinst_PROGRAMS not check_PROGRAMS so that we build +## even when not doing "make check" +noinst_PROGRAMS=$(TESTS) dbus-daemon dbus-daemon-launch-helper-test dbus-daemon-launch-helper + +bus_test_system_SOURCES= \ + $(XML_SOURCES) \ + config-parser-common.c \ + config-parser-common.h \ + config-parser-trivial.c \ + config-parser-trivial.h \ + utils.c \ + utils.h \ + test-system.c + +bus_test_system_LDADD=$(top_builddir)/dbus/libdbus-convenience.la $(DBUS_BUS_LIBS) +bus_test_system_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +bus_test_SOURCES= \ + $(BUS_SOURCES) \ + test-main.c + +bus_test_LDADD=$(top_builddir)/dbus/libdbus-convenience.la $(DBUS_BUS_LIBS) +bus_test_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +## mop up the gcov files +clean-local: + /bin/rm *.bb *.bbg *.da *.gcov || true + +uninstall-hook: + rm -f $(DESTDIR)$(DBUS_DAEMONDIR)/dbus-daemon + rm -f $(DESTDIR)$(libexecdir)/dbus-daemon-launch-helper + +install-data-hook: + if test '!' -d $(DESTDIR)$(DBUS_DAEMONDIR); then \ + $(mkinstalldirs) $(DESTDIR)$(DBUS_DAEMONDIR); \ + chmod 755 $(DESTDIR)$(DBUS_DAEMONDIR); \ + fi + $(INSTALL_PROGRAM) dbus-daemon $(DESTDIR)$(DBUS_DAEMONDIR) + $(mkinstalldirs) $(DESTDIR)$(localstatedir)/run/dbus + $(mkinstalldirs) $(DESTDIR)$(configdir)/system.d + $(mkinstalldirs) $(DESTDIR)$(configdir)/session.d + $(mkinstalldirs) $(DESTDIR)$(datadir)/dbus-1/services + $(mkinstalldirs) $(DESTDIR)$(datadir)/dbus-1/system-services + $(mkinstalldirs) $(DESTDIR)$(libexecdir)/dbus-1 + $(INSTALL_PROGRAM) dbus-daemon-launch-helper $(DESTDIR)$(libexecdir) + if test `id -u` -eq 0; then \ + chown root:$(DBUS_USER) $(DESTDIR)$(libexecdir)/dbus-daemon-launch-helper; \ + chmod 4750 $(DESTDIR)$(libexecdir)/dbus-daemon-launch-helper; \ + else \ + echo "Not installing $(DESTDIR)$(libexecdir)/dbus-daemon-launch-helper binary setuid!"; \ + echo "You'll need to manually set permissions to root:$(DBUS_USER) and permissions 4750"; \ + fi + +#### Init scripts fun +SCRIPT_IN_FILES=messagebus.in \ + rc.messagebus.in + +## Red Hat start +if DBUS_INIT_SCRIPTS_RED_HAT + +initddir=$(sysconfdir)/rc.d/init.d + +initd_SCRIPTS= \ + messagebus + +endif + ## Red Hat end + +## Slackware start +if DBUS_INIT_SCRIPTS_SLACKWARE + +initddir=$(sysconfdir)/rc.d/ + +initd_SCRIPTS= \ + rc.messagebus + +endif +## Slackware end + +MAN_IN_FILES=dbus-daemon.1.in +man_MANS = dbus-daemon.1 + +#### Extra dist + +EXTRA_DIST=$(CONFIG_IN_FILES) $(SCRIPT_IN_FILES) $(man_MANS) $(MAN_IN_FILES) diff --git a/bus/Makefile.in b/bus/Makefile.in new file mode 100644 index 00000000..13a599af --- /dev/null +++ b/bus/Makefile.in @@ -0,0 +1,1458 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@DBUS_BUILD_TESTS_TRUE@TESTS = bus-test$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ bus-test-system$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ bus-test-launch-helper$(EXEEXT) +noinst_PROGRAMS = $(am__EXEEXT_1) dbus-daemon$(EXEEXT) \ + dbus-daemon-launch-helper-test$(EXEEXT) \ + dbus-daemon-launch-helper$(EXEEXT) +subdir = bus +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/dbus-daemon.1.in $(srcdir)/messagebus.in \ + $(srcdir)/rc.messagebus.in $(srcdir)/session.conf.in \ + $(srcdir)/system.conf.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = system.conf session.conf messagebus rc.messagebus \ + dbus-daemon.1 +CONFIG_CLEAN_VPATH_FILES = +@DBUS_BUILD_TESTS_TRUE@am__EXEEXT_1 = bus-test$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ bus-test-system$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ bus-test-launch-helper$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) +am__bus_test_SOURCES_DIST = activation.c activation.h \ + activation-exit-codes.h bus.c bus.h config-parser.c \ + config-parser.h config-parser-common.c config-parser-common.h \ + connection.c connection.h desktop-file.c desktop-file.h \ + dir-watch-default.c dir-watch-dnotify.c dir-watch-inotify.c \ + dir-watch-kqueue.c dir-watch.h dispatch.c dispatch.h driver.c \ + driver.h expirelist.c expirelist.h policy.c policy.h selinux.h \ + selinux.c services.c services.h signals.c signals.h test.c \ + test.h utils.c utils.h config-loader-expat.c \ + config-loader-libxml.c test-main.c +@DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX_FALSE@@DBUS_BUS_ENABLE_INOTIFY_FALSE@@DBUS_BUS_ENABLE_KQUEUE_FALSE@am__objects_1 = dir-watch-default.$(OBJEXT) +@DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX_TRUE@@DBUS_BUS_ENABLE_INOTIFY_FALSE@@DBUS_BUS_ENABLE_KQUEUE_FALSE@am__objects_1 = dir-watch-dnotify.$(OBJEXT) +@DBUS_BUS_ENABLE_INOTIFY_TRUE@@DBUS_BUS_ENABLE_KQUEUE_FALSE@am__objects_1 = dir-watch-inotify.$(OBJEXT) +@DBUS_BUS_ENABLE_KQUEUE_TRUE@am__objects_1 = \ +@DBUS_BUS_ENABLE_KQUEUE_TRUE@ dir-watch-kqueue.$(OBJEXT) +@DBUS_USE_EXPAT_FALSE@@DBUS_USE_LIBXML_TRUE@am__objects_2 = config-loader-libxml.$(OBJEXT) +@DBUS_USE_EXPAT_TRUE@am__objects_2 = config-loader-expat.$(OBJEXT) +am__objects_3 = activation.$(OBJEXT) bus.$(OBJEXT) \ + config-parser.$(OBJEXT) config-parser-common.$(OBJEXT) \ + connection.$(OBJEXT) desktop-file.$(OBJEXT) $(am__objects_1) \ + dispatch.$(OBJEXT) driver.$(OBJEXT) expirelist.$(OBJEXT) \ + policy.$(OBJEXT) selinux.$(OBJEXT) services.$(OBJEXT) \ + signals.$(OBJEXT) test.$(OBJEXT) utils.$(OBJEXT) \ + $(am__objects_2) +am_bus_test_OBJECTS = $(am__objects_3) test-main.$(OBJEXT) +bus_test_OBJECTS = $(am_bus_test_OBJECTS) +am__DEPENDENCIES_1 = +bus_test_DEPENDENCIES = $(top_builddir)/dbus/libdbus-convenience.la \ + $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +bus_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(bus_test_LDFLAGS) $(LDFLAGS) -o $@ +am__bus_test_launch_helper_SOURCES_DIST = test-launch-helper.c \ + config-loader-expat.c config-loader-libxml.c \ + config-parser-common.c config-parser-common.h \ + config-parser-trivial.c config-parser-trivial.h desktop-file.c \ + desktop-file.h utils.c utils.h activation-exit-codes.h \ + activation-helper.h activation-helper.c +@DBUS_USE_EXPAT_FALSE@@DBUS_USE_LIBXML_TRUE@am__objects_4 = bus_test_launch_helper-config-loader-libxml.$(OBJEXT) +@DBUS_USE_EXPAT_TRUE@am__objects_4 = bus_test_launch_helper-config-loader-expat.$(OBJEXT) +am__objects_5 = $(am__objects_4) \ + bus_test_launch_helper-config-parser-common.$(OBJEXT) \ + bus_test_launch_helper-config-parser-trivial.$(OBJEXT) \ + bus_test_launch_helper-desktop-file.$(OBJEXT) \ + bus_test_launch_helper-utils.$(OBJEXT) \ + bus_test_launch_helper-activation-helper.$(OBJEXT) +am_bus_test_launch_helper_OBJECTS = \ + bus_test_launch_helper-test-launch-helper.$(OBJEXT) \ + $(am__objects_5) +bus_test_launch_helper_OBJECTS = $(am_bus_test_launch_helper_OBJECTS) +bus_test_launch_helper_DEPENDENCIES = \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(am__DEPENDENCIES_1) +bus_test_launch_helper_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(bus_test_launch_helper_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__bus_test_system_SOURCES_DIST = config-loader-expat.c \ + config-loader-libxml.c config-parser-common.c \ + config-parser-common.h config-parser-trivial.c \ + config-parser-trivial.h utils.c utils.h test-system.c +am_bus_test_system_OBJECTS = $(am__objects_2) \ + config-parser-common.$(OBJEXT) config-parser-trivial.$(OBJEXT) \ + utils.$(OBJEXT) test-system.$(OBJEXT) +bus_test_system_OBJECTS = $(am_bus_test_system_OBJECTS) +bus_test_system_DEPENDENCIES = \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(am__DEPENDENCIES_1) +bus_test_system_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(bus_test_system_LDFLAGS) $(LDFLAGS) \ + -o $@ +am__dbus_daemon_SOURCES_DIST = activation.c activation.h \ + activation-exit-codes.h bus.c bus.h config-parser.c \ + config-parser.h config-parser-common.c config-parser-common.h \ + connection.c connection.h desktop-file.c desktop-file.h \ + dir-watch-default.c dir-watch-dnotify.c dir-watch-inotify.c \ + dir-watch-kqueue.c dir-watch.h dispatch.c dispatch.h driver.c \ + driver.h expirelist.c expirelist.h policy.c policy.h selinux.h \ + selinux.c services.c services.h signals.c signals.h test.c \ + test.h utils.c utils.h config-loader-expat.c \ + config-loader-libxml.c main.c +am_dbus_daemon_OBJECTS = $(am__objects_3) main.$(OBJEXT) +dbus_daemon_OBJECTS = $(am_dbus_daemon_OBJECTS) +dbus_daemon_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(am__DEPENDENCIES_1) +dbus_daemon_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(dbus_daemon_LDFLAGS) $(LDFLAGS) -o $@ +am__dbus_daemon_launch_helper_SOURCES_DIST = activation-helper-bin.c \ + config-loader-expat.c config-loader-libxml.c \ + config-parser-common.c config-parser-common.h \ + config-parser-trivial.c config-parser-trivial.h desktop-file.c \ + desktop-file.h utils.c utils.h activation-exit-codes.h \ + activation-helper.h activation-helper.c +am__objects_6 = $(am__objects_2) config-parser-common.$(OBJEXT) \ + config-parser-trivial.$(OBJEXT) desktop-file.$(OBJEXT) \ + utils.$(OBJEXT) activation-helper.$(OBJEXT) +am_dbus_daemon_launch_helper_OBJECTS = \ + activation-helper-bin.$(OBJEXT) $(am__objects_6) +dbus_daemon_launch_helper_OBJECTS = \ + $(am_dbus_daemon_launch_helper_OBJECTS) +dbus_daemon_launch_helper_DEPENDENCIES = \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(am__DEPENDENCIES_1) +dbus_daemon_launch_helper_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(dbus_daemon_launch_helper_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__dbus_daemon_launch_helper_test_SOURCES_DIST = \ + activation-helper-bin.c config-loader-expat.c \ + config-loader-libxml.c config-parser-common.c \ + config-parser-common.h config-parser-trivial.c \ + config-parser-trivial.h desktop-file.c desktop-file.h utils.c \ + utils.h activation-exit-codes.h activation-helper.h \ + activation-helper.c +@DBUS_USE_EXPAT_FALSE@@DBUS_USE_LIBXML_TRUE@am__objects_7 = dbus_daemon_launch_helper_test-config-loader-libxml.$(OBJEXT) +@DBUS_USE_EXPAT_TRUE@am__objects_7 = dbus_daemon_launch_helper_test-config-loader-expat.$(OBJEXT) +am__objects_8 = $(am__objects_7) \ + dbus_daemon_launch_helper_test-config-parser-common.$(OBJEXT) \ + dbus_daemon_launch_helper_test-config-parser-trivial.$(OBJEXT) \ + dbus_daemon_launch_helper_test-desktop-file.$(OBJEXT) \ + dbus_daemon_launch_helper_test-utils.$(OBJEXT) \ + dbus_daemon_launch_helper_test-activation-helper.$(OBJEXT) +am_dbus_daemon_launch_helper_test_OBJECTS = dbus_daemon_launch_helper_test-activation-helper-bin.$(OBJEXT) \ + $(am__objects_8) +dbus_daemon_launch_helper_test_OBJECTS = \ + $(am_dbus_daemon_launch_helper_test_OBJECTS) +dbus_daemon_launch_helper_test_DEPENDENCIES = \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(am__DEPENDENCIES_1) +dbus_daemon_launch_helper_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) \ + $(dbus_daemon_launch_helper_test_LDFLAGS) $(LDFLAGS) -o $@ +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(initddir)" "$(DESTDIR)$(man1dir)" \ + "$(DESTDIR)$(configdir)" +SCRIPTS = $(initd_SCRIPTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(bus_test_SOURCES) $(bus_test_launch_helper_SOURCES) \ + $(bus_test_system_SOURCES) $(dbus_daemon_SOURCES) \ + $(dbus_daemon_launch_helper_SOURCES) \ + $(dbus_daemon_launch_helper_test_SOURCES) +DIST_SOURCES = $(am__bus_test_SOURCES_DIST) \ + $(am__bus_test_launch_helper_SOURCES_DIST) \ + $(am__bus_test_system_SOURCES_DIST) \ + $(am__dbus_daemon_SOURCES_DIST) \ + $(am__dbus_daemon_launch_helper_SOURCES_DIST) \ + $(am__dbus_daemon_launch_helper_test_SOURCES_DIST) +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(man_MANS) +DATA = $(config_DATA) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DBUS_BINDIR = @DBUS_BINDIR@ +DBUS_BUS_CFLAGS = @DBUS_BUS_CFLAGS@ +DBUS_BUS_LIBS = @DBUS_BUS_LIBS@ +DBUS_CLIENT_CFLAGS = @DBUS_CLIENT_CFLAGS@ +DBUS_CLIENT_LIBS = @DBUS_CLIENT_LIBS@ +DBUS_CONSOLE_AUTH_DIR = @DBUS_CONSOLE_AUTH_DIR@ +DBUS_CONSOLE_OWNER_FILE = @DBUS_CONSOLE_OWNER_FILE@ +DBUS_DAEMONDIR = @DBUS_DAEMONDIR@ +DBUS_DATADIR = @DBUS_DATADIR@ +DBUS_HAVE_INT64 = @DBUS_HAVE_INT64@ +DBUS_INT16_TYPE = @DBUS_INT16_TYPE@ +DBUS_INT32_TYPE = @DBUS_INT32_TYPE@ +DBUS_INT64_CONSTANT = @DBUS_INT64_CONSTANT@ +DBUS_INT64_TYPE = @DBUS_INT64_TYPE@ +DBUS_LAUNCHER_CFLAGS = @DBUS_LAUNCHER_CFLAGS@ +DBUS_LAUNCHER_LIBS = @DBUS_LAUNCHER_LIBS@ +DBUS_LIBEXECDIR = @DBUS_LIBEXECDIR@ +DBUS_MAJOR_VERSION = @DBUS_MAJOR_VERSION@ +DBUS_MICRO_VERSION = @DBUS_MICRO_VERSION@ +DBUS_MINOR_VERSION = @DBUS_MINOR_VERSION@ +DBUS_PATH_OR_ABSTRACT = @DBUS_PATH_OR_ABSTRACT@ +DBUS_SESSION_SOCKET_DIR = @DBUS_SESSION_SOCKET_DIR@ +DBUS_SYSTEM_BUS_DEFAULT_ADDRESS = @DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ +DBUS_SYSTEM_PID_FILE = @DBUS_SYSTEM_PID_FILE@ +DBUS_SYSTEM_SOCKET = @DBUS_SYSTEM_SOCKET@ +DBUS_TEST_CFLAGS = @DBUS_TEST_CFLAGS@ +DBUS_TEST_LIBS = @DBUS_TEST_LIBS@ +DBUS_UINT64_CONSTANT = @DBUS_UINT64_CONSTANT@ +DBUS_USER = @DBUS_USER@ +DBUS_VERSION = @DBUS_VERSION@ +DBUS_X_CFLAGS = @DBUS_X_CFLAGS@ +DBUS_X_LIBS = @DBUS_X_LIBS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPANDED_BINDIR = @EXPANDED_BINDIR@ +EXPANDED_DATADIR = @EXPANDED_DATADIR@ +EXPANDED_LIBDIR = @EXPANDED_LIBDIR@ +EXPANDED_LIBEXECDIR = @EXPANDED_LIBEXECDIR@ +EXPANDED_LOCALSTATEDIR = @EXPANDED_LOCALSTATEDIR@ +EXPANDED_SYSCONFDIR = @EXPANDED_SYSCONFDIR@ +FGREP = @FGREP@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML_CFLAGS = @LIBXML_CFLAGS@ +LIBXML_LIBS = @LIBXML_LIBS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_AGE = @LT_AGE@ +LT_CURRENT = @LT_CURRENT@ +LT_REVISION = @LT_REVISION@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIC_CFLAGS = @PIC_CFLAGS@ +PIC_LDFLAGS = @PIC_LDFLAGS@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +R_DYNAMIC_LDFLAG = @R_DYNAMIC_LDFLAG@ +SECTION_FLAGS = @SECTION_FLAGS@ +SECTION_LDFLAGS = @SECTION_LDFLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TEST_BUS_BINARY = @TEST_BUS_BINARY@ +TEST_EXIT_BINARY = @TEST_EXIT_BINARY@ +TEST_INVALID_SERVICE_DIR = @TEST_INVALID_SERVICE_DIR@ +TEST_INVALID_SERVICE_SYSTEM_DIR = @TEST_INVALID_SERVICE_SYSTEM_DIR@ +TEST_LAUNCH_HELPER_BINARY = @TEST_LAUNCH_HELPER_BINARY@ +TEST_PRIVSERVER_BINARY = @TEST_PRIVSERVER_BINARY@ +TEST_SEGFAULT_BINARY = @TEST_SEGFAULT_BINARY@ +TEST_SERVICE_BINARY = @TEST_SERVICE_BINARY@ +TEST_SHELL_SERVICE_BINARY = @TEST_SHELL_SERVICE_BINARY@ +TEST_SLEEP_FOREVER_BINARY = @TEST_SLEEP_FOREVER_BINARY@ +TEST_SOCKET_DIR = @TEST_SOCKET_DIR@ +TEST_VALID_SERVICE_DIR = @TEST_VALID_SERVICE_DIR@ +TEST_VALID_SERVICE_SYSTEM_DIR = @TEST_VALID_SERVICE_SYSTEM_DIR@ +VERSION = @VERSION@ +XMKMF = @XMKMF@ +XMLTO = @XMLTO@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +configdir = $(sysconfdir)/dbus-1 +INCLUDES = -I$(top_srcdir) $(DBUS_BUS_CFLAGS) @PIE_CFLAGS@ \ + -DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\" \ + -DDAEMON_NAME=\"dbus-daemon\" -DDBUS_COMPILATION + +EFENCE = +CONFIG_IN_FILES = \ + session.conf.in \ + system.conf.in + +config_DATA = \ + session.conf \ + system.conf + +@DBUS_USE_EXPAT_TRUE@XML_SOURCES = config-loader-expat.c +@DBUS_USE_LIBXML_TRUE@XML_SOURCES = config-loader-libxml.c +@DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX_FALSE@@DBUS_BUS_ENABLE_INOTIFY_FALSE@@DBUS_BUS_ENABLE_KQUEUE_FALSE@DIR_WATCH_SOURCE = dir-watch-default.c +@DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX_TRUE@@DBUS_BUS_ENABLE_INOTIFY_FALSE@@DBUS_BUS_ENABLE_KQUEUE_FALSE@DIR_WATCH_SOURCE = dir-watch-dnotify.c +@DBUS_BUS_ENABLE_INOTIFY_TRUE@@DBUS_BUS_ENABLE_KQUEUE_FALSE@DIR_WATCH_SOURCE = dir-watch-inotify.c +@DBUS_BUS_ENABLE_KQUEUE_TRUE@DIR_WATCH_SOURCE = dir-watch-kqueue.c +BUS_SOURCES = \ + activation.c \ + activation.h \ + activation-exit-codes.h \ + bus.c \ + bus.h \ + config-parser.c \ + config-parser.h \ + config-parser-common.c \ + config-parser-common.h \ + connection.c \ + connection.h \ + desktop-file.c \ + desktop-file.h \ + $(DIR_WATCH_SOURCE) \ + dir-watch.h \ + dispatch.c \ + dispatch.h \ + driver.c \ + driver.h \ + expirelist.c \ + expirelist.h \ + policy.c \ + policy.h \ + selinux.h \ + selinux.c \ + services.c \ + services.h \ + signals.c \ + signals.h \ + test.c \ + test.h \ + utils.c \ + utils.h \ + $(XML_SOURCES) + +dbus_daemon_SOURCES = \ + $(BUS_SOURCES) \ + main.c + +dbus_daemon_LDADD = \ + $(EFENCE) \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(DBUS_BUS_LIBS) + +dbus_daemon_LDFLAGS = @R_DYNAMIC_LDFLAG@ @SECTION_LDFLAGS@ @PIE_LDFLAGS@ +LAUNCH_HELPER_SOURCES = \ + $(XML_SOURCES) \ + config-parser-common.c \ + config-parser-common.h \ + config-parser-trivial.c \ + config-parser-trivial.h \ + desktop-file.c \ + desktop-file.h \ + utils.c \ + utils.h \ + activation-exit-codes.h \ + activation-helper.h \ + activation-helper.c + +dbus_daemon_launch_helper_SOURCES = \ + activation-helper-bin.c \ + $(LAUNCH_HELPER_SOURCES) + +dbus_daemon_launch_helper_LDADD = \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(DBUS_LAUNCHER_LIBS) + +dbus_daemon_launch_helper_LDFLAGS = @R_DYNAMIC_LDFLAG@ @SECTION_LDFLAGS@ +dbus_daemon_launch_helper_test_SOURCES = \ + activation-helper-bin.c \ + $(LAUNCH_HELPER_SOURCES) + +dbus_daemon_launch_helper_test_LDADD = \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(DBUS_LAUNCHER_LIBS) + +dbus_daemon_launch_helper_test_LDFLAGS = @R_DYNAMIC_LDFLAG@ @SECTION_LDFLAGS@ +dbus_daemon_launch_helper_test_CPPFLAGS = \ + -DACTIVATION_LAUNCHER_TEST + +bus_test_launch_helper_SOURCES = \ + test-launch-helper.c \ + $(LAUNCH_HELPER_SOURCES) + +bus_test_launch_helper_LDADD = \ + $(top_builddir)/dbus/libdbus-convenience.la \ + $(DBUS_LAUNCHER_LIBS) + +bus_test_launch_helper_LDFLAGS = @R_DYNAMIC_LDFLAG@ @SECTION_LDFLAGS@ +bus_test_launch_helper_CPPFLAGS = \ + -DACTIVATION_LAUNCHER_TEST \ + -DACTIVATION_LAUNCHER_DO_OOM + +@DBUS_BUILD_TESTS_TRUE@TESTS_ENVIRONMENT = DBUS_TEST_DATA=$(top_builddir)/test/data DBUS_TEST_HOMEDIR=$(top_builddir)/dbus DBUS_FATAL_WARNINGS=1 DBUS_BLOCK_ON_ABORT=1 +bus_test_system_SOURCES = \ + $(XML_SOURCES) \ + config-parser-common.c \ + config-parser-common.h \ + config-parser-trivial.c \ + config-parser-trivial.h \ + utils.c \ + utils.h \ + test-system.c + +bus_test_system_LDADD = $(top_builddir)/dbus/libdbus-convenience.la $(DBUS_BUS_LIBS) +bus_test_system_LDFLAGS = @R_DYNAMIC_LDFLAG@ +bus_test_SOURCES = \ + $(BUS_SOURCES) \ + test-main.c + +bus_test_LDADD = $(top_builddir)/dbus/libdbus-convenience.la $(DBUS_BUS_LIBS) +bus_test_LDFLAGS = @R_DYNAMIC_LDFLAG@ + +#### Init scripts fun +SCRIPT_IN_FILES = messagebus.in \ + rc.messagebus.in + +@DBUS_INIT_SCRIPTS_RED_HAT_TRUE@initddir = $(sysconfdir)/rc.d/init.d +@DBUS_INIT_SCRIPTS_SLACKWARE_TRUE@initddir = $(sysconfdir)/rc.d/ +@DBUS_INIT_SCRIPTS_RED_HAT_TRUE@initd_SCRIPTS = \ +@DBUS_INIT_SCRIPTS_RED_HAT_TRUE@ messagebus + +@DBUS_INIT_SCRIPTS_SLACKWARE_TRUE@initd_SCRIPTS = \ +@DBUS_INIT_SCRIPTS_SLACKWARE_TRUE@ rc.messagebus + +MAN_IN_FILES = dbus-daemon.1.in +man_MANS = dbus-daemon.1 + +#### Extra dist +EXTRA_DIST = $(CONFIG_IN_FILES) $(SCRIPT_IN_FILES) $(man_MANS) $(MAN_IN_FILES) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu bus/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu bus/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +system.conf: $(top_builddir)/config.status $(srcdir)/system.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +session.conf: $(top_builddir)/config.status $(srcdir)/session.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +messagebus: $(top_builddir)/config.status $(srcdir)/messagebus.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +rc.messagebus: $(top_builddir)/config.status $(srcdir)/rc.messagebus.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +dbus-daemon.1: $(top_builddir)/config.status $(srcdir)/dbus-daemon.1.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +bus-test$(EXEEXT): $(bus_test_OBJECTS) $(bus_test_DEPENDENCIES) + @rm -f bus-test$(EXEEXT) + $(AM_V_CCLD)$(bus_test_LINK) $(bus_test_OBJECTS) $(bus_test_LDADD) $(LIBS) +bus-test-launch-helper$(EXEEXT): $(bus_test_launch_helper_OBJECTS) $(bus_test_launch_helper_DEPENDENCIES) + @rm -f bus-test-launch-helper$(EXEEXT) + $(AM_V_CCLD)$(bus_test_launch_helper_LINK) $(bus_test_launch_helper_OBJECTS) $(bus_test_launch_helper_LDADD) $(LIBS) +bus-test-system$(EXEEXT): $(bus_test_system_OBJECTS) $(bus_test_system_DEPENDENCIES) + @rm -f bus-test-system$(EXEEXT) + $(AM_V_CCLD)$(bus_test_system_LINK) $(bus_test_system_OBJECTS) $(bus_test_system_LDADD) $(LIBS) +dbus-daemon$(EXEEXT): $(dbus_daemon_OBJECTS) $(dbus_daemon_DEPENDENCIES) + @rm -f dbus-daemon$(EXEEXT) + $(AM_V_CCLD)$(dbus_daemon_LINK) $(dbus_daemon_OBJECTS) $(dbus_daemon_LDADD) $(LIBS) +dbus-daemon-launch-helper$(EXEEXT): $(dbus_daemon_launch_helper_OBJECTS) $(dbus_daemon_launch_helper_DEPENDENCIES) + @rm -f dbus-daemon-launch-helper$(EXEEXT) + $(AM_V_CCLD)$(dbus_daemon_launch_helper_LINK) $(dbus_daemon_launch_helper_OBJECTS) $(dbus_daemon_launch_helper_LDADD) $(LIBS) +dbus-daemon-launch-helper-test$(EXEEXT): $(dbus_daemon_launch_helper_test_OBJECTS) $(dbus_daemon_launch_helper_test_DEPENDENCIES) + @rm -f dbus-daemon-launch-helper-test$(EXEEXT) + $(AM_V_CCLD)$(dbus_daemon_launch_helper_test_LINK) $(dbus_daemon_launch_helper_test_OBJECTS) $(dbus_daemon_launch_helper_test_LDADD) $(LIBS) +install-initdSCRIPTS: $(initd_SCRIPTS) + @$(NORMAL_INSTALL) + test -z "$(initddir)" || $(MKDIR_P) "$(DESTDIR)$(initddir)" + @list='$(initd_SCRIPTS)'; test -n "$(initddir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(initddir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(initddir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-initdSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(initd_SCRIPTS)'; test -n "$(initddir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(initddir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(initddir)" && rm -f $$files + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/activation-helper-bin.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/activation-helper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/activation.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus_test_launch_helper-activation-helper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus_test_launch_helper-config-loader-expat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus_test_launch_helper-config-loader-libxml.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus_test_launch_helper-config-parser-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus_test_launch_helper-config-parser-trivial.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus_test_launch_helper-desktop-file.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus_test_launch_helper-test-launch-helper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus_test_launch_helper-utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config-loader-expat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config-loader-libxml.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config-parser-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config-parser-trivial.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config-parser.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper-bin.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-expat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-libxml.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-trivial.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus_daemon_launch_helper_test-desktop-file.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus_daemon_launch_helper_test-utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/desktop-file.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dir-watch-default.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dir-watch-dnotify.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dir-watch-inotify.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dir-watch-kqueue.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dispatch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/driver.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/expirelist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/policy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/selinux.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/services.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signals.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-system.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +bus_test_launch_helper-test-launch-helper.o: test-launch-helper.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-test-launch-helper.o -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-test-launch-helper.Tpo -c -o bus_test_launch_helper-test-launch-helper.o `test -f 'test-launch-helper.c' || echo '$(srcdir)/'`test-launch-helper.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-test-launch-helper.Tpo $(DEPDIR)/bus_test_launch_helper-test-launch-helper.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-launch-helper.c' object='bus_test_launch_helper-test-launch-helper.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-test-launch-helper.o `test -f 'test-launch-helper.c' || echo '$(srcdir)/'`test-launch-helper.c + +bus_test_launch_helper-test-launch-helper.obj: test-launch-helper.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-test-launch-helper.obj -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-test-launch-helper.Tpo -c -o bus_test_launch_helper-test-launch-helper.obj `if test -f 'test-launch-helper.c'; then $(CYGPATH_W) 'test-launch-helper.c'; else $(CYGPATH_W) '$(srcdir)/test-launch-helper.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-test-launch-helper.Tpo $(DEPDIR)/bus_test_launch_helper-test-launch-helper.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-launch-helper.c' object='bus_test_launch_helper-test-launch-helper.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-test-launch-helper.obj `if test -f 'test-launch-helper.c'; then $(CYGPATH_W) 'test-launch-helper.c'; else $(CYGPATH_W) '$(srcdir)/test-launch-helper.c'; fi` + +bus_test_launch_helper-config-loader-expat.o: config-loader-expat.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-config-loader-expat.o -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-config-loader-expat.Tpo -c -o bus_test_launch_helper-config-loader-expat.o `test -f 'config-loader-expat.c' || echo '$(srcdir)/'`config-loader-expat.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-config-loader-expat.Tpo $(DEPDIR)/bus_test_launch_helper-config-loader-expat.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-loader-expat.c' object='bus_test_launch_helper-config-loader-expat.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-config-loader-expat.o `test -f 'config-loader-expat.c' || echo '$(srcdir)/'`config-loader-expat.c + +bus_test_launch_helper-config-loader-expat.obj: config-loader-expat.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-config-loader-expat.obj -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-config-loader-expat.Tpo -c -o bus_test_launch_helper-config-loader-expat.obj `if test -f 'config-loader-expat.c'; then $(CYGPATH_W) 'config-loader-expat.c'; else $(CYGPATH_W) '$(srcdir)/config-loader-expat.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-config-loader-expat.Tpo $(DEPDIR)/bus_test_launch_helper-config-loader-expat.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-loader-expat.c' object='bus_test_launch_helper-config-loader-expat.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-config-loader-expat.obj `if test -f 'config-loader-expat.c'; then $(CYGPATH_W) 'config-loader-expat.c'; else $(CYGPATH_W) '$(srcdir)/config-loader-expat.c'; fi` + +bus_test_launch_helper-config-loader-libxml.o: config-loader-libxml.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-config-loader-libxml.o -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-config-loader-libxml.Tpo -c -o bus_test_launch_helper-config-loader-libxml.o `test -f 'config-loader-libxml.c' || echo '$(srcdir)/'`config-loader-libxml.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-config-loader-libxml.Tpo $(DEPDIR)/bus_test_launch_helper-config-loader-libxml.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-loader-libxml.c' object='bus_test_launch_helper-config-loader-libxml.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-config-loader-libxml.o `test -f 'config-loader-libxml.c' || echo '$(srcdir)/'`config-loader-libxml.c + +bus_test_launch_helper-config-loader-libxml.obj: config-loader-libxml.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-config-loader-libxml.obj -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-config-loader-libxml.Tpo -c -o bus_test_launch_helper-config-loader-libxml.obj `if test -f 'config-loader-libxml.c'; then $(CYGPATH_W) 'config-loader-libxml.c'; else $(CYGPATH_W) '$(srcdir)/config-loader-libxml.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-config-loader-libxml.Tpo $(DEPDIR)/bus_test_launch_helper-config-loader-libxml.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-loader-libxml.c' object='bus_test_launch_helper-config-loader-libxml.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-config-loader-libxml.obj `if test -f 'config-loader-libxml.c'; then $(CYGPATH_W) 'config-loader-libxml.c'; else $(CYGPATH_W) '$(srcdir)/config-loader-libxml.c'; fi` + +bus_test_launch_helper-config-parser-common.o: config-parser-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-config-parser-common.o -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-config-parser-common.Tpo -c -o bus_test_launch_helper-config-parser-common.o `test -f 'config-parser-common.c' || echo '$(srcdir)/'`config-parser-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-config-parser-common.Tpo $(DEPDIR)/bus_test_launch_helper-config-parser-common.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-parser-common.c' object='bus_test_launch_helper-config-parser-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-config-parser-common.o `test -f 'config-parser-common.c' || echo '$(srcdir)/'`config-parser-common.c + +bus_test_launch_helper-config-parser-common.obj: config-parser-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-config-parser-common.obj -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-config-parser-common.Tpo -c -o bus_test_launch_helper-config-parser-common.obj `if test -f 'config-parser-common.c'; then $(CYGPATH_W) 'config-parser-common.c'; else $(CYGPATH_W) '$(srcdir)/config-parser-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-config-parser-common.Tpo $(DEPDIR)/bus_test_launch_helper-config-parser-common.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-parser-common.c' object='bus_test_launch_helper-config-parser-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-config-parser-common.obj `if test -f 'config-parser-common.c'; then $(CYGPATH_W) 'config-parser-common.c'; else $(CYGPATH_W) '$(srcdir)/config-parser-common.c'; fi` + +bus_test_launch_helper-config-parser-trivial.o: config-parser-trivial.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-config-parser-trivial.o -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-config-parser-trivial.Tpo -c -o bus_test_launch_helper-config-parser-trivial.o `test -f 'config-parser-trivial.c' || echo '$(srcdir)/'`config-parser-trivial.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-config-parser-trivial.Tpo $(DEPDIR)/bus_test_launch_helper-config-parser-trivial.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-parser-trivial.c' object='bus_test_launch_helper-config-parser-trivial.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-config-parser-trivial.o `test -f 'config-parser-trivial.c' || echo '$(srcdir)/'`config-parser-trivial.c + +bus_test_launch_helper-config-parser-trivial.obj: config-parser-trivial.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-config-parser-trivial.obj -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-config-parser-trivial.Tpo -c -o bus_test_launch_helper-config-parser-trivial.obj `if test -f 'config-parser-trivial.c'; then $(CYGPATH_W) 'config-parser-trivial.c'; else $(CYGPATH_W) '$(srcdir)/config-parser-trivial.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-config-parser-trivial.Tpo $(DEPDIR)/bus_test_launch_helper-config-parser-trivial.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-parser-trivial.c' object='bus_test_launch_helper-config-parser-trivial.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-config-parser-trivial.obj `if test -f 'config-parser-trivial.c'; then $(CYGPATH_W) 'config-parser-trivial.c'; else $(CYGPATH_W) '$(srcdir)/config-parser-trivial.c'; fi` + +bus_test_launch_helper-desktop-file.o: desktop-file.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-desktop-file.o -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-desktop-file.Tpo -c -o bus_test_launch_helper-desktop-file.o `test -f 'desktop-file.c' || echo '$(srcdir)/'`desktop-file.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-desktop-file.Tpo $(DEPDIR)/bus_test_launch_helper-desktop-file.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='desktop-file.c' object='bus_test_launch_helper-desktop-file.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-desktop-file.o `test -f 'desktop-file.c' || echo '$(srcdir)/'`desktop-file.c + +bus_test_launch_helper-desktop-file.obj: desktop-file.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-desktop-file.obj -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-desktop-file.Tpo -c -o bus_test_launch_helper-desktop-file.obj `if test -f 'desktop-file.c'; then $(CYGPATH_W) 'desktop-file.c'; else $(CYGPATH_W) '$(srcdir)/desktop-file.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-desktop-file.Tpo $(DEPDIR)/bus_test_launch_helper-desktop-file.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='desktop-file.c' object='bus_test_launch_helper-desktop-file.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-desktop-file.obj `if test -f 'desktop-file.c'; then $(CYGPATH_W) 'desktop-file.c'; else $(CYGPATH_W) '$(srcdir)/desktop-file.c'; fi` + +bus_test_launch_helper-utils.o: utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-utils.o -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-utils.Tpo -c -o bus_test_launch_helper-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-utils.Tpo $(DEPDIR)/bus_test_launch_helper-utils.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils.c' object='bus_test_launch_helper-utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c + +bus_test_launch_helper-utils.obj: utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-utils.obj -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-utils.Tpo -c -o bus_test_launch_helper-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-utils.Tpo $(DEPDIR)/bus_test_launch_helper-utils.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils.c' object='bus_test_launch_helper-utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi` + +bus_test_launch_helper-activation-helper.o: activation-helper.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-activation-helper.o -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-activation-helper.Tpo -c -o bus_test_launch_helper-activation-helper.o `test -f 'activation-helper.c' || echo '$(srcdir)/'`activation-helper.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-activation-helper.Tpo $(DEPDIR)/bus_test_launch_helper-activation-helper.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='activation-helper.c' object='bus_test_launch_helper-activation-helper.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-activation-helper.o `test -f 'activation-helper.c' || echo '$(srcdir)/'`activation-helper.c + +bus_test_launch_helper-activation-helper.obj: activation-helper.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT bus_test_launch_helper-activation-helper.obj -MD -MP -MF $(DEPDIR)/bus_test_launch_helper-activation-helper.Tpo -c -o bus_test_launch_helper-activation-helper.obj `if test -f 'activation-helper.c'; then $(CYGPATH_W) 'activation-helper.c'; else $(CYGPATH_W) '$(srcdir)/activation-helper.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/bus_test_launch_helper-activation-helper.Tpo $(DEPDIR)/bus_test_launch_helper-activation-helper.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='activation-helper.c' object='bus_test_launch_helper-activation-helper.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(bus_test_launch_helper_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o bus_test_launch_helper-activation-helper.obj `if test -f 'activation-helper.c'; then $(CYGPATH_W) 'activation-helper.c'; else $(CYGPATH_W) '$(srcdir)/activation-helper.c'; fi` + +dbus_daemon_launch_helper_test-activation-helper-bin.o: activation-helper-bin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-activation-helper-bin.o -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper-bin.Tpo -c -o dbus_daemon_launch_helper_test-activation-helper-bin.o `test -f 'activation-helper-bin.c' || echo '$(srcdir)/'`activation-helper-bin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper-bin.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper-bin.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='activation-helper-bin.c' object='dbus_daemon_launch_helper_test-activation-helper-bin.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-activation-helper-bin.o `test -f 'activation-helper-bin.c' || echo '$(srcdir)/'`activation-helper-bin.c + +dbus_daemon_launch_helper_test-activation-helper-bin.obj: activation-helper-bin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-activation-helper-bin.obj -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper-bin.Tpo -c -o dbus_daemon_launch_helper_test-activation-helper-bin.obj `if test -f 'activation-helper-bin.c'; then $(CYGPATH_W) 'activation-helper-bin.c'; else $(CYGPATH_W) '$(srcdir)/activation-helper-bin.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper-bin.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper-bin.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='activation-helper-bin.c' object='dbus_daemon_launch_helper_test-activation-helper-bin.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-activation-helper-bin.obj `if test -f 'activation-helper-bin.c'; then $(CYGPATH_W) 'activation-helper-bin.c'; else $(CYGPATH_W) '$(srcdir)/activation-helper-bin.c'; fi` + +dbus_daemon_launch_helper_test-config-loader-expat.o: config-loader-expat.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-config-loader-expat.o -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-expat.Tpo -c -o dbus_daemon_launch_helper_test-config-loader-expat.o `test -f 'config-loader-expat.c' || echo '$(srcdir)/'`config-loader-expat.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-expat.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-expat.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-loader-expat.c' object='dbus_daemon_launch_helper_test-config-loader-expat.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-config-loader-expat.o `test -f 'config-loader-expat.c' || echo '$(srcdir)/'`config-loader-expat.c + +dbus_daemon_launch_helper_test-config-loader-expat.obj: config-loader-expat.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-config-loader-expat.obj -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-expat.Tpo -c -o dbus_daemon_launch_helper_test-config-loader-expat.obj `if test -f 'config-loader-expat.c'; then $(CYGPATH_W) 'config-loader-expat.c'; else $(CYGPATH_W) '$(srcdir)/config-loader-expat.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-expat.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-expat.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-loader-expat.c' object='dbus_daemon_launch_helper_test-config-loader-expat.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-config-loader-expat.obj `if test -f 'config-loader-expat.c'; then $(CYGPATH_W) 'config-loader-expat.c'; else $(CYGPATH_W) '$(srcdir)/config-loader-expat.c'; fi` + +dbus_daemon_launch_helper_test-config-loader-libxml.o: config-loader-libxml.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-config-loader-libxml.o -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-libxml.Tpo -c -o dbus_daemon_launch_helper_test-config-loader-libxml.o `test -f 'config-loader-libxml.c' || echo '$(srcdir)/'`config-loader-libxml.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-libxml.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-libxml.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-loader-libxml.c' object='dbus_daemon_launch_helper_test-config-loader-libxml.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-config-loader-libxml.o `test -f 'config-loader-libxml.c' || echo '$(srcdir)/'`config-loader-libxml.c + +dbus_daemon_launch_helper_test-config-loader-libxml.obj: config-loader-libxml.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-config-loader-libxml.obj -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-libxml.Tpo -c -o dbus_daemon_launch_helper_test-config-loader-libxml.obj `if test -f 'config-loader-libxml.c'; then $(CYGPATH_W) 'config-loader-libxml.c'; else $(CYGPATH_W) '$(srcdir)/config-loader-libxml.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-libxml.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-config-loader-libxml.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-loader-libxml.c' object='dbus_daemon_launch_helper_test-config-loader-libxml.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-config-loader-libxml.obj `if test -f 'config-loader-libxml.c'; then $(CYGPATH_W) 'config-loader-libxml.c'; else $(CYGPATH_W) '$(srcdir)/config-loader-libxml.c'; fi` + +dbus_daemon_launch_helper_test-config-parser-common.o: config-parser-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-config-parser-common.o -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-common.Tpo -c -o dbus_daemon_launch_helper_test-config-parser-common.o `test -f 'config-parser-common.c' || echo '$(srcdir)/'`config-parser-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-common.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-common.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-parser-common.c' object='dbus_daemon_launch_helper_test-config-parser-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-config-parser-common.o `test -f 'config-parser-common.c' || echo '$(srcdir)/'`config-parser-common.c + +dbus_daemon_launch_helper_test-config-parser-common.obj: config-parser-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-config-parser-common.obj -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-common.Tpo -c -o dbus_daemon_launch_helper_test-config-parser-common.obj `if test -f 'config-parser-common.c'; then $(CYGPATH_W) 'config-parser-common.c'; else $(CYGPATH_W) '$(srcdir)/config-parser-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-common.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-common.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-parser-common.c' object='dbus_daemon_launch_helper_test-config-parser-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-config-parser-common.obj `if test -f 'config-parser-common.c'; then $(CYGPATH_W) 'config-parser-common.c'; else $(CYGPATH_W) '$(srcdir)/config-parser-common.c'; fi` + +dbus_daemon_launch_helper_test-config-parser-trivial.o: config-parser-trivial.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-config-parser-trivial.o -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-trivial.Tpo -c -o dbus_daemon_launch_helper_test-config-parser-trivial.o `test -f 'config-parser-trivial.c' || echo '$(srcdir)/'`config-parser-trivial.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-trivial.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-trivial.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-parser-trivial.c' object='dbus_daemon_launch_helper_test-config-parser-trivial.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-config-parser-trivial.o `test -f 'config-parser-trivial.c' || echo '$(srcdir)/'`config-parser-trivial.c + +dbus_daemon_launch_helper_test-config-parser-trivial.obj: config-parser-trivial.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-config-parser-trivial.obj -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-trivial.Tpo -c -o dbus_daemon_launch_helper_test-config-parser-trivial.obj `if test -f 'config-parser-trivial.c'; then $(CYGPATH_W) 'config-parser-trivial.c'; else $(CYGPATH_W) '$(srcdir)/config-parser-trivial.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-trivial.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-config-parser-trivial.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='config-parser-trivial.c' object='dbus_daemon_launch_helper_test-config-parser-trivial.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-config-parser-trivial.obj `if test -f 'config-parser-trivial.c'; then $(CYGPATH_W) 'config-parser-trivial.c'; else $(CYGPATH_W) '$(srcdir)/config-parser-trivial.c'; fi` + +dbus_daemon_launch_helper_test-desktop-file.o: desktop-file.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-desktop-file.o -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-desktop-file.Tpo -c -o dbus_daemon_launch_helper_test-desktop-file.o `test -f 'desktop-file.c' || echo '$(srcdir)/'`desktop-file.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-desktop-file.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-desktop-file.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='desktop-file.c' object='dbus_daemon_launch_helper_test-desktop-file.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-desktop-file.o `test -f 'desktop-file.c' || echo '$(srcdir)/'`desktop-file.c + +dbus_daemon_launch_helper_test-desktop-file.obj: desktop-file.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-desktop-file.obj -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-desktop-file.Tpo -c -o dbus_daemon_launch_helper_test-desktop-file.obj `if test -f 'desktop-file.c'; then $(CYGPATH_W) 'desktop-file.c'; else $(CYGPATH_W) '$(srcdir)/desktop-file.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-desktop-file.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-desktop-file.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='desktop-file.c' object='dbus_daemon_launch_helper_test-desktop-file.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-desktop-file.obj `if test -f 'desktop-file.c'; then $(CYGPATH_W) 'desktop-file.c'; else $(CYGPATH_W) '$(srcdir)/desktop-file.c'; fi` + +dbus_daemon_launch_helper_test-utils.o: utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-utils.o -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-utils.Tpo -c -o dbus_daemon_launch_helper_test-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-utils.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-utils.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils.c' object='dbus_daemon_launch_helper_test-utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-utils.o `test -f 'utils.c' || echo '$(srcdir)/'`utils.c + +dbus_daemon_launch_helper_test-utils.obj: utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-utils.obj -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-utils.Tpo -c -o dbus_daemon_launch_helper_test-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-utils.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-utils.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils.c' object='dbus_daemon_launch_helper_test-utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-utils.obj `if test -f 'utils.c'; then $(CYGPATH_W) 'utils.c'; else $(CYGPATH_W) '$(srcdir)/utils.c'; fi` + +dbus_daemon_launch_helper_test-activation-helper.o: activation-helper.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-activation-helper.o -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper.Tpo -c -o dbus_daemon_launch_helper_test-activation-helper.o `test -f 'activation-helper.c' || echo '$(srcdir)/'`activation-helper.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='activation-helper.c' object='dbus_daemon_launch_helper_test-activation-helper.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-activation-helper.o `test -f 'activation-helper.c' || echo '$(srcdir)/'`activation-helper.c + +dbus_daemon_launch_helper_test-activation-helper.obj: activation-helper.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dbus_daemon_launch_helper_test-activation-helper.obj -MD -MP -MF $(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper.Tpo -c -o dbus_daemon_launch_helper_test-activation-helper.obj `if test -f 'activation-helper.c'; then $(CYGPATH_W) 'activation-helper.c'; else $(CYGPATH_W) '$(srcdir)/activation-helper.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper.Tpo $(DEPDIR)/dbus_daemon_launch_helper_test-activation-helper.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='activation-helper.c' object='dbus_daemon_launch_helper_test-activation-helper.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(dbus_daemon_launch_helper_test_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dbus_daemon_launch_helper_test-activation-helper.obj `if test -f 'activation-helper.c'; then $(CYGPATH_W) 'activation-helper.c'; else $(CYGPATH_W) '$(srcdir)/activation-helper.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man1: $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" + @list=''; test -n "$(man1dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man1dir)" && rm -f $$files; } +install-configDATA: $(config_DATA) + @$(NORMAL_INSTALL) + test -z "$(configdir)" || $(MKDIR_P) "$(DESTDIR)$(configdir)" + @list='$(config_DATA)'; test -n "$(configdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(configdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(configdir)" || exit $$?; \ + done + +uninstall-configDATA: + @$(NORMAL_UNINSTALL) + @list='$(config_DATA)'; test -n "$(configdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(configdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(configdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @list='$(MANS)'; if test -n "$$list"; then \ + list=`for p in $$list; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ + if test -n "$$list" && \ + grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ + echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ + grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ + echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ + echo " typically \`make maintainer-clean' will remove them" >&2; \ + exit 1; \ + else :; fi; \ + else :; fi + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(MANS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(initddir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(configdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-local clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-configDATA install-initdSCRIPTS install-man + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man1 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-configDATA uninstall-initdSCRIPTS \ + uninstall-man + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-hook +uninstall-man: uninstall-man1 + +.MAKE: check-am install-am install-data-am install-strip uninstall-am + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-generic clean-libtool clean-local clean-noinstPROGRAMS \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-configDATA \ + install-data install-data-am install-data-hook install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-initdSCRIPTS install-man install-man1 install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-configDATA \ + uninstall-hook uninstall-initdSCRIPTS uninstall-man \ + uninstall-man1 + + +clean-local: + /bin/rm *.bb *.bbg *.da *.gcov || true + +uninstall-hook: + rm -f $(DESTDIR)$(DBUS_DAEMONDIR)/dbus-daemon + rm -f $(DESTDIR)$(libexecdir)/dbus-daemon-launch-helper + +install-data-hook: + if test '!' -d $(DESTDIR)$(DBUS_DAEMONDIR); then \ + $(mkinstalldirs) $(DESTDIR)$(DBUS_DAEMONDIR); \ + chmod 755 $(DESTDIR)$(DBUS_DAEMONDIR); \ + fi + $(INSTALL_PROGRAM) dbus-daemon $(DESTDIR)$(DBUS_DAEMONDIR) + $(mkinstalldirs) $(DESTDIR)$(localstatedir)/run/dbus + $(mkinstalldirs) $(DESTDIR)$(configdir)/system.d + $(mkinstalldirs) $(DESTDIR)$(configdir)/session.d + $(mkinstalldirs) $(DESTDIR)$(datadir)/dbus-1/services + $(mkinstalldirs) $(DESTDIR)$(datadir)/dbus-1/system-services + $(mkinstalldirs) $(DESTDIR)$(libexecdir)/dbus-1 + $(INSTALL_PROGRAM) dbus-daemon-launch-helper $(DESTDIR)$(libexecdir) + if test `id -u` -eq 0; then \ + chown root:$(DBUS_USER) $(DESTDIR)$(libexecdir)/dbus-daemon-launch-helper; \ + chmod 4750 $(DESTDIR)$(libexecdir)/dbus-daemon-launch-helper; \ + else \ + echo "Not installing $(DESTDIR)$(libexecdir)/dbus-daemon-launch-helper binary setuid!"; \ + echo "You'll need to manually set permissions to root:$(DBUS_USER) and permissions 4750"; \ + fi + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/bus/activation-exit-codes.h b/bus/activation-exit-codes.h new file mode 100644 index 00000000..bbb98dca --- /dev/null +++ b/bus/activation-exit-codes.h @@ -0,0 +1,45 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* activation-exit-codes.h Return values for the launch helper which is set + * in the helper and read in dbus-spawn. + * + * Copyright (C) 2007 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_ACTIVATION_EXIT_CODES_H +#define BUS_ACTIVATION_EXIT_CODES_H + +/** Return codes from the launch helper - not public API. However, + * presumably if some third party did write their own launch helper, + * they would have to rely on these, or at least always return + * 1 for GENERIC_FAILURE. + */ +#define BUS_SPAWN_EXIT_CODE_GENERIC_FAILURE 1 +#define BUS_SPAWN_EXIT_CODE_NO_MEMORY 2 +#define BUS_SPAWN_EXIT_CODE_CONFIG_INVALID 3 +#define BUS_SPAWN_EXIT_CODE_SETUP_FAILED 4 +#define BUS_SPAWN_EXIT_CODE_NAME_INVALID 5 +#define BUS_SPAWN_EXIT_CODE_SERVICE_NOT_FOUND 6 +#define BUS_SPAWN_EXIT_CODE_PERMISSIONS_INVALID 7 +#define BUS_SPAWN_EXIT_CODE_FILE_INVALID 8 +#define BUS_SPAWN_EXIT_CODE_EXEC_FAILED 9 +#define BUS_SPAWN_EXIT_CODE_INVALID_ARGS 10 +#define BUS_SPAWN_EXIT_CODE_CHILD_SIGNALED 11 + +#endif /* BUS_ACTIVATION_EXIT_CODES_H */ diff --git a/bus/activation-helper-bin.c b/bus/activation-helper-bin.c new file mode 100644 index 00000000..a360acc7 --- /dev/null +++ b/bus/activation-helper-bin.c @@ -0,0 +1,100 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* activation-helper-bin.c Setuid helper for launching programs as a custom + * user. This file is security sensitive. + * + * Copyright (C) 2007 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#include "utils.h" +#include "activation-helper.h" +#include "activation-exit-codes.h" + +#include +#include +#include + +static int +convert_error_to_exit_code (DBusError *error) +{ + if (dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY)) + return BUS_SPAWN_EXIT_CODE_NO_MEMORY; + + if (dbus_error_has_name (error, DBUS_ERROR_SPAWN_CONFIG_INVALID)) + return BUS_SPAWN_EXIT_CODE_CONFIG_INVALID; + + if (dbus_error_has_name (error, DBUS_ERROR_SPAWN_SETUP_FAILED)) + return BUS_SPAWN_EXIT_CODE_SETUP_FAILED; + + if (dbus_error_has_name (error, DBUS_ERROR_SPAWN_SERVICE_INVALID)) + return BUS_SPAWN_EXIT_CODE_SERVICE_NOT_FOUND; + + if (dbus_error_has_name (error, DBUS_ERROR_SPAWN_PERMISSIONS_INVALID)) + return BUS_SPAWN_EXIT_CODE_PERMISSIONS_INVALID; + + if (dbus_error_has_name (error, DBUS_ERROR_SPAWN_FILE_INVALID)) + return BUS_SPAWN_EXIT_CODE_FILE_INVALID; + + if (dbus_error_has_name (error, DBUS_ERROR_SPAWN_EXEC_FAILED)) + return BUS_SPAWN_EXIT_CODE_EXEC_FAILED; + + if (dbus_error_has_name (error, DBUS_ERROR_INVALID_ARGS)) + return BUS_SPAWN_EXIT_CODE_INVALID_ARGS; + + if (dbus_error_has_name (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED)) + return BUS_SPAWN_EXIT_CODE_CHILD_SIGNALED; + + /* should we assert? */ + fprintf(stderr, "%s: %s\n", error->name, error->message); + + return BUS_SPAWN_EXIT_CODE_SETUP_FAILED; +} + +int +main (int argc, char **argv) +{ + DBusError error; + int retval; + + /* default is all okay */ + retval = 0; + + /* have we used a help option or not specified the correct arguments? */ + if (argc != 2 || + strcmp (argv[1], "--help") == 0 || + strcmp (argv[1], "-h") == 0 || + strcmp (argv[1], "-?") == 0) + { + fprintf (stderr, "dbus-daemon-activation-helper service.to.activate\n"); + exit (0); + } + + dbus_error_init (&error); + if (!run_launch_helper (argv[1], &error)) + { + /* convert error to an exit code */ + retval = convert_error_to_exit_code (&error); + dbus_error_free (&error); + } + + return retval; +} + diff --git a/bus/activation-helper.c b/bus/activation-helper.c new file mode 100644 index 00000000..baba8f04 --- /dev/null +++ b/bus/activation-helper.c @@ -0,0 +1,563 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* activation-helper.c Setuid helper for launching programs as a custom + * user. This file is security sensitive. + * + * Copyright (C) 2007 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#include "bus.h" +#include "driver.h" +#include "utils.h" +#include "desktop-file.h" +#include "config-parser-trivial.h" +#include "activation-helper.h" +#include "activation-exit-codes.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static BusDesktopFile * +desktop_file_for_name (BusConfigParser *parser, + const char *name, + DBusError *error) +{ + BusDesktopFile *desktop_file; + DBusList **service_dirs; + DBusList *link; + DBusError tmp_error; + DBusString full_path; + DBusString filename; + const char *dir; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + desktop_file = NULL; + + if (!_dbus_string_init (&filename)) + { + BUS_SET_OOM (error); + goto out_all; + } + + if (!_dbus_string_init (&full_path)) + { + BUS_SET_OOM (error); + goto out_filename; + } + + if (!_dbus_string_append (&filename, name) || + !_dbus_string_append (&filename, ".service")) + { + BUS_SET_OOM (error); + goto out; + } + + service_dirs = bus_config_parser_get_service_dirs (parser); + for (link = _dbus_list_get_first_link (service_dirs); + link != NULL; + link = _dbus_list_get_next_link (service_dirs, link)) + { + dir = link->data; + _dbus_verbose ("Looking at '%s'\n", dir); + + dbus_error_init (&tmp_error); + + /* clear the path from last time */ + _dbus_string_set_length (&full_path, 0); + + /* build the full path */ + if (!_dbus_string_append (&full_path, dir) || + !_dbus_concat_dir_and_file (&full_path, &filename)) + { + BUS_SET_OOM (error); + goto out; + } + + _dbus_verbose ("Trying to load file '%s'\n", _dbus_string_get_data (&full_path)); + desktop_file = bus_desktop_file_load (&full_path, &tmp_error); + if (desktop_file == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + _dbus_verbose ("Could not load %s: %s: %s\n", + _dbus_string_get_const_data (&full_path), + tmp_error.name, tmp_error.message); + + /* we may have failed if the file is not found; this is not fatal */ + if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) + { + dbus_move_error (&tmp_error, error); + /* we only bail out on OOM */ + goto out; + } + dbus_error_free (&tmp_error); + } + + /* did we find the desktop file we want? */ + if (desktop_file != NULL) + break; + } + + /* Didn't find desktop file; set error */ + if (desktop_file == NULL) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND, + "The name %s was not provided by any .service files", + name); + } + +out: + _dbus_string_free (&full_path); +out_filename: + _dbus_string_free (&filename); +out_all: + return desktop_file; +} + +/* Cleares the environment, except for DBUS_VERBOSE and DBUS_STARTER_x */ +static dbus_bool_t +clear_environment (DBusError *error) +{ + const char *debug_env = NULL; + const char *starter_env = NULL; + +#ifdef DBUS_ENABLE_VERBOSE_MODE + /* are we debugging */ + debug_env = _dbus_getenv ("DBUS_VERBOSE"); +#endif + + /* we save the starter */ + starter_env = _dbus_getenv ("DBUS_STARTER_ADDRESS"); + +#ifndef ACTIVATION_LAUNCHER_TEST + /* totally clear the environment */ + if (!_dbus_clearenv ()) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_SETUP_FAILED, + "could not clear environment\n"); + return FALSE; + } +#endif + +#ifdef DBUS_ENABLE_VERBOSE_MODE + /* restore the debugging environment setting if set */ + if (debug_env) + _dbus_setenv ("DBUS_VERBOSE", debug_env); +#endif + + /* restore the starter */ + if (starter_env) + _dbus_setenv ("DBUS_STARTER_ADDRESS", starter_env); + + /* set the type, which must be system if we got this far */ + _dbus_setenv ("DBUS_STARTER_BUS_TYPE", "system"); + + return TRUE; +} + +static dbus_bool_t +check_permissions (const char *dbus_user, DBusError *error) +{ + uid_t uid, euid; + struct passwd *pw; + + pw = NULL; + uid = 0; + euid = 0; + +#ifndef ACTIVATION_LAUNCHER_TEST + /* bail out unless the dbus user is invoking the helper */ + pw = getpwnam(dbus_user); + if (!pw) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_PERMISSIONS_INVALID, + "cannot find user '%s'", dbus_user); + return FALSE; + } + uid = getuid(); + if (pw->pw_uid != uid) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_PERMISSIONS_INVALID, + "not invoked from user '%s'", dbus_user); + return FALSE; + } + + /* bail out unless we are setuid to user root */ + euid = geteuid(); + if (euid != 0) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_PERMISSIONS_INVALID, + "not setuid root"); + return FALSE; + } +#endif + + return TRUE; +} + +static dbus_bool_t +check_service_name (BusDesktopFile *desktop_file, + const char *service_name, + DBusError *error) +{ + char *name_tmp; + dbus_bool_t retval; + + retval = FALSE; + + /* try to get Name */ + if (!bus_desktop_file_get_string (desktop_file, + DBUS_SERVICE_SECTION, + DBUS_SERVICE_NAME, + &name_tmp, + error)) + goto failed; + + /* verify that the name is the same as the file service name */ + if (strcmp (service_name, name_tmp) != 0) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_FILE_INVALID, + "Service '%s' does not match expected value", name_tmp); + goto failed_free; + } + + retval = TRUE; + +failed_free: + /* we don't return the name, so free it here */ + dbus_free (name_tmp); +failed: + return retval; +} + +static dbus_bool_t +get_parameters_for_service (BusDesktopFile *desktop_file, + const char *service_name, + char **exec, + char **user, + DBusError *error) +{ + char *exec_tmp; + char *user_tmp; + + exec_tmp = NULL; + user_tmp = NULL; + + /* check the name of the service */ + if (!check_service_name (desktop_file, service_name, error)) + goto failed; + + /* get the complete path of the executable */ + if (!bus_desktop_file_get_string (desktop_file, + DBUS_SERVICE_SECTION, + DBUS_SERVICE_EXEC, + &exec_tmp, + error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + /* get the user that should run this service - user is compulsary for system activation */ + if (!bus_desktop_file_get_string (desktop_file, + DBUS_SERVICE_SECTION, + DBUS_SERVICE_USER, + &user_tmp, + error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + /* only assign if all the checks passed */ + *exec = exec_tmp; + *user = user_tmp; + return TRUE; + +failed: + dbus_free (exec_tmp); + dbus_free (user_tmp); + return FALSE; +} + +static dbus_bool_t +switch_user (char *user, DBusError *error) +{ +#ifndef ACTIVATION_LAUNCHER_TEST + struct passwd *pw; + + /* find user */ + pw = getpwnam (user); + if (!pw) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_SETUP_FAILED, + "cannot find user '%s'\n", user); + return FALSE; + } + + /* initialize the group access list */ + if (initgroups (user, pw->pw_gid)) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_SETUP_FAILED, + "could not initialize groups"); + return FALSE; + } + + /* change to the primary group for the user */ + if (setgid (pw->pw_gid)) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_SETUP_FAILED, + "cannot setgid group %i", pw->pw_gid); + return FALSE; + } + + /* change to the user specified */ + if (setuid (pw->pw_uid) < 0) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_SETUP_FAILED, + "cannot setuid user %i", pw->pw_uid); + return FALSE; + } +#endif + return TRUE; +} + +static dbus_bool_t +exec_for_correct_user (char *exec, char *user, DBusError *error) +{ + char **argv; + int argc; + dbus_bool_t retval; + + argc = 0; + retval = TRUE; + argv = NULL; + + if (!switch_user (user, error)) + return FALSE; + + /* convert command into arguments */ + if (!_dbus_shell_parse_argv (exec, &argc, &argv, error)) + return FALSE; + +#ifndef ACTIVATION_LAUNCHER_DO_OOM + /* replace with new binary, with no environment */ + if (execv (argv[0], argv) < 0) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, + "Failed to exec: %s", argv[0]); + retval = FALSE; + } +#endif + + dbus_free_string_array (argv); + return retval; +} + +static dbus_bool_t +check_bus_name (const char *bus_name, + DBusError *error) +{ + DBusString str; + + _dbus_string_init_const (&str, bus_name); + if (!_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str))) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND, + "bus name '%s' is not a valid bus name\n", + bus_name); + return FALSE; + } + + return TRUE; +} + +static dbus_bool_t +get_correct_parser (BusConfigParser **parser, DBusError *error) +{ + DBusString config_file; + dbus_bool_t retval; + const char *test_config_file; + + retval = FALSE; + test_config_file = NULL; + +#ifdef ACTIVATION_LAUNCHER_TEST + /* there is no _way_ we should be setuid if this define is set. + * but we should be doubly paranoid and check... */ + if (getuid() != geteuid()) + _dbus_assert_not_reached ("dbus-daemon-launch-helper-test binary is setuid!"); + + /* this is not a security hole. The environment variable is only passed in the + * dbus-daemon-lauch-helper-test NON-SETUID launcher */ + test_config_file = _dbus_getenv ("TEST_LAUNCH_HELPER_CONFIG"); + if (test_config_file == NULL) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_SETUP_FAILED, + "the TEST_LAUNCH_HELPER_CONFIG env variable is not set"); + goto out; + } +#endif + + /* we _only_ use the predefined system config file */ + if (!_dbus_string_init (&config_file)) + { + BUS_SET_OOM (error); + goto out; + } +#ifndef ACTIVATION_LAUNCHER_TEST + if (!_dbus_string_append (&config_file, DBUS_SYSTEM_CONFIG_FILE)) + { + BUS_SET_OOM (error); + goto out_free_config; + } +#else + if (!_dbus_string_append (&config_file, test_config_file)) + { + BUS_SET_OOM (error); + goto out_free_config; + } +#endif + + /* where are we pointing.... */ + _dbus_verbose ("dbus-daemon-activation-helper: using config file: %s\n", + _dbus_string_get_const_data (&config_file)); + + /* get the dbus user */ + *parser = bus_config_load (&config_file, TRUE, NULL, error); + if (*parser == NULL) + { + goto out_free_config; + } + + /* woot */ + retval = TRUE; + +out_free_config: + _dbus_string_free (&config_file); +out: + return retval; +} + +static dbus_bool_t +launch_bus_name (const char *bus_name, BusConfigParser *parser, DBusError *error) +{ + BusDesktopFile *desktop_file; + char *exec, *user; + dbus_bool_t retval; + + exec = NULL; + user = NULL; + retval = FALSE; + + /* get the correct service file for the name we are trying to activate */ + desktop_file = desktop_file_for_name (parser, bus_name, error); + if (desktop_file == NULL) + return FALSE; + + /* get exec and user for service name */ + if (!get_parameters_for_service (desktop_file, bus_name, &exec, &user, error)) + goto finish; + + _dbus_verbose ("dbus-daemon-activation-helper: Name='%s'\n", bus_name); + _dbus_verbose ("dbus-daemon-activation-helper: Exec='%s'\n", exec); + _dbus_verbose ("dbus-daemon-activation-helper: User='%s'\n", user); + + /* actually execute */ + if (!exec_for_correct_user (exec, user, error)) + goto finish; + + retval = TRUE; + +finish: + dbus_free (exec); + dbus_free (user); + bus_desktop_file_free (desktop_file); + return retval; +} + +static dbus_bool_t +check_dbus_user (BusConfigParser *parser, DBusError *error) +{ + const char *dbus_user; + + dbus_user = bus_config_parser_get_user (parser); + if (dbus_user == NULL) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_CONFIG_INVALID, + "could not get user from config file\n"); + return FALSE; + } + + /* check to see if permissions are correct */ + if (!check_permissions (dbus_user, error)) + return FALSE; + + return TRUE; +} + +dbus_bool_t +run_launch_helper (const char *bus_name, + DBusError *error) +{ + BusConfigParser *parser; + dbus_bool_t retval; + + parser = NULL; + retval = FALSE; + + /* clear the environment, apart from a few select settings */ + if (!clear_environment (error)) + goto error; + + /* check to see if we have a valid bus name */ + if (!check_bus_name (bus_name, error)) + goto error; + + /* get the correct parser, either the test or default parser */ + if (!get_correct_parser (&parser, error)) + goto error; + + /* check we are being invoked by the correct dbus user */ + if (!check_dbus_user (parser, error)) + goto error_free_parser; + + /* launch the bus with the service defined user */ + if (!launch_bus_name (bus_name, parser, error)) + goto error_free_parser; + + /* woohoo! */ + retval = TRUE; + +error_free_parser: + bus_config_parser_unref (parser); +error: + return retval; +} + diff --git a/bus/activation-helper.h b/bus/activation-helper.h new file mode 100644 index 00000000..361a4c6a --- /dev/null +++ b/bus/activation-helper.h @@ -0,0 +1,31 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* activation-helper.h The actual activation helper split from the main + * function for testing. + * + * Copyright (C) 2007 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_ACTIVATION_HELPER_H +#define BUS_ACTIVATION_HELPER_H + +dbus_bool_t run_launch_helper (const char *bus_name, DBusError *error); + + +#endif /* BUS_ACTIVATION_HELPER_H */ diff --git a/bus/activation.c b/bus/activation.c new file mode 100644 index 00000000..2fcd85d2 --- /dev/null +++ b/bus/activation.c @@ -0,0 +1,2351 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* activation.c Activation of services + * + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2003 Red Hat, Inc. + * Copyright (C) 2004 Imendio HB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "activation.h" +#include "activation-exit-codes.h" +#include "desktop-file.h" +#include "dispatch.h" +#include "services.h" +#include "test.h" +#include "utils.h" +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_ERRNO_H +#include +#endif + +struct BusActivation +{ + int refcount; + DBusHashTable *entries; + DBusHashTable *pending_activations; + char *server_address; + BusContext *context; + int n_pending_activations; /**< This is in fact the number of BusPendingActivationEntry, + * i.e. number of pending activation requests, not pending + * activations per se + */ + DBusHashTable *directories; + DBusHashTable *environment; +}; + +typedef struct +{ + int refcount; + char *dir_c; + DBusHashTable *entries; +} BusServiceDirectory; + +typedef struct +{ + int refcount; + char *name; + char *exec; + char *user; + unsigned long mtime; + BusServiceDirectory *s_dir; + char *filename; +} BusActivationEntry; + +typedef struct BusPendingActivationEntry BusPendingActivationEntry; + +struct BusPendingActivationEntry +{ + DBusMessage *activation_message; + DBusConnection *connection; + + dbus_bool_t auto_activation; +}; + +typedef struct +{ + int refcount; + BusActivation *activation; + char *service_name; + char *exec; + DBusList *entries; + int n_entries; + DBusBabysitter *babysitter; + DBusTimeout *timeout; + unsigned int timeout_added : 1; +} BusPendingActivation; + +#if 0 +static BusServiceDirectory * +bus_service_directory_ref (BusServiceDirectory *dir) +{ + _dbus_assert (dir->refcount); + + dir->refcount++; + + return dir; +} +#endif + +static void +bus_service_directory_unref (BusServiceDirectory *dir) +{ + if (dir == NULL) + return; + + _dbus_assert (dir->refcount > 0); + dir->refcount--; + + if (dir->refcount > 0) + return; + + if (dir->entries) + _dbus_hash_table_unref (dir->entries); + + dbus_free (dir->dir_c); + dbus_free (dir); +} + +static void +bus_pending_activation_entry_free (BusPendingActivationEntry *entry) +{ + if (entry->activation_message) + dbus_message_unref (entry->activation_message); + + if (entry->connection) + dbus_connection_unref (entry->connection); + + dbus_free (entry); +} + +static void +handle_timeout_callback (DBusTimeout *timeout, + void *data) +{ + BusPendingActivation *pending_activation = data; + + while (!dbus_timeout_handle (pending_activation->timeout)) + _dbus_wait_for_memory (); +} + +static BusPendingActivation * +bus_pending_activation_ref (BusPendingActivation *pending_activation) +{ + _dbus_assert (pending_activation->refcount > 0); + pending_activation->refcount += 1; + + return pending_activation; +} + +static void +bus_pending_activation_unref (BusPendingActivation *pending_activation) +{ + DBusList *link; + + if (pending_activation == NULL) /* hash table requires this */ + return; + + _dbus_assert (pending_activation->refcount > 0); + pending_activation->refcount -= 1; + + if (pending_activation->refcount > 0) + return; + + if (pending_activation->timeout_added) + { + _dbus_loop_remove_timeout (bus_context_get_loop (pending_activation->activation->context), + pending_activation->timeout, + handle_timeout_callback, pending_activation); + pending_activation->timeout_added = FALSE; + } + + if (pending_activation->timeout) + _dbus_timeout_unref (pending_activation->timeout); + + if (pending_activation->babysitter) + { + if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter, + NULL, NULL, NULL, + pending_activation->babysitter, + NULL)) + _dbus_assert_not_reached ("setting watch functions to NULL failed"); + + _dbus_babysitter_unref (pending_activation->babysitter); + } + + dbus_free (pending_activation->service_name); + dbus_free (pending_activation->exec); + + link = _dbus_list_get_first_link (&pending_activation->entries); + + while (link != NULL) + { + BusPendingActivationEntry *entry = link->data; + + bus_pending_activation_entry_free (entry); + + link = _dbus_list_get_next_link (&pending_activation->entries, link); + } + _dbus_list_clear (&pending_activation->entries); + + pending_activation->activation->n_pending_activations -= + pending_activation->n_entries; + + _dbus_assert (pending_activation->activation->n_pending_activations >= 0); + + dbus_free (pending_activation); +} + +static BusActivationEntry * +bus_activation_entry_ref (BusActivationEntry *entry) +{ + _dbus_assert (entry->refcount > 0); + entry->refcount++; + + return entry; +} + +static void +bus_activation_entry_unref (BusActivationEntry *entry) +{ + if (entry == NULL) /* hash table requires this */ + return; + + _dbus_assert (entry->refcount > 0); + entry->refcount--; + + if (entry->refcount > 0) + return; + + dbus_free (entry->name); + dbus_free (entry->exec); + dbus_free (entry->user); + dbus_free (entry->filename); + + dbus_free (entry); +} + +static dbus_bool_t +update_desktop_file_entry (BusActivation *activation, + BusServiceDirectory *s_dir, + DBusString *filename, + BusDesktopFile *desktop_file, + DBusError *error) +{ + char *name, *exec, *user; + BusActivationEntry *entry; + DBusStat stat_buf; + DBusString file_path; + DBusError tmp_error; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + name = NULL; + exec = NULL; + user = NULL; + entry = NULL; + + dbus_error_init (&tmp_error); + + if (!_dbus_string_init (&file_path)) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_append (&file_path, s_dir->dir_c) || + !_dbus_concat_dir_and_file (&file_path, filename)) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!_dbus_stat (&file_path, &stat_buf, NULL)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Can't stat the service file\n"); + goto failed; + } + + if (!bus_desktop_file_get_string (desktop_file, + DBUS_SERVICE_SECTION, + DBUS_SERVICE_NAME, + &name, + error)) + goto failed; + + if (!bus_desktop_file_get_string (desktop_file, + DBUS_SERVICE_SECTION, + DBUS_SERVICE_EXEC, + &exec, + error)) + goto failed; + + /* user is not _required_ unless we are using system activation */ + if (!bus_desktop_file_get_string (desktop_file, + DBUS_SERVICE_SECTION, + DBUS_SERVICE_USER, + &user, &tmp_error)) + { + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + /* if we got OOM, then exit */ + if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) + { + dbus_move_error (&tmp_error, error); + goto failed; + } + else + { + /* if we have error because we didn't find anything then continue */ + dbus_error_free (&tmp_error); + dbus_free (user); + user = NULL; + } + } + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); + + entry = _dbus_hash_table_lookup_string (s_dir->entries, + _dbus_string_get_const_data (filename)); + if (entry == NULL) /* New file */ + { + /* FIXME we need a better-defined algorithm for which service file to + * pick than "whichever one is first in the directory listing" + */ + if (_dbus_hash_table_lookup_string (activation->entries, name)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Service %s already exists in activation entry list\n", name); + goto failed; + } + + entry = dbus_new0 (BusActivationEntry, 1); + if (entry == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + entry->name = name; + entry->exec = exec; + entry->user = user; + entry->refcount = 1; + + entry->s_dir = s_dir; + entry->filename = _dbus_strdup (_dbus_string_get_const_data (filename)); + if (!entry->filename) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!_dbus_hash_table_insert_string (activation->entries, entry->name, bus_activation_entry_ref (entry))) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!_dbus_hash_table_insert_string (s_dir->entries, entry->filename, bus_activation_entry_ref (entry))) + { + /* Revert the insertion in the entries table */ + _dbus_hash_table_remove_string (activation->entries, entry->name); + BUS_SET_OOM (error); + goto failed; + } + + _dbus_verbose ("Added \"%s\" to list of services\n", entry->name); + } + else /* Just update the entry */ + { + bus_activation_entry_ref (entry); + _dbus_hash_table_remove_string (activation->entries, entry->name); + + if (_dbus_hash_table_lookup_string (activation->entries, name)) + { + _dbus_verbose ("The new service name \"%s\" of service file \"%s\" already in cache, ignoring\n", + name, _dbus_string_get_const_data (&file_path)); + goto failed; + } + + dbus_free (entry->name); + dbus_free (entry->exec); + dbus_free (entry->user); + entry->name = name; + entry->exec = exec; + entry->user = user; + if (!_dbus_hash_table_insert_string (activation->entries, + entry->name, bus_activation_entry_ref(entry))) + { + BUS_SET_OOM (error); + /* Also remove path to entries hash since we want this in sync with + * the entries hash table */ + _dbus_hash_table_remove_string (entry->s_dir->entries, + entry->filename); + bus_activation_entry_unref (entry); + return FALSE; + } + } + + entry->mtime = stat_buf.mtime; + + _dbus_string_free (&file_path); + bus_activation_entry_unref (entry); + + return TRUE; + +failed: + dbus_free (name); + dbus_free (exec); + dbus_free (user); + _dbus_string_free (&file_path); + + if (entry) + bus_activation_entry_unref (entry); + + return FALSE; +} + +static dbus_bool_t +check_service_file (BusActivation *activation, + BusActivationEntry *entry, + BusActivationEntry **updated_entry, + DBusError *error) +{ + DBusStat stat_buf; + dbus_bool_t retval; + BusActivationEntry *tmp_entry; + DBusString file_path; + DBusString filename; + + retval = TRUE; + tmp_entry = entry; + + _dbus_string_init_const (&filename, entry->filename); + + if (!_dbus_string_init (&file_path)) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_append (&file_path, entry->s_dir->dir_c) || + !_dbus_concat_dir_and_file (&file_path, &filename)) + { + BUS_SET_OOM (error); + retval = FALSE; + goto out; + } + + if (!_dbus_stat (&file_path, &stat_buf, NULL)) + { + _dbus_verbose ("****** Can't stat file \"%s\", removing from cache\n", + _dbus_string_get_const_data (&file_path)); + + _dbus_hash_table_remove_string (activation->entries, entry->name); + _dbus_hash_table_remove_string (entry->s_dir->entries, entry->filename); + + tmp_entry = NULL; + retval = TRUE; + goto out; + } + else + { + if (stat_buf.mtime > entry->mtime) + { + BusDesktopFile *desktop_file; + DBusError tmp_error; + + dbus_error_init (&tmp_error); + + desktop_file = bus_desktop_file_load (&file_path, &tmp_error); + if (desktop_file == NULL) + { + _dbus_verbose ("Could not load %s: %s\n", + _dbus_string_get_const_data (&file_path), + tmp_error.message); + if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) + { + dbus_move_error (&tmp_error, error); + retval = FALSE; + goto out; + } + dbus_error_free (&tmp_error); + retval = TRUE; + goto out; + } + + /* @todo We can return OOM or a DBUS_ERROR_FAILED error + * Handle these both better + */ + if (!update_desktop_file_entry (activation, entry->s_dir, &filename, desktop_file, &tmp_error)) + { + bus_desktop_file_free (desktop_file); + if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) + { + dbus_move_error (&tmp_error, error); + retval = FALSE; + goto out; + } + dbus_error_free (&tmp_error); + retval = TRUE; + goto out; + } + + bus_desktop_file_free (desktop_file); + retval = TRUE; + } + } + +out: + _dbus_string_free (&file_path); + + if (updated_entry != NULL) + *updated_entry = tmp_entry; + return retval; +} + + +/* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip + * hash entries it already added. + */ +static dbus_bool_t +update_directory (BusActivation *activation, + BusServiceDirectory *s_dir, + DBusError *error) +{ + DBusDirIter *iter; + DBusString dir, filename; + BusDesktopFile *desktop_file; + DBusError tmp_error; + dbus_bool_t retval; + BusActivationEntry *entry; + DBusString full_path; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + iter = NULL; + desktop_file = NULL; + + _dbus_string_init_const (&dir, s_dir->dir_c); + + if (!_dbus_string_init (&filename)) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_init (&full_path)) + { + BUS_SET_OOM (error); + _dbus_string_free (&filename); + return FALSE; + } + + retval = FALSE; + + /* from this point it's safe to "goto out" */ + + iter = _dbus_directory_open (&dir, error); + if (iter == NULL) + { + _dbus_verbose ("Failed to open directory %s: %s\n", + s_dir->dir_c, + error ? error->message : "unknown"); + goto out; + } + + /* Now read the files */ + dbus_error_init (&tmp_error); + while (_dbus_directory_get_next_file (iter, &filename, &tmp_error)) + { + _dbus_assert (!dbus_error_is_set (&tmp_error)); + + _dbus_string_set_length (&full_path, 0); + + if (!_dbus_string_ends_with_c_str (&filename, ".service")) + { + _dbus_verbose ("Skipping non-.service file %s\n", + _dbus_string_get_const_data (&filename)); + continue; + } + + entry = _dbus_hash_table_lookup_string (s_dir->entries, _dbus_string_get_const_data (&filename)); + if (entry) /* Already has this service file in the cache */ + { + if (!check_service_file (activation, entry, NULL, error)) + goto out; + + continue; + } + + if (!_dbus_string_append (&full_path, s_dir->dir_c) || + !_dbus_concat_dir_and_file (&full_path, &filename)) + { + BUS_SET_OOM (error); + goto out; + } + + /* New file */ + desktop_file = bus_desktop_file_load (&full_path, &tmp_error); + if (desktop_file == NULL) + { + _dbus_verbose ("Could not load %s: %s\n", + _dbus_string_get_const_data (&full_path), + tmp_error.message); + + if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) + { + dbus_move_error (&tmp_error, error); + goto out; + } + + dbus_error_free (&tmp_error); + continue; + } + + /* @todo We can return OOM or a DBUS_ERROR_FAILED error + * Handle these both better + */ + if (!update_desktop_file_entry (activation, s_dir, &filename, desktop_file, &tmp_error)) + { + bus_desktop_file_free (desktop_file); + desktop_file = NULL; + + _dbus_verbose ("Could not add %s to activation entry list: %s\n", + _dbus_string_get_const_data (&full_path), tmp_error.message); + + if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) + { + dbus_move_error (&tmp_error, error); + goto out; + } + + dbus_error_free (&tmp_error); + continue; + } + else + { + bus_desktop_file_free (desktop_file); + desktop_file = NULL; + continue; + } + } + + if (dbus_error_is_set (&tmp_error)) + { + dbus_move_error (&tmp_error, error); + goto out; + } + + retval = TRUE; + + out: + if (!retval) + _DBUS_ASSERT_ERROR_IS_SET (error); + else + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (iter != NULL) + _dbus_directory_close (iter); + _dbus_string_free (&filename); + _dbus_string_free (&full_path); + + return retval; +} + +static dbus_bool_t +populate_environment (BusActivation *activation) +{ + DBusString key; + DBusString value; + int i; + char **environment; + dbus_bool_t retval = FALSE; + + environment = _dbus_get_environment (); + + if (environment == NULL) + return FALSE; + + if (!_dbus_string_init (&key)) + { + dbus_free_string_array (environment); + return FALSE; + } + + if (!_dbus_string_init (&value)) + { + _dbus_string_free (&key); + dbus_free_string_array (environment); + return FALSE; + } + + for (i = 0; environment[i] != NULL; i++) + { + if (!_dbus_string_append (&key, environment[i])) + break; + + if (_dbus_string_split_on_byte (&key, '=', &value)) + { + char *hash_key, *hash_value; + + if (!_dbus_string_steal_data (&key, &hash_key)) + break; + + if (!_dbus_string_steal_data (&value, &hash_value)) + break; + + if (!_dbus_hash_table_insert_string (activation->environment, + hash_key, hash_value)) + break; + } + _dbus_string_set_length (&key, 0); + _dbus_string_set_length (&value, 0); + } + + if (environment[i] != NULL) + goto out; + + retval = TRUE; +out: + + _dbus_string_free (&key); + _dbus_string_free (&value); + dbus_free_string_array (environment); + + return retval; +} + +dbus_bool_t +bus_activation_reload (BusActivation *activation, + const DBusString *address, + DBusList **directories, + DBusError *error) +{ + DBusList *link; + char *dir; + + if (activation->server_address != NULL) + dbus_free (activation->server_address); + if (!_dbus_string_copy_data (address, &activation->server_address)) + { + BUS_SET_OOM (error); + goto failed; + } + + if (activation->entries != NULL) + _dbus_hash_table_unref (activation->entries); + activation->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, + (DBusFreeFunction)bus_activation_entry_unref); + if (activation->entries == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + if (activation->directories != NULL) + _dbus_hash_table_unref (activation->directories); + activation->directories = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, + (DBusFreeFunction)bus_service_directory_unref); + + if (activation->directories == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + link = _dbus_list_get_first_link (directories); + while (link != NULL) + { + BusServiceDirectory *s_dir; + + dir = _dbus_strdup ((const char *) link->data); + if (!dir) + { + BUS_SET_OOM (error); + goto failed; + } + + s_dir = dbus_new0 (BusServiceDirectory, 1); + if (!s_dir) + { + dbus_free (dir); + BUS_SET_OOM (error); + goto failed; + } + + s_dir->refcount = 1; + s_dir->dir_c = dir; + + s_dir->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, + (DBusFreeFunction)bus_activation_entry_unref); + + if (!s_dir->entries) + { + bus_service_directory_unref (s_dir); + BUS_SET_OOM (error); + goto failed; + } + + if (!_dbus_hash_table_insert_string (activation->directories, s_dir->dir_c, s_dir)) + { + bus_service_directory_unref (s_dir); + BUS_SET_OOM (error); + goto failed; + } + + /* only fail on OOM, it is ok if we can't read the directory */ + if (!update_directory (activation, s_dir, error)) + { + if (dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY)) + goto failed; + else + dbus_error_free (error); + } + + link = _dbus_list_get_next_link (directories, link); + } + + return TRUE; + failed: + return FALSE; +} + +BusActivation* +bus_activation_new (BusContext *context, + const DBusString *address, + DBusList **directories, + DBusError *error) +{ + BusActivation *activation; + DBusList *link; + char *dir; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + activation = dbus_new0 (BusActivation, 1); + if (activation == NULL) + { + BUS_SET_OOM (error); + return NULL; + } + + activation->refcount = 1; + activation->context = context; + activation->n_pending_activations = 0; + + if (!bus_activation_reload (activation, address, directories, error)) + goto failed; + + /* Initialize this hash table once, we don't want to lose pending + * activations on reload. */ + activation->pending_activations = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, + (DBusFreeFunction)bus_pending_activation_unref); + + if (activation->pending_activations == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + activation->environment = _dbus_hash_table_new (DBUS_HASH_STRING, + (DBusFreeFunction) dbus_free, + (DBusFreeFunction) dbus_free); + + if (activation->environment == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!populate_environment (activation)) + { + BUS_SET_OOM (error); + goto failed; + } + + return activation; + + failed: + bus_activation_unref (activation); + return NULL; +} + +BusActivation * +bus_activation_ref (BusActivation *activation) +{ + _dbus_assert (activation->refcount > 0); + + activation->refcount += 1; + + return activation; +} + +void +bus_activation_unref (BusActivation *activation) +{ + _dbus_assert (activation->refcount > 0); + + activation->refcount -= 1; + + if (activation->refcount > 0) + return; + + dbus_free (activation->server_address); + if (activation->entries) + _dbus_hash_table_unref (activation->entries); + if (activation->pending_activations) + _dbus_hash_table_unref (activation->pending_activations); + if (activation->directories) + _dbus_hash_table_unref (activation->directories); + if (activation->environment) + _dbus_hash_table_unref (activation->environment); + + dbus_free (activation); +} + +static dbus_bool_t +add_bus_environment (BusActivation *activation, + DBusError *error) +{ + const char *type; + + if (!bus_activation_set_environment_variable (activation, + "DBUS_STARTER_ADDRESS", + activation->server_address, + error)) + return FALSE; + + type = bus_context_get_type (activation->context); + if (type != NULL) + { + if (!bus_activation_set_environment_variable (activation, + "DBUS_STARTER_BUS_TYPE", type, + error)) + return FALSE; + + if (strcmp (type, "session") == 0) + { + if (!bus_activation_set_environment_variable (activation, + "DBUS_SESSION_BUS_ADDRESS", + activation->server_address, + error)) + return FALSE; + } + else if (strcmp (type, "system") == 0) + { + if (!bus_activation_set_environment_variable (activation, + "DBUS_SYSTEM_BUS_ADDRESS", + activation->server_address, + error)) + return FALSE; + } + } + + return TRUE; +} + +typedef struct +{ + BusPendingActivation *pending_activation; + DBusPreallocatedHash *hash_entry; +} RestorePendingData; + +static void +restore_pending (void *data) +{ + RestorePendingData *d = data; + + _dbus_assert (d->pending_activation != NULL); + _dbus_assert (d->hash_entry != NULL); + + _dbus_verbose ("Restoring pending activation for service %s, has timeout = %d\n", + d->pending_activation->service_name, + d->pending_activation->timeout_added); + + _dbus_hash_table_insert_string_preallocated (d->pending_activation->activation->pending_activations, + d->hash_entry, + d->pending_activation->service_name, d->pending_activation); + + bus_pending_activation_ref (d->pending_activation); + + d->hash_entry = NULL; +} + +static void +free_pending_restore_data (void *data) +{ + RestorePendingData *d = data; + + if (d->hash_entry) + _dbus_hash_table_free_preallocated_entry (d->pending_activation->activation->pending_activations, + d->hash_entry); + + bus_pending_activation_unref (d->pending_activation); + + dbus_free (d); +} + +static dbus_bool_t +add_restore_pending_to_transaction (BusTransaction *transaction, + BusPendingActivation *pending_activation) +{ + RestorePendingData *d; + + d = dbus_new (RestorePendingData, 1); + if (d == NULL) + return FALSE; + + d->pending_activation = pending_activation; + d->hash_entry = _dbus_hash_table_preallocate_entry (d->pending_activation->activation->pending_activations); + + bus_pending_activation_ref (d->pending_activation); + + if (d->hash_entry == NULL || + !bus_transaction_add_cancel_hook (transaction, restore_pending, d, + free_pending_restore_data)) + { + free_pending_restore_data (d); + return FALSE; + } + + _dbus_verbose ("Saved pending activation to be restored if the transaction fails\n"); + + return TRUE; +} + +dbus_bool_t +bus_activation_service_created (BusActivation *activation, + const char *service_name, + BusTransaction *transaction, + DBusError *error) +{ + BusPendingActivation *pending_activation; + DBusMessage *message; + DBusList *link; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* Check if it's a pending activation */ + pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name); + + if (!pending_activation) + return TRUE; + + link = _dbus_list_get_first_link (&pending_activation->entries); + while (link != NULL) + { + BusPendingActivationEntry *entry = link->data; + DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link); + + if (dbus_connection_get_is_connected (entry->connection)) + { + /* Only send activation replies to regular activation requests. */ + if (!entry->auto_activation) + { + dbus_uint32_t result; + + message = dbus_message_new_method_return (entry->activation_message); + if (!message) + { + BUS_SET_OOM (error); + goto error; + } + + result = DBUS_START_REPLY_SUCCESS; + + if (!dbus_message_append_args (message, + DBUS_TYPE_UINT32, &result, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + goto error; + } + + if (!bus_transaction_send_from_driver (transaction, entry->connection, message)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + goto error; + } + + dbus_message_unref (message); + } + } + + link = next; + } + + return TRUE; + + error: + return FALSE; +} + +dbus_bool_t +bus_activation_send_pending_auto_activation_messages (BusActivation *activation, + BusService *service, + BusTransaction *transaction, + DBusError *error) +{ + BusPendingActivation *pending_activation; + DBusList *link; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* Check if it's a pending activation */ + pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, + bus_service_get_name (service)); + + if (!pending_activation) + return TRUE; + + link = _dbus_list_get_first_link (&pending_activation->entries); + while (link != NULL) + { + BusPendingActivationEntry *entry = link->data; + DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link); + + if (entry->auto_activation && dbus_connection_get_is_connected (entry->connection)) + { + DBusConnection *addressed_recipient; + + addressed_recipient = bus_service_get_primary_owners_connection (service); + + /* Resume dispatching where we left off in bus_dispatch() */ + if (!bus_dispatch_matches (transaction, + entry->connection, + addressed_recipient, + entry->activation_message, error)) + goto error; + } + + link = next; + } + + if (!add_restore_pending_to_transaction (transaction, pending_activation)) + { + _dbus_verbose ("Could not add cancel hook to transaction to revert removing pending activation\n"); + BUS_SET_OOM (error); + goto error; + } + + _dbus_hash_table_remove_string (activation->pending_activations, bus_service_get_name (service)); + + return TRUE; + + error: + return FALSE; +} + +/** + * FIXME @todo the error messages here would ideally be preallocated + * so we don't need to allocate memory to send them. + * Using the usual tactic, prealloc an OOM message, then + * if we can't alloc the real error send the OOM error instead. + */ +static dbus_bool_t +try_send_activation_failure (BusPendingActivation *pending_activation, + const DBusError *how) +{ + BusActivation *activation; + DBusList *link; + BusTransaction *transaction; + + activation = pending_activation->activation; + + transaction = bus_transaction_new (activation->context); + if (transaction == NULL) + return FALSE; + + link = _dbus_list_get_first_link (&pending_activation->entries); + while (link != NULL) + { + BusPendingActivationEntry *entry = link->data; + DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link); + + if (dbus_connection_get_is_connected (entry->connection)) + { + if (!bus_transaction_send_error_reply (transaction, + entry->connection, + how, + entry->activation_message)) + goto error; + } + + link = next; + } + + bus_transaction_execute_and_free (transaction); + + return TRUE; + + error: + if (transaction) + bus_transaction_cancel_and_free (transaction); + return FALSE; +} + +/** + * Free the pending activation and send an error message to all the + * connections that were waiting for it. + */ +static void +pending_activation_failed (BusPendingActivation *pending_activation, + const DBusError *how) +{ + /* FIXME use preallocated OOM messages instead of bus_wait_for_memory() */ + while (!try_send_activation_failure (pending_activation, how)) + _dbus_wait_for_memory (); + + /* Destroy this pending activation */ + _dbus_hash_table_remove_string (pending_activation->activation->pending_activations, + pending_activation->service_name); +} + +/** + * Depending on the exit code of the helper, set the error accordingly + */ +static void +handle_servicehelper_exit_error (int exit_code, + DBusError *error) +{ + switch (exit_code) + { + case BUS_SPAWN_EXIT_CODE_NO_MEMORY: + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "Launcher could not run (out of memory)"); + break; + case BUS_SPAWN_EXIT_CODE_SETUP_FAILED: + dbus_set_error (error, DBUS_ERROR_SPAWN_SETUP_FAILED, + "Failed to setup environment correctly"); + break; + case BUS_SPAWN_EXIT_CODE_NAME_INVALID: + dbus_set_error (error, DBUS_ERROR_SPAWN_SERVICE_INVALID, + "Bus name is not valid or missing"); + break; + case BUS_SPAWN_EXIT_CODE_SERVICE_NOT_FOUND: + dbus_set_error (error, DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND, + "Bus name not found in system service directory"); + break; + case BUS_SPAWN_EXIT_CODE_PERMISSIONS_INVALID: + dbus_set_error (error, DBUS_ERROR_SPAWN_PERMISSIONS_INVALID, + "The permission of the setuid helper is not correct"); + break; + case BUS_SPAWN_EXIT_CODE_FILE_INVALID: + dbus_set_error (error, DBUS_ERROR_SPAWN_PERMISSIONS_INVALID, + "The service file is incorrect or does not have all required attributes"); + break; + case BUS_SPAWN_EXIT_CODE_EXEC_FAILED: + dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, + "Cannot launch daemon, file not found or permissions invalid"); + break; + case BUS_SPAWN_EXIT_CODE_INVALID_ARGS: + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Invalid arguments to command line"); + break; + case BUS_SPAWN_EXIT_CODE_CHILD_SIGNALED: + dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED, + "Launched child was signaled, it probably crashed"); + break; + default: + dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED, + "Launch helper exited with unknown return code %i", exit_code); + break; + } +} + +static dbus_bool_t +babysitter_watch_callback (DBusWatch *watch, + unsigned int condition, + void *data) +{ + BusPendingActivation *pending_activation = data; + dbus_bool_t retval; + DBusBabysitter *babysitter; + dbus_bool_t uses_servicehelper; + + babysitter = pending_activation->babysitter; + + _dbus_babysitter_ref (babysitter); + + retval = dbus_watch_handle (watch, condition); + + /* There are two major cases here; are we the system bus or the session? Here this + * is distinguished by whether or not we use a setuid helper launcher. With the launch helper, + * some process exit codes are meaningful, processed by handle_servicehelper_exit_error. + * + * In both cases though, just ignore when a process exits with status 0; it's possible for + * a program to (misguidedly) "daemonize", and that appears to us as an exit. This closes a race + * condition between this code and the child process claiming the bus name. + */ + uses_servicehelper = bus_context_get_servicehelper (pending_activation->activation->context) != NULL; + + /* FIXME this is broken in the same way that + * connection watches used to be; there should be + * a separate callback for status change, instead + * of doing "if we handled a watch status might + * have changed" + * + * Fixing this lets us move dbus_watch_handle + * calls into dbus-mainloop.c + */ + if (_dbus_babysitter_get_child_exited (babysitter)) + { + DBusError error; + DBusHashIter iter; + dbus_bool_t activation_failed; + int exit_code = 0; + + dbus_error_init (&error); + + _dbus_babysitter_set_child_exit_error (babysitter, &error); + + /* Explicitly check for SPAWN_CHILD_EXITED to avoid overwriting an + * exec error */ + if (dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED) + && _dbus_babysitter_get_child_exit_status (babysitter, &exit_code)) + { + activation_failed = exit_code != 0; + + dbus_error_free(&error); + + if (activation_failed) + { + if (uses_servicehelper) + handle_servicehelper_exit_error (exit_code, &error); + else + _dbus_babysitter_set_child_exit_error (babysitter, &error); + } + } + else + { + activation_failed = TRUE; + } + + if (activation_failed) + { + /* Destroy all pending activations with the same exec */ + _dbus_hash_iter_init (pending_activation->activation->pending_activations, + &iter); + while (_dbus_hash_iter_next (&iter)) + { + BusPendingActivation *p = _dbus_hash_iter_get_value (&iter); + + if (p != pending_activation && strcmp (p->exec, pending_activation->exec) == 0) + pending_activation_failed (p, &error); + } + + /* Destroys the pending activation */ + pending_activation_failed (pending_activation, &error); + + dbus_error_free (&error); + } + } + + _dbus_babysitter_unref (babysitter); + + return retval; +} + +static dbus_bool_t +add_babysitter_watch (DBusWatch *watch, + void *data) +{ + BusPendingActivation *pending_activation = data; + + return _dbus_loop_add_watch (bus_context_get_loop (pending_activation->activation->context), + watch, babysitter_watch_callback, pending_activation, + NULL); +} + +static void +remove_babysitter_watch (DBusWatch *watch, + void *data) +{ + BusPendingActivation *pending_activation = data; + + _dbus_loop_remove_watch (bus_context_get_loop (pending_activation->activation->context), + watch, babysitter_watch_callback, pending_activation); +} + +static dbus_bool_t +pending_activation_timed_out (void *data) +{ + BusPendingActivation *pending_activation = data; + DBusError error; + + /* Kill the spawned process, since it sucks + * (not sure this is what we want to do, but + * may as well try it for now) + */ + if (pending_activation->babysitter) + _dbus_babysitter_kill_child (pending_activation->babysitter); + + dbus_error_init (&error); + + dbus_set_error (&error, DBUS_ERROR_TIMED_OUT, + "Activation of %s timed out", + pending_activation->service_name); + + pending_activation_failed (pending_activation, &error); + + dbus_error_free (&error); + + return TRUE; +} + +static void +cancel_pending (void *data) +{ + BusPendingActivation *pending_activation = data; + + _dbus_verbose ("Canceling pending activation of %s\n", + pending_activation->service_name); + + if (pending_activation->babysitter) + _dbus_babysitter_kill_child (pending_activation->babysitter); + + _dbus_hash_table_remove_string (pending_activation->activation->pending_activations, + pending_activation->service_name); +} + +static void +free_pending_cancel_data (void *data) +{ + BusPendingActivation *pending_activation = data; + + bus_pending_activation_unref (pending_activation); +} + +static dbus_bool_t +add_cancel_pending_to_transaction (BusTransaction *transaction, + BusPendingActivation *pending_activation) +{ + if (!bus_transaction_add_cancel_hook (transaction, cancel_pending, + pending_activation, + free_pending_cancel_data)) + return FALSE; + + bus_pending_activation_ref (pending_activation); + + _dbus_verbose ("Saved pending activation to be canceled if the transaction fails\n"); + + return TRUE; +} + +static dbus_bool_t +update_service_cache (BusActivation *activation, DBusError *error) +{ + DBusHashIter iter; + + _dbus_hash_iter_init (activation->directories, &iter); + while (_dbus_hash_iter_next (&iter)) + { + DBusError tmp_error; + BusServiceDirectory *s_dir; + + s_dir = _dbus_hash_iter_get_value (&iter); + + dbus_error_init (&tmp_error); + if (!update_directory (activation, s_dir, &tmp_error)) + { + if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY)) + { + dbus_move_error (&tmp_error, error); + return FALSE; + } + + dbus_error_free (&tmp_error); + continue; + } + } + + return TRUE; +} + +static BusActivationEntry * +activation_find_entry (BusActivation *activation, + const char *service_name, + DBusError *error) +{ + BusActivationEntry *entry; + + entry = _dbus_hash_table_lookup_string (activation->entries, service_name); + if (!entry) + { + if (!update_service_cache (activation, error)) + return NULL; + + entry = _dbus_hash_table_lookup_string (activation->entries, + service_name); + } + else + { + BusActivationEntry *updated_entry; + + if (!check_service_file (activation, entry, &updated_entry, error)) + return NULL; + + entry = updated_entry; + } + + if (!entry) + { + dbus_set_error (error, DBUS_ERROR_SERVICE_UNKNOWN, + "The name %s was not provided by any .service files", + service_name); + return NULL; + } + + return entry; +} + +static char ** +bus_activation_get_environment (BusActivation *activation) +{ + char **environment; + int i, length; + DBusString entry; + DBusHashIter iter; + + length = _dbus_hash_table_get_n_entries (activation->environment); + + environment = dbus_new0 (char *, length + 1); + + if (environment == NULL) + return NULL; + + i = 0; + _dbus_hash_iter_init (activation->environment, &iter); + + if (!_dbus_string_init (&entry)) + { + dbus_free_string_array (environment); + return NULL; + } + + while (_dbus_hash_iter_next (&iter)) + { + const char *key, *value; + + key = (const char *) _dbus_hash_iter_get_string_key (&iter); + value = (const char *) _dbus_hash_iter_get_value (&iter); + + if (!_dbus_string_append_printf (&entry, "%s=%s", key, value)) + break; + + if (!_dbus_string_steal_data (&entry, environment + i)) + break; + i++; + } + + _dbus_string_free (&entry); + + if (i != length) + { + dbus_free_string_array (environment); + environment = NULL; + } + + return environment; +} + +dbus_bool_t +bus_activation_set_environment_variable (BusActivation *activation, + const char *key, + const char *value, + DBusError *error) +{ + char *hash_key; + char *hash_value; + dbus_bool_t retval; + + retval = FALSE; + hash_key = NULL; + hash_value = NULL; + hash_key = _dbus_strdup (key); + + if (hash_key == NULL) + goto out; + + hash_value = _dbus_strdup (value); + + if (hash_value == NULL) + goto out; + + if (!_dbus_hash_table_insert_string (activation->environment, + hash_key, hash_value)) + goto out; + + retval = TRUE; +out: + if (retval == FALSE) + { + dbus_free (hash_key); + dbus_free (hash_value); + BUS_SET_OOM (error); + } + + return retval; +} + +dbus_bool_t +bus_activation_activate_service (BusActivation *activation, + DBusConnection *connection, + BusTransaction *transaction, + dbus_bool_t auto_activation, + DBusMessage *activation_message, + const char *service_name, + DBusError *error) +{ + BusActivationEntry *entry; + BusPendingActivation *pending_activation; + BusPendingActivationEntry *pending_activation_entry; + DBusMessage *message; + DBusString service_str; + const char *servicehelper; + char **argv; + char **envp = NULL; + int argc; + dbus_bool_t retval; + DBusHashIter iter; + dbus_bool_t activated; + DBusString command; + + activated = TRUE; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (activation->n_pending_activations >= + bus_context_get_max_pending_activations (activation->context)) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "The maximum number of pending activations has been reached, activation of %s failed", + service_name); + return FALSE; + } + + entry = activation_find_entry (activation, service_name, error); + if (!entry) + return FALSE; + + /* Bypass the registry lookup if we're auto-activating, bus_dispatch would not + * call us if the service is already active. + */ + if (!auto_activation) + { + /* Check if the service is active */ + _dbus_string_init_const (&service_str, service_name); + if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL) + { + dbus_uint32_t result; + + _dbus_verbose ("Service \"%s\" is already active\n", service_name); + + message = dbus_message_new_method_return (activation_message); + + if (!message) + { + _dbus_verbose ("No memory to create reply to activate message\n"); + BUS_SET_OOM (error); + return FALSE; + } + + result = DBUS_START_REPLY_ALREADY_RUNNING; + + if (!dbus_message_append_args (message, + DBUS_TYPE_UINT32, &result, + DBUS_TYPE_INVALID)) + { + _dbus_verbose ("No memory to set args of reply to activate message\n"); + BUS_SET_OOM (error); + dbus_message_unref (message); + return FALSE; + } + + retval = bus_transaction_send_from_driver (transaction, connection, message); + dbus_message_unref (message); + if (!retval) + { + _dbus_verbose ("Failed to send reply\n"); + BUS_SET_OOM (error); + } + + return retval; + } + } + + pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1); + if (!pending_activation_entry) + { + _dbus_verbose ("Failed to create pending activation entry\n"); + BUS_SET_OOM (error); + return FALSE; + } + + pending_activation_entry->auto_activation = auto_activation; + + pending_activation_entry->activation_message = activation_message; + dbus_message_ref (activation_message); + pending_activation_entry->connection = connection; + dbus_connection_ref (connection); + + /* Check if the service is being activated */ + pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name); + if (pending_activation) + { + if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry)) + { + _dbus_verbose ("Failed to append a new entry to pending activation\n"); + + BUS_SET_OOM (error); + bus_pending_activation_entry_free (pending_activation_entry); + return FALSE; + } + + pending_activation->n_entries += 1; + pending_activation->activation->n_pending_activations += 1; + } + else + { + pending_activation = dbus_new0 (BusPendingActivation, 1); + if (!pending_activation) + { + _dbus_verbose ("Failed to create pending activation\n"); + + BUS_SET_OOM (error); + bus_pending_activation_entry_free (pending_activation_entry); + return FALSE; + } + + pending_activation->activation = activation; + pending_activation->refcount = 1; + + pending_activation->service_name = _dbus_strdup (service_name); + if (!pending_activation->service_name) + { + _dbus_verbose ("Failed to copy service name for pending activation\n"); + + BUS_SET_OOM (error); + bus_pending_activation_unref (pending_activation); + bus_pending_activation_entry_free (pending_activation_entry); + return FALSE; + } + + pending_activation->exec = _dbus_strdup (entry->exec); + if (!pending_activation->exec) + { + _dbus_verbose ("Failed to copy service exec for pending activation\n"); + BUS_SET_OOM (error); + bus_pending_activation_unref (pending_activation); + bus_pending_activation_entry_free (pending_activation_entry); + return FALSE; + } + + pending_activation->timeout = + _dbus_timeout_new (bus_context_get_activation_timeout (activation->context), + pending_activation_timed_out, + pending_activation, + NULL); + if (!pending_activation->timeout) + { + _dbus_verbose ("Failed to create timeout for pending activation\n"); + + BUS_SET_OOM (error); + bus_pending_activation_unref (pending_activation); + bus_pending_activation_entry_free (pending_activation_entry); + return FALSE; + } + + if (!_dbus_loop_add_timeout (bus_context_get_loop (activation->context), + pending_activation->timeout, + handle_timeout_callback, + pending_activation, + NULL)) + { + _dbus_verbose ("Failed to add timeout for pending activation\n"); + + BUS_SET_OOM (error); + bus_pending_activation_unref (pending_activation); + bus_pending_activation_entry_free (pending_activation_entry); + return FALSE; + } + + pending_activation->timeout_added = TRUE; + + if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry)) + { + _dbus_verbose ("Failed to add entry to just-created pending activation\n"); + + BUS_SET_OOM (error); + bus_pending_activation_unref (pending_activation); + bus_pending_activation_entry_free (pending_activation_entry); + return FALSE; + } + + pending_activation->n_entries += 1; + pending_activation->activation->n_pending_activations += 1; + + activated = FALSE; + _dbus_hash_iter_init (activation->pending_activations, &iter); + while (_dbus_hash_iter_next (&iter)) + { + BusPendingActivation *p = _dbus_hash_iter_get_value (&iter); + + if (strcmp (p->exec, entry->exec) == 0) + { + activated = TRUE; + break; + } + } + + if (!_dbus_hash_table_insert_string (activation->pending_activations, + pending_activation->service_name, + pending_activation)) + { + _dbus_verbose ("Failed to put pending activation in hash table\n"); + + BUS_SET_OOM (error); + bus_pending_activation_unref (pending_activation); + return FALSE; + } + } + + if (!add_cancel_pending_to_transaction (transaction, pending_activation)) + { + _dbus_verbose ("Failed to add pending activation cancel hook to transaction\n"); + BUS_SET_OOM (error); + _dbus_hash_table_remove_string (activation->pending_activations, + pending_activation->service_name); + + return FALSE; + } + + if (activated) + return TRUE; + + /* use command as system and session different */ + if (!_dbus_string_init (&command)) + { + BUS_SET_OOM (error); + return FALSE; + } + + /* does the bus use a helper? */ + servicehelper = bus_context_get_servicehelper (activation->context); + if (servicehelper != NULL) + { + if (entry->user == NULL) + { + _dbus_string_free (&command); + dbus_set_error (error, DBUS_ERROR_SPAWN_FILE_INVALID, + "Cannot do system-bus activation with no user\n"); + return FALSE; + } + + /* join the helper path and the service name */ + if (!_dbus_string_append (&command, servicehelper)) + { + _dbus_string_free (&command); + BUS_SET_OOM (error); + return FALSE; + } + if (!_dbus_string_append (&command, " ")) + { + _dbus_string_free (&command); + BUS_SET_OOM (error); + return FALSE; + } + if (!_dbus_string_append (&command, service_name)) + { + _dbus_string_free (&command); + BUS_SET_OOM (error); + return FALSE; + } + } + else + { + /* the bus does not use a helper, so we can append arguments with the exec line */ + if (!_dbus_string_append (&command, entry->exec)) + { + _dbus_string_free (&command); + BUS_SET_OOM (error); + return FALSE; + } + } + + /* convert command into arguments */ + if (!_dbus_shell_parse_argv (_dbus_string_get_const_data (&command), &argc, &argv, error)) + { + _dbus_verbose ("Failed to parse command line: %s\n", entry->exec); + _DBUS_ASSERT_ERROR_IS_SET (error); + + _dbus_hash_table_remove_string (activation->pending_activations, + pending_activation->service_name); + + _dbus_string_free (&command); + return FALSE; + } + _dbus_string_free (&command); + + if (!add_bus_environment (activation, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_free_string_array (argv); + return FALSE; + } + + envp = bus_activation_get_environment (activation); + + if (envp == NULL) + { + BUS_SET_OOM (error); + dbus_free_string_array (argv); + return FALSE; + } + + _dbus_verbose ("Spawning %s ...\n", argv[0]); + if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv, + envp, + NULL, activation, + error)) + { + _dbus_verbose ("Failed to spawn child\n"); + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_free_string_array (argv); + dbus_free_string_array (envp); + + return FALSE; + } + + dbus_free_string_array (argv); + envp = NULL; + + _dbus_assert (pending_activation->babysitter != NULL); + + if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter, + add_babysitter_watch, + remove_babysitter_watch, + NULL, + pending_activation, + NULL)) + { + BUS_SET_OOM (error); + _dbus_verbose ("Failed to set babysitter watch functions\n"); + return FALSE; + } + + return TRUE; +} + +dbus_bool_t +bus_activation_list_services (BusActivation *activation, + char ***listp, + int *array_len) +{ + int i, j, len; + char **retval; + DBusHashIter iter; + + len = _dbus_hash_table_get_n_entries (activation->entries); + retval = dbus_new (char *, len + 1); + + if (retval == NULL) + return FALSE; + + _dbus_hash_iter_init (activation->entries, &iter); + i = 0; + while (_dbus_hash_iter_next (&iter)) + { + BusActivationEntry *entry = _dbus_hash_iter_get_value (&iter); + + retval[i] = _dbus_strdup (entry->name); + if (retval[i] == NULL) + goto error; + + i++; + } + + retval[i] = NULL; + + if (array_len) + *array_len = len; + + *listp = retval; + return TRUE; + + error: + for (j = 0; j < i; j++) + dbus_free (retval[i]); + dbus_free (retval); + + return FALSE; +} + + +#ifdef DBUS_BUILD_TESTS + +#include + +#define SERVICE_NAME_1 "MyService1" +#define SERVICE_NAME_2 "MyService2" +#define SERVICE_NAME_3 "MyService3" + +#define SERVICE_FILE_1 "service-1.service" +#define SERVICE_FILE_2 "service-2.service" +#define SERVICE_FILE_3 "service-3.service" + +static dbus_bool_t +test_create_service_file (DBusString *dir, + const char *filename, + const char *name, + const char *exec) +{ + DBusString file_name, full_path; + FILE *file; + dbus_bool_t ret_val; + + ret_val = TRUE; + _dbus_string_init_const (&file_name, filename); + + if (!_dbus_string_init (&full_path)) + return FALSE; + + if (!_dbus_string_append (&full_path, _dbus_string_get_const_data (dir)) || + !_dbus_concat_dir_and_file (&full_path, &file_name)) + { + ret_val = FALSE; + goto out; + } + + file = fopen (_dbus_string_get_const_data (&full_path), "w"); + if (!file) + { + ret_val = FALSE; + goto out; + } + + fprintf (file, "[D-BUS Service]\nName=%s\nExec=%s\n", name, exec); + fclose (file); + +out: + _dbus_string_free (&full_path); + return ret_val; +} + +static dbus_bool_t +test_remove_service_file (DBusString *dir, const char *filename) +{ + DBusString file_name, full_path; + dbus_bool_t ret_val; + + ret_val = TRUE; + + _dbus_string_init_const (&file_name, filename); + + if (!_dbus_string_init (&full_path)) + return FALSE; + + if (!_dbus_string_append (&full_path, _dbus_string_get_const_data (dir)) || + !_dbus_concat_dir_and_file (&full_path, &file_name)) + { + ret_val = FALSE; + goto out; + } + + if (!_dbus_delete_file (&full_path, NULL)) + { + ret_val = FALSE; + goto out; + } + +out: + _dbus_string_free (&full_path); + return ret_val; +} + +static dbus_bool_t +test_remove_directory (DBusString *dir) +{ + DBusDirIter *iter; + DBusString filename, full_path; + dbus_bool_t ret_val; + + ret_val = TRUE; + + if (!_dbus_string_init (&filename)) + return FALSE; + + if (!_dbus_string_init (&full_path)) + { + _dbus_string_free (&filename); + return FALSE; + } + + iter = _dbus_directory_open (dir, NULL); + if (iter == NULL) + { + ret_val = FALSE; + goto out; + } + + while (_dbus_directory_get_next_file (iter, &filename, NULL)) + { + if (!test_remove_service_file (dir, _dbus_string_get_const_data (&filename))) + { + ret_val = FALSE; + goto out; + } + } + _dbus_directory_close (iter); + + if (!_dbus_delete_directory (dir, NULL)) + { + ret_val = FALSE; + goto out; + } + +out: + _dbus_string_free (&filename); + _dbus_string_free (&full_path); + + return ret_val; +} + +static dbus_bool_t +init_service_reload_test (DBusString *dir) +{ + DBusStat stat_buf; + + if (!_dbus_stat (dir, &stat_buf, NULL)) + { + if (!_dbus_create_directory (dir, NULL)) + return FALSE; + } + else + { + if (!test_remove_directory (dir)) + return FALSE; + + if (!_dbus_create_directory (dir, NULL)) + return FALSE; + } + + /* Create one initial file */ + if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_1, "exec-1")) + return FALSE; + + return TRUE; +} + +static dbus_bool_t +cleanup_service_reload_test (DBusString *dir) +{ + if (!test_remove_directory (dir)) + return FALSE; + + return TRUE; +} + +typedef struct +{ + BusActivation *activation; + const char *service_name; + dbus_bool_t expecting_find; +} CheckData; + +static dbus_bool_t +check_func (void *data) +{ + CheckData *d; + BusActivationEntry *entry; + DBusError error; + dbus_bool_t ret_val; + + ret_val = TRUE; + d = data; + + dbus_error_init (&error); + + entry = activation_find_entry (d->activation, d->service_name, &error); + if (entry == NULL) + { + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + ret_val = TRUE; + } + else + { + if (d->expecting_find) + ret_val = FALSE; + } + + dbus_error_free (&error); + } + else + { + if (!d->expecting_find) + ret_val = FALSE; + } + + return ret_val; +} + +static dbus_bool_t +do_test (const char *description, dbus_bool_t oom_test, CheckData *data) +{ + dbus_bool_t err; + + if (oom_test) + err = !_dbus_test_oom_handling (description, check_func, data); + else + err = !check_func (data); + + if (err) + _dbus_assert_not_reached ("Test failed"); + + return TRUE; +} + +static dbus_bool_t +do_service_reload_test (DBusString *dir, dbus_bool_t oom_test) +{ + BusActivation *activation; + DBusString address; + DBusList *directories; + CheckData d; + + directories = NULL; + _dbus_string_init_const (&address, ""); + + if (!_dbus_list_append (&directories, _dbus_string_get_data (dir))) + return FALSE; + + activation = bus_activation_new (NULL, &address, &directories, NULL); + if (!activation) + return FALSE; + + d.activation = activation; + + /* Check for existing service file */ + d.expecting_find = TRUE; + d.service_name = SERVICE_NAME_1; + + if (!do_test ("Existing service file", oom_test, &d)) + return FALSE; + + /* Check for non-existing service file */ + d.expecting_find = FALSE; + d.service_name = SERVICE_NAME_3; + + if (!do_test ("Nonexisting service file", oom_test, &d)) + return FALSE; + + /* Check for added service file */ + if (!test_create_service_file (dir, SERVICE_FILE_2, SERVICE_NAME_2, "exec-2")) + return FALSE; + + d.expecting_find = TRUE; + d.service_name = SERVICE_NAME_2; + + if (!do_test ("Added service file", oom_test, &d)) + return FALSE; + + /* Check for removed service file */ + if (!test_remove_service_file (dir, SERVICE_FILE_2)) + return FALSE; + + d.expecting_find = FALSE; + d.service_name = SERVICE_FILE_2; + + if (!do_test ("Removed service file", oom_test, &d)) + return FALSE; + + /* Check for updated service file */ + + _dbus_sleep_milliseconds (1000); /* Sleep a second to make sure the mtime is updated */ + + if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_3, "exec-3")) + return FALSE; + + d.expecting_find = TRUE; + d.service_name = SERVICE_NAME_3; + + if (!do_test ("Updated service file, part 1", oom_test, &d)) + return FALSE; + + d.expecting_find = FALSE; + d.service_name = SERVICE_NAME_1; + + if (!do_test ("Updated service file, part 2", oom_test, &d)) + return FALSE; + + bus_activation_unref (activation); + _dbus_list_clear (&directories); + + return TRUE; +} + +dbus_bool_t +bus_activation_service_reload_test (const DBusString *test_data_dir) +{ + DBusString directory; + + if (!_dbus_string_init (&directory)) + return FALSE; + + if (!_dbus_string_append (&directory, _dbus_get_tmpdir())) + return FALSE; + + if (!_dbus_string_append (&directory, "/dbus-reload-test-") || + !_dbus_generate_random_ascii (&directory, 6)) + { + return FALSE; + } + + /* Do normal tests */ + if (!init_service_reload_test (&directory)) + _dbus_assert_not_reached ("could not initiate service reload test"); + + if (!do_service_reload_test (&directory, FALSE)) + ; /* Do nothing? */ + + /* Do OOM tests */ + if (!init_service_reload_test (&directory)) + _dbus_assert_not_reached ("could not initiate service reload test"); + + if (!do_service_reload_test (&directory, TRUE)) + ; /* Do nothing? */ + + /* Cleanup test directory */ + if (!cleanup_service_reload_test (&directory)) + return FALSE; + + _dbus_string_free (&directory); + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/bus/activation.h b/bus/activation.h new file mode 100644 index 00000000..03bfed28 --- /dev/null +++ b/bus/activation.h @@ -0,0 +1,68 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* activation.h Activation of services + * + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_ACTIVATION_H +#define BUS_ACTIVATION_H + +#include +#include +#include "bus.h" + +BusActivation* bus_activation_new (BusContext *context, + const DBusString *address, + DBusList **directories, + DBusError *error); +dbus_bool_t bus_activation_reload (BusActivation *activation, + const DBusString *address, + DBusList **directories, + DBusError *error); +BusActivation* bus_activation_ref (BusActivation *activation); +void bus_activation_unref (BusActivation *activation); + +dbus_bool_t bus_activation_set_environment_variable (BusActivation *activation, + const char *key, + const char *value, + DBusError *error); +dbus_bool_t bus_activation_activate_service (BusActivation *activation, + DBusConnection *connection, + BusTransaction *transaction, + dbus_bool_t auto_activation, + DBusMessage *activation_message, + const char *service_name, + DBusError *error); +dbus_bool_t bus_activation_service_created (BusActivation *activation, + const char *service_name, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_activation_list_services (BusActivation *registry, + char ***listp, + int *array_len); + +dbus_bool_t bus_activation_send_pending_auto_activation_messages (BusActivation *activation, + BusService *service, + BusTransaction *transaction, + DBusError *error); + + + +#endif /* BUS_ACTIVATION_H */ diff --git a/bus/bus.c b/bus/bus.c new file mode 100644 index 00000000..fd8a8724 --- /dev/null +++ b/bus/bus.c @@ -0,0 +1,1569 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* bus.c message bus context object + * + * Copyright (C) 2003, 2004 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "bus.h" +#include "activation.h" +#include "connection.h" +#include "services.h" +#include "utils.h" +#include "policy.h" +#include "config-parser.h" +#include "signals.h" +#include "selinux.h" +#include "dir-watch.h" +#include +#include +#include +#include + +struct BusContext +{ + int refcount; + DBusGUID uuid; + char *config_file; + char *type; + char *servicehelper; + char *address; + char *pidfile; + char *user; + char *log_prefix; + DBusLoop *loop; + DBusList *servers; + BusConnections *connections; + BusActivation *activation; + BusRegistry *registry; + BusPolicy *policy; + BusMatchmaker *matchmaker; + BusLimits limits; + unsigned int fork : 1; + unsigned int syslog : 1; + unsigned int keep_umask : 1; +}; + +static dbus_int32_t server_data_slot = -1; + +typedef struct +{ + BusContext *context; +} BusServerData; + +#define BUS_SERVER_DATA(server) (dbus_server_get_data ((server), server_data_slot)) + +static BusContext* +server_get_context (DBusServer *server) +{ + BusContext *context; + BusServerData *bd; + + if (!dbus_server_allocate_data_slot (&server_data_slot)) + return NULL; + + bd = BUS_SERVER_DATA (server); + if (bd == NULL) + { + dbus_server_free_data_slot (&server_data_slot); + return NULL; + } + + context = bd->context; + + dbus_server_free_data_slot (&server_data_slot); + + return context; +} + +static dbus_bool_t +server_watch_callback (DBusWatch *watch, + unsigned int condition, + void *data) +{ + /* FIXME this can be done in dbus-mainloop.c + * if the code in activation.c for the babysitter + * watch handler is fixed. + */ + + return dbus_watch_handle (watch, condition); +} + +static dbus_bool_t +add_server_watch (DBusWatch *watch, + void *data) +{ + DBusServer *server = data; + BusContext *context; + + context = server_get_context (server); + + return _dbus_loop_add_watch (context->loop, + watch, server_watch_callback, server, + NULL); +} + +static void +remove_server_watch (DBusWatch *watch, + void *data) +{ + DBusServer *server = data; + BusContext *context; + + context = server_get_context (server); + + _dbus_loop_remove_watch (context->loop, + watch, server_watch_callback, server); +} + + +static void +server_timeout_callback (DBusTimeout *timeout, + void *data) +{ + /* can return FALSE on OOM but we just let it fire again later */ + dbus_timeout_handle (timeout); +} + +static dbus_bool_t +add_server_timeout (DBusTimeout *timeout, + void *data) +{ + DBusServer *server = data; + BusContext *context; + + context = server_get_context (server); + + return _dbus_loop_add_timeout (context->loop, + timeout, server_timeout_callback, server, NULL); +} + +static void +remove_server_timeout (DBusTimeout *timeout, + void *data) +{ + DBusServer *server = data; + BusContext *context; + + context = server_get_context (server); + + _dbus_loop_remove_timeout (context->loop, + timeout, server_timeout_callback, server); +} + +static void +new_connection_callback (DBusServer *server, + DBusConnection *new_connection, + void *data) +{ + BusContext *context = data; + + if (!bus_connections_setup_connection (context->connections, new_connection)) + { + _dbus_verbose ("No memory to setup new connection\n"); + + /* if we don't do this, it will get unref'd without + * being disconnected... kind of strange really + * that we have to do this, people won't get it right + * in general. + */ + dbus_connection_close (new_connection); + } + + dbus_connection_set_max_received_size (new_connection, + context->limits.max_incoming_bytes); + + dbus_connection_set_max_message_size (new_connection, + context->limits.max_message_size); + + /* on OOM, we won't have ref'd the connection so it will die. */ +} + +static void +free_server_data (void *data) +{ + BusServerData *bd = data; + + dbus_free (bd); +} + +static dbus_bool_t +setup_server (BusContext *context, + DBusServer *server, + char **auth_mechanisms, + DBusError *error) +{ + BusServerData *bd; + + bd = dbus_new0 (BusServerData, 1); + if (bd == NULL || !dbus_server_set_data (server, + server_data_slot, + bd, free_server_data)) + { + dbus_free (bd); + BUS_SET_OOM (error); + return FALSE; + } + + bd->context = context; + + if (!dbus_server_set_auth_mechanisms (server, (const char**) auth_mechanisms)) + { + BUS_SET_OOM (error); + return FALSE; + } + + dbus_server_set_new_connection_function (server, + new_connection_callback, + context, NULL); + + if (!dbus_server_set_watch_functions (server, + add_server_watch, + remove_server_watch, + NULL, + server, + NULL)) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!dbus_server_set_timeout_functions (server, + add_server_timeout, + remove_server_timeout, + NULL, + server, NULL)) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; +} + +/* This code only gets executed the first time the + * config files are parsed. It is not executed + * when config files are reloaded. + */ +static dbus_bool_t +process_config_first_time_only (BusContext *context, + BusConfigParser *parser, + DBusError *error) +{ + DBusString log_prefix; + DBusList *link; + DBusList **addresses; + const char *user, *pidfile; + char **auth_mechanisms; + DBusList **auth_mechanisms_list; + int len; + dbus_bool_t retval; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + retval = FALSE; + auth_mechanisms = NULL; + + /* Check for an existing pid file. Of course this is a race; + * we'd have to use fcntl() locks on the pid file to + * avoid that. But we want to check for the pid file + * before overwriting any existing sockets, etc. + */ + pidfile = bus_config_parser_get_pidfile (parser); + if (pidfile != NULL) + { + DBusString u; + DBusStat stbuf; + + _dbus_string_init_const (&u, pidfile); + + if (_dbus_stat (&u, &stbuf, NULL)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "The pid file \"%s\" exists, if the message bus is not running, remove this file", + pidfile); + goto failed; + } + } + + /* keep around the pid filename so we can delete it later */ + context->pidfile = _dbus_strdup (pidfile); + + /* note that type may be NULL */ + context->type = _dbus_strdup (bus_config_parser_get_type (parser)); + if (bus_config_parser_get_type (parser) != NULL && context->type == NULL) + goto oom; + + user = bus_config_parser_get_user (parser); + if (user != NULL) + { + context->user = _dbus_strdup (user); + if (context->user == NULL) + goto oom; + } + + /* Set up the prefix for syslog messages */ + if (!_dbus_string_init (&log_prefix)) + goto oom; + if (context->type && !strcmp (context->type, "system")) + { + if (!_dbus_string_append (&log_prefix, "[system] ")) + goto oom; + } + else if (context->type && !strcmp (context->type, "session")) + { + DBusCredentials *credentials; + + credentials = _dbus_credentials_new_from_current_process (); + if (!credentials) + goto oom; + if (!_dbus_string_append (&log_prefix, "[session ")) + goto oom; + if (!_dbus_credentials_to_string_append (credentials, &log_prefix)) + goto oom; + if (!_dbus_string_append (&log_prefix, "] ")) + goto oom; + _dbus_credentials_unref (credentials); + } + if (!_dbus_string_steal_data (&log_prefix, &context->log_prefix)) + goto oom; + _dbus_string_free (&log_prefix); + + /* Build an array of auth mechanisms */ + + auth_mechanisms_list = bus_config_parser_get_mechanisms (parser); + len = _dbus_list_get_length (auth_mechanisms_list); + + if (len > 0) + { + int i; + + auth_mechanisms = dbus_new0 (char*, len + 1); + if (auth_mechanisms == NULL) + goto oom; + + i = 0; + link = _dbus_list_get_first_link (auth_mechanisms_list); + while (link != NULL) + { + auth_mechanisms[i] = _dbus_strdup (link->data); + if (auth_mechanisms[i] == NULL) + goto oom; + link = _dbus_list_get_next_link (auth_mechanisms_list, link); + } + } + else + { + auth_mechanisms = NULL; + } + + /* Listen on our addresses */ + + addresses = bus_config_parser_get_addresses (parser); + + link = _dbus_list_get_first_link (addresses); + while (link != NULL) + { + DBusServer *server; + + server = dbus_server_listen (link->data, error); + if (server == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + else if (!setup_server (context, server, auth_mechanisms, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + if (!_dbus_list_append (&context->servers, server)) + goto oom; + + link = _dbus_list_get_next_link (addresses, link); + } + + context->fork = bus_config_parser_get_fork (parser); + context->syslog = bus_config_parser_get_syslog (parser); + context->keep_umask = bus_config_parser_get_keep_umask (parser); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + retval = TRUE; + + failed: + dbus_free_string_array (auth_mechanisms); + return retval; + + oom: + BUS_SET_OOM (error); + dbus_free_string_array (auth_mechanisms); + return FALSE; +} + +/* This code gets executed every time the config files + * are parsed: both during BusContext construction + * and on reloads. This function is slightly screwy + * since it can do a "half reload" in out-of-memory + * situations. Realistically, unlikely to ever matter. + */ +static dbus_bool_t +process_config_every_time (BusContext *context, + BusConfigParser *parser, + dbus_bool_t is_reload, + DBusError *error) +{ + DBusString full_address; + DBusList *link; + DBusList **dirs; + BusActivation *new_activation; + char *addr; + const char *servicehelper; + char *s; + + dbus_bool_t retval; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + addr = NULL; + retval = FALSE; + + if (!_dbus_string_init (&full_address)) + { + BUS_SET_OOM (error); + return FALSE; + } + + /* get our limits and timeout lengths */ + bus_config_parser_get_limits (parser, &context->limits); + + if (context->policy) + bus_policy_unref (context->policy); + context->policy = bus_config_parser_steal_policy (parser); + _dbus_assert (context->policy != NULL); + + /* We have to build the address backward, so that + * later in the config file have priority + */ + link = _dbus_list_get_last_link (&context->servers); + while (link != NULL) + { + addr = dbus_server_get_address (link->data); + if (addr == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + if (_dbus_string_get_length (&full_address) > 0) + { + if (!_dbus_string_append (&full_address, ";")) + { + BUS_SET_OOM (error); + goto failed; + } + } + + if (!_dbus_string_append (&full_address, addr)) + { + BUS_SET_OOM (error); + goto failed; + } + + dbus_free (addr); + addr = NULL; + + link = _dbus_list_get_prev_link (&context->servers, link); + } + + if (is_reload) + dbus_free (context->address); + + if (!_dbus_string_copy_data (&full_address, &context->address)) + { + BUS_SET_OOM (error); + goto failed; + } + + /* get the service directories */ + dirs = bus_config_parser_get_service_dirs (parser); + + /* and the service helper */ + servicehelper = bus_config_parser_get_servicehelper (parser); + + s = _dbus_strdup(servicehelper); + if (s == NULL && servicehelper != NULL) + { + BUS_SET_OOM (error); + goto failed; + } + else + { + dbus_free(context->servicehelper); + context->servicehelper = s; + } + + /* Create activation subsystem */ + if (context->activation) + { + if (!bus_activation_reload (context->activation, &full_address, dirs, error)) + goto failed; + } + else + { + context->activation = bus_activation_new (context, &full_address, dirs, error); + } + + if (context->activation == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + retval = TRUE; + + failed: + _dbus_string_free (&full_address); + + if (addr) + dbus_free (addr); + + return retval; +} + +static dbus_bool_t +list_concat_new (DBusList **a, + DBusList **b, + DBusList **result) +{ + DBusList *link; + + *result = NULL; + + link = _dbus_list_get_first_link (a); + for (link = _dbus_list_get_first_link (a); link; link = _dbus_list_get_next_link (a, link)) + { + if (!_dbus_list_append (result, link->data)) + goto oom; + } + for (link = _dbus_list_get_first_link (b); link; link = _dbus_list_get_next_link (b, link)) + { + if (!_dbus_list_append (result, link->data)) + goto oom; + } + + return TRUE; +oom: + _dbus_list_clear (result); + return FALSE; +} + +static dbus_bool_t +process_config_postinit (BusContext *context, + BusConfigParser *parser, + DBusError *error) +{ + DBusHashTable *service_context_table; + DBusList *watched_dirs = NULL; + + service_context_table = bus_config_parser_steal_service_context_table (parser); + if (!bus_registry_set_service_context_table (context->registry, + service_context_table)) + { + BUS_SET_OOM (error); + return FALSE; + } + + _dbus_hash_table_unref (service_context_table); + + /* We need to monitor both the configuration directories and directories + * containing .service files. + */ + if (!list_concat_new (bus_config_parser_get_conf_dirs (parser), + bus_config_parser_get_service_dirs (parser), + &watched_dirs)) + { + BUS_SET_OOM (error); + return FALSE; + } + + bus_set_watched_dirs (context, &watched_dirs); + + _dbus_list_clear (&watched_dirs); + + return TRUE; +} + +BusContext* +bus_context_new (const DBusString *config_file, + ForceForkSetting force_fork, + DBusPipe *print_addr_pipe, + DBusPipe *print_pid_pipe, + DBusError *error) +{ + DBusString log_prefix; + BusContext *context; + BusConfigParser *parser; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + context = NULL; + parser = NULL; + + if (!dbus_server_allocate_data_slot (&server_data_slot)) + { + BUS_SET_OOM (error); + return NULL; + } + + context = dbus_new0 (BusContext, 1); + if (context == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + context->refcount = 1; + + _dbus_generate_uuid (&context->uuid); + + if (!_dbus_string_copy_data (config_file, &context->config_file)) + { + BUS_SET_OOM (error); + goto failed; + } + + context->loop = _dbus_loop_new (); + if (context->loop == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + context->registry = bus_registry_new (context); + if (context->registry == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + parser = bus_config_load (config_file, TRUE, NULL, error); + if (parser == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + if (!process_config_first_time_only (context, parser, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + if (!process_config_every_time (context, parser, FALSE, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + /* we need another ref of the server data slot for the context + * to own + */ + if (!dbus_server_allocate_data_slot (&server_data_slot)) + _dbus_assert_not_reached ("second ref of server data slot failed"); + + /* Note that we don't know whether the print_addr_pipe is + * one of the sockets we're using to listen on, or some + * other random thing. But I think the answer is "don't do + * that then" + */ + if (print_addr_pipe != NULL && _dbus_pipe_is_valid (print_addr_pipe)) + { + DBusString addr; + const char *a = bus_context_get_address (context); + int bytes; + + _dbus_assert (a != NULL); + if (!_dbus_string_init (&addr)) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!_dbus_string_append (&addr, a) || + !_dbus_string_append (&addr, "\n")) + { + _dbus_string_free (&addr); + BUS_SET_OOM (error); + goto failed; + } + + bytes = _dbus_string_get_length (&addr); + if (_dbus_pipe_write (print_addr_pipe, &addr, 0, bytes, error) != bytes) + { + /* pipe write returns an error on failure but not short write */ + if (error != NULL && !dbus_error_is_set (error)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Printing message bus address: did not write all bytes\n"); + } + _dbus_string_free (&addr); + goto failed; + } + + if (!_dbus_pipe_is_stdout_or_stderr (print_addr_pipe)) + _dbus_pipe_close (print_addr_pipe, NULL); + + _dbus_string_free (&addr); + } + + context->connections = bus_connections_new (context); + if (context->connections == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + context->matchmaker = bus_matchmaker_new (); + if (context->matchmaker == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + /* check user before we fork */ + if (context->user != NULL) + { + if (!_dbus_verify_daemon_user (context->user)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Could not get UID and GID for username \"%s\"", + context->user); + goto failed; + } + } + + /* Now become a daemon if appropriate and write out pid file in any case */ + { + DBusString u; + + if (context->pidfile) + _dbus_string_init_const (&u, context->pidfile); + + if ((force_fork != FORK_NEVER && context->fork) || force_fork == FORK_ALWAYS) + { + _dbus_verbose ("Forking and becoming daemon\n"); + + if (!_dbus_become_daemon (context->pidfile ? &u : NULL, + print_pid_pipe, + error, + context->keep_umask)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + } + else + { + _dbus_verbose ("Fork not requested\n"); + + /* Need to write PID file and to PID pipe for ourselves, + * not for the child process. This is a no-op if the pidfile + * is NULL and print_pid_pipe is NULL. + */ + if (!_dbus_write_pid_to_file_and_pipe (context->pidfile ? &u : NULL, + print_pid_pipe, + _dbus_getpid (), + error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + } + } + + if (print_pid_pipe && _dbus_pipe_is_valid (print_pid_pipe) && + !_dbus_pipe_is_stdout_or_stderr (print_pid_pipe)) + _dbus_pipe_close (print_pid_pipe, NULL); + + if (!bus_selinux_full_init ()) + { + bus_context_log (context, DBUS_SYSTEM_LOG_FATAL, "SELinux enabled but AVC initialization failed; check system log\n"); + } + + if (!process_config_postinit (context, parser, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + if (parser != NULL) + { + bus_config_parser_unref (parser); + parser = NULL; + } + + /* Here we change our credentials if required, + * as soon as we've set up our sockets and pidfile + */ + if (context->user != NULL) + { + if (!_dbus_change_to_daemon_user (context->user, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + +#ifdef HAVE_SELINUX + /* FIXME - why not just put this in full_init() below? */ + bus_selinux_audit_init (); +#endif + } + + dbus_server_free_data_slot (&server_data_slot); + + return context; + + failed: + if (parser != NULL) + bus_config_parser_unref (parser); + if (context != NULL) + bus_context_unref (context); + + if (server_data_slot >= 0) + dbus_server_free_data_slot (&server_data_slot); + + return NULL; +} + +dbus_bool_t +bus_context_get_id (BusContext *context, + DBusString *uuid) +{ + return _dbus_uuid_encode (&context->uuid, uuid); +} + +dbus_bool_t +bus_context_reload_config (BusContext *context, + DBusError *error) +{ + BusConfigParser *parser; + DBusString config_file; + dbus_bool_t ret; + + /* Flush the user database cache */ + _dbus_flush_caches (); + + ret = FALSE; + _dbus_string_init_const (&config_file, context->config_file); + parser = bus_config_load (&config_file, TRUE, NULL, error); + if (parser == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + + if (!process_config_every_time (context, parser, TRUE, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + if (!process_config_postinit (context, parser, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed; + } + ret = TRUE; + + bus_context_log (context, DBUS_SYSTEM_LOG_INFO, "Reloaded configuration"); + failed: + if (!ret) + bus_context_log (context, DBUS_SYSTEM_LOG_INFO, "Unable to reload configuration: %s", error->message); + if (parser != NULL) + bus_config_parser_unref (parser); + return ret; +} + +static void +shutdown_server (BusContext *context, + DBusServer *server) +{ + if (server == NULL || + !dbus_server_get_is_connected (server)) + return; + + if (!dbus_server_set_watch_functions (server, + NULL, NULL, NULL, + context, + NULL)) + _dbus_assert_not_reached ("setting watch functions to NULL failed"); + + if (!dbus_server_set_timeout_functions (server, + NULL, NULL, NULL, + context, + NULL)) + _dbus_assert_not_reached ("setting timeout functions to NULL failed"); + + dbus_server_disconnect (server); +} + +void +bus_context_shutdown (BusContext *context) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&context->servers); + while (link != NULL) + { + shutdown_server (context, link->data); + + link = _dbus_list_get_next_link (&context->servers, link); + } +} + +BusContext * +bus_context_ref (BusContext *context) +{ + _dbus_assert (context->refcount > 0); + context->refcount += 1; + + return context; +} + +void +bus_context_unref (BusContext *context) +{ + _dbus_assert (context->refcount > 0); + context->refcount -= 1; + + if (context->refcount == 0) + { + DBusList *link; + + _dbus_verbose ("Finalizing bus context %p\n", context); + + bus_context_shutdown (context); + + if (context->connections) + { + bus_connections_unref (context->connections); + context->connections = NULL; + } + + if (context->registry) + { + bus_registry_unref (context->registry); + context->registry = NULL; + } + + if (context->activation) + { + bus_activation_unref (context->activation); + context->activation = NULL; + } + + link = _dbus_list_get_first_link (&context->servers); + while (link != NULL) + { + dbus_server_unref (link->data); + + link = _dbus_list_get_next_link (&context->servers, link); + } + _dbus_list_clear (&context->servers); + + if (context->policy) + { + bus_policy_unref (context->policy); + context->policy = NULL; + } + + if (context->loop) + { + _dbus_loop_unref (context->loop); + context->loop = NULL; + } + + if (context->matchmaker) + { + bus_matchmaker_unref (context->matchmaker); + context->matchmaker = NULL; + } + + dbus_free (context->config_file); + dbus_free (context->log_prefix); + dbus_free (context->type); + dbus_free (context->address); + dbus_free (context->user); + dbus_free (context->servicehelper); + + if (context->pidfile) + { + DBusString u; + _dbus_string_init_const (&u, context->pidfile); + + /* Deliberately ignore errors here, since there's not much + * we can do about it, and we're exiting anyways. + */ + _dbus_delete_file (&u, NULL); + + dbus_free (context->pidfile); + } + dbus_free (context); + + dbus_server_free_data_slot (&server_data_slot); + } +} + +/* type may be NULL */ +const char* +bus_context_get_type (BusContext *context) +{ + return context->type; +} + +const char* +bus_context_get_address (BusContext *context) +{ + return context->address; +} + +const char* +bus_context_get_servicehelper (BusContext *context) +{ + return context->servicehelper; +} + +BusRegistry* +bus_context_get_registry (BusContext *context) +{ + return context->registry; +} + +BusConnections* +bus_context_get_connections (BusContext *context) +{ + return context->connections; +} + +BusActivation* +bus_context_get_activation (BusContext *context) +{ + return context->activation; +} + +BusMatchmaker* +bus_context_get_matchmaker (BusContext *context) +{ + return context->matchmaker; +} + +DBusLoop* +bus_context_get_loop (BusContext *context) +{ + return context->loop; +} + +dbus_bool_t +bus_context_allow_unix_user (BusContext *context, + unsigned long uid) +{ + return bus_policy_allow_unix_user (context->policy, + uid); +} + +/* For now this is never actually called because the default + * DBusConnection behavior of 'same user that owns the bus can connect' + * is all it would do. + */ +dbus_bool_t +bus_context_allow_windows_user (BusContext *context, + const char *windows_sid) +{ + return bus_policy_allow_windows_user (context->policy, + windows_sid); +} + +BusPolicy * +bus_context_get_policy (BusContext *context) +{ + return context->policy; +} + +BusClientPolicy* +bus_context_create_client_policy (BusContext *context, + DBusConnection *connection, + DBusError *error) +{ + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return bus_policy_create_client_policy (context->policy, connection, + error); +} + +int +bus_context_get_activation_timeout (BusContext *context) +{ + + return context->limits.activation_timeout; +} + +int +bus_context_get_auth_timeout (BusContext *context) +{ + return context->limits.auth_timeout; +} + +int +bus_context_get_max_completed_connections (BusContext *context) +{ + return context->limits.max_completed_connections; +} + +int +bus_context_get_max_incomplete_connections (BusContext *context) +{ + return context->limits.max_incomplete_connections; +} + +int +bus_context_get_max_connections_per_user (BusContext *context) +{ + return context->limits.max_connections_per_user; +} + +int +bus_context_get_max_pending_activations (BusContext *context) +{ + return context->limits.max_pending_activations; +} + +int +bus_context_get_max_services_per_connection (BusContext *context) +{ + return context->limits.max_services_per_connection; +} + +int +bus_context_get_max_match_rules_per_connection (BusContext *context) +{ + return context->limits.max_match_rules_per_connection; +} + +int +bus_context_get_max_replies_per_connection (BusContext *context) +{ + return context->limits.max_replies_per_connection; +} + +int +bus_context_get_reply_timeout (BusContext *context) +{ + return context->limits.reply_timeout; +} + +void +bus_context_log (BusContext *context, DBusSystemLogSeverity severity, const char *msg, ...) _DBUS_GNUC_PRINTF (3, 4); + +void +bus_context_log (BusContext *context, DBusSystemLogSeverity severity, const char *msg, ...) +{ + va_list args; + + if (!context->syslog) + return; + + va_start (args, msg); + + if (context->log_prefix) + { + DBusString full_msg; + + if (!_dbus_string_init (&full_msg)) + goto out; + if (!_dbus_string_append (&full_msg, context->log_prefix)) + goto oom_out; + if (!_dbus_string_append_printf_valist (&full_msg, msg, args)) + goto oom_out; + + _dbus_system_log (severity, "%s", _dbus_string_get_const_data (&full_msg)); + oom_out: + _dbus_string_free (&full_msg); + } + else + _dbus_system_logv (severity, msg, args); + +out: + va_end (args); +} + +/* + * addressed_recipient is the recipient specified in the message. + * + * proposed_recipient is the recipient we're considering sending + * to right this second, and may be an eavesdropper. + * + * sender is the sender of the message. + * + * NULL for proposed_recipient or sender definitely means the bus driver. + * + * NULL for addressed_recipient may mean the bus driver, or may mean + * no destination was specified in the message (e.g. a signal). + */ +dbus_bool_t +bus_context_check_security_policy (BusContext *context, + BusTransaction *transaction, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, + DBusMessage *message, + DBusError *error) +{ + const char *dest; + BusClientPolicy *sender_policy; + BusClientPolicy *recipient_policy; + dbus_int32_t toggles; + dbus_bool_t log; + int type; + dbus_bool_t requested_reply; + const char *sender_name; + const char *sender_loginfo; + const char *proposed_recipient_loginfo; + + type = dbus_message_get_type (message); + dest = dbus_message_get_destination (message); + + /* dispatch.c was supposed to ensure these invariants */ + _dbus_assert (dest != NULL || + type == DBUS_MESSAGE_TYPE_SIGNAL || + (sender == NULL && !bus_connection_is_active (proposed_recipient))); + _dbus_assert (type == DBUS_MESSAGE_TYPE_SIGNAL || + addressed_recipient != NULL || + strcmp (dest, DBUS_SERVICE_DBUS) == 0); + + /* Used in logging below */ + if (sender != NULL) + { + sender_name = bus_connection_get_name (sender); + sender_loginfo = bus_connection_get_loginfo (sender); + } + else + { + sender_name = NULL; + sender_loginfo = "(bus)"; + } + + if (proposed_recipient != NULL) + proposed_recipient_loginfo = bus_connection_get_loginfo (proposed_recipient); + else + proposed_recipient_loginfo = "bus"; + + switch (type) + { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + case DBUS_MESSAGE_TYPE_SIGNAL: + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + case DBUS_MESSAGE_TYPE_ERROR: + break; + + default: + _dbus_verbose ("security check disallowing message of unknown type %d\n", + type); + + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Message bus will not accept messages of unknown type\n"); + + return FALSE; + } + + requested_reply = FALSE; + + if (sender != NULL) + { + /* First verify the SELinux access controls. If allowed then + * go on with the standard checks. + */ + if (!bus_selinux_allows_send (sender, proposed_recipient, + dbus_message_type_to_string (dbus_message_get_type (message)), + dbus_message_get_interface (message), + dbus_message_get_member (message), + dbus_message_get_error_name (message), + dest ? dest : DBUS_SERVICE_DBUS, error)) + { + if (error != NULL && !dbus_error_is_set (error)) + { + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "An SELinux policy prevents this sender " + "from sending this message to this recipient " + "(rejected message had sender \"%s\" interface \"%s\" " + "member \"%s\" error name \"%s\" destination \"%s\")", + sender_name ? sender_name : "(unset)", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + dest ? dest : DBUS_SERVICE_DBUS); + _dbus_verbose ("SELinux security check denying send to service\n"); + } + + return FALSE; + } + + if (bus_connection_is_active (sender)) + { + sender_policy = bus_connection_get_policy (sender); + _dbus_assert (sender_policy != NULL); + + /* Fill in requested_reply variable with TRUE if this is a + * reply and the reply was pending. + */ + if (dbus_message_get_reply_serial (message) != 0) + { + if (proposed_recipient != NULL /* not to the bus driver */ && + addressed_recipient == proposed_recipient /* not eavesdropping */) + { + DBusError error2; + + dbus_error_init (&error2); + requested_reply = bus_connections_check_reply (bus_connection_get_connections (sender), + transaction, + sender, addressed_recipient, message, + &error2); + if (dbus_error_is_set (&error2)) + { + dbus_move_error (&error2, error); + return FALSE; + } + } + } + } + else + { + /* Policy for inactive connections is that they can only send + * the hello message to the bus driver + */ + if (proposed_recipient == NULL && + dbus_message_is_method_call (message, + DBUS_INTERFACE_DBUS, + "Hello")) + { + _dbus_verbose ("security check allowing %s message\n", + "Hello"); + return TRUE; + } + else + { + _dbus_verbose ("security check disallowing non-%s message\n", + "Hello"); + + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Client tried to send a message other than %s without being registered", + "Hello"); + + return FALSE; + } + } + } + else + { + sender_policy = NULL; + + /* If the sender is the bus driver, we assume any reply was a + * requested reply as bus driver won't send bogus ones + */ + if (addressed_recipient == proposed_recipient /* not eavesdropping */ && + dbus_message_get_reply_serial (message) != 0) + requested_reply = TRUE; + } + + _dbus_assert ((sender != NULL && sender_policy != NULL) || + (sender == NULL && sender_policy == NULL)); + + if (proposed_recipient != NULL) + { + /* only the bus driver can send to an inactive recipient (as it + * owns no services, so other apps can't address it). Inactive + * recipients can receive any message. + */ + if (bus_connection_is_active (proposed_recipient)) + { + recipient_policy = bus_connection_get_policy (proposed_recipient); + _dbus_assert (recipient_policy != NULL); + } + else if (sender == NULL) + { + _dbus_verbose ("security check using NULL recipient policy for message from bus\n"); + recipient_policy = NULL; + } + else + { + _dbus_assert_not_reached ("a message was somehow sent to an inactive recipient from a source other than the message bus\n"); + recipient_policy = NULL; + } + } + else + recipient_policy = NULL; + + _dbus_assert ((proposed_recipient != NULL && recipient_policy != NULL) || + (proposed_recipient != NULL && sender == NULL && recipient_policy == NULL) || + (proposed_recipient == NULL && recipient_policy == NULL)); + + log = FALSE; + if (sender_policy && + !bus_client_policy_check_can_send (sender_policy, + context->registry, + requested_reply, + proposed_recipient, + message, &toggles, &log)) + { + const char *msg = "Rejected send message, %d matched rules; " + "type=\"%s\", sender=\"%s\" (%s) interface=\"%s\" member=\"%s\" error name=\"%s\" requested_reply=%d destination=\"%s\" (%s))"; + + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, msg, + toggles, + dbus_message_type_to_string (dbus_message_get_type (message)), + sender_name ? sender_name : "(unset)", + sender_loginfo, + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + requested_reply, + dest ? dest : DBUS_SERVICE_DBUS, + proposed_recipient_loginfo); + /* Needs to be duplicated to avoid calling malloc and having to handle OOM */ + if (addressed_recipient == proposed_recipient) + bus_context_log (context, DBUS_SYSTEM_LOG_SECURITY, msg, + toggles, + dbus_message_type_to_string (dbus_message_get_type (message)), + sender_name ? sender_name : "(unset)", + sender_loginfo, + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + requested_reply, + dest ? dest : DBUS_SERVICE_DBUS, + proposed_recipient_loginfo); + _dbus_verbose ("security policy disallowing message due to sender policy\n"); + return FALSE; + } + + if (log) + bus_context_log (context, DBUS_SYSTEM_LOG_SECURITY, + "Would reject message, %d matched rules; " + "type=\"%s\", sender=\"%s\" (%s) interface=\"%s\" member=\"%s\" error name=\"%s\" requested_reply=%d destination=\"%s\" (%s))", + toggles, + dbus_message_type_to_string (dbus_message_get_type (message)), + sender_name ? sender_name : "(unset)", + sender_loginfo, + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + requested_reply, + dest ? dest : DBUS_SERVICE_DBUS, + proposed_recipient_loginfo); + + if (recipient_policy && + !bus_client_policy_check_can_receive (recipient_policy, + context->registry, + requested_reply, + sender, + addressed_recipient, proposed_recipient, + message, &toggles)) + { + const char *msg = "Rejected receive message, %d matched rules; " + "type=\"%s\" sender=\"%s\" (%s) interface=\"%s\" member=\"%s\" error name=\"%s\" reply serial=%u requested_reply=%d destination=\"%s\" (%s))"; + + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, msg, + toggles, + dbus_message_type_to_string (dbus_message_get_type (message)), + sender_name ? sender_name : "(unset)", + sender_loginfo, + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + dbus_message_get_reply_serial (message), + requested_reply, + dest ? dest : DBUS_SERVICE_DBUS, + proposed_recipient_loginfo); + /* Needs to be duplicated to avoid calling malloc and having to handle OOM */ + if (addressed_recipient == proposed_recipient) + bus_context_log (context, DBUS_SYSTEM_LOG_SECURITY, msg, + toggles, + dbus_message_type_to_string (dbus_message_get_type (message)), + sender_name ? sender_name : "(unset)", + sender_loginfo, + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + dbus_message_get_reply_serial (message), + requested_reply, + dest ? dest : DBUS_SERVICE_DBUS, + proposed_recipient_loginfo); + _dbus_verbose ("security policy disallowing message due to recipient policy\n"); + return FALSE; + } + + /* See if limits on size have been exceeded */ + if (proposed_recipient && + dbus_connection_get_outgoing_size (proposed_recipient) > + context->limits.max_outgoing_bytes) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "The destination service \"%s\" has a full message queue", + dest ? dest : (proposed_recipient ? + bus_connection_get_name (proposed_recipient) : + DBUS_SERVICE_DBUS)); + _dbus_verbose ("security policy disallowing message due to full message queue\n"); + return FALSE; + } + + /* Record that we will allow a reply here in the future (don't + * bother if the recipient is the bus or this is an eavesdropping + * connection). Only the addressed recipient may reply. + */ + if (type == DBUS_MESSAGE_TYPE_METHOD_CALL && + sender && + addressed_recipient && + addressed_recipient == proposed_recipient && /* not eavesdropping */ + !bus_connections_expect_reply (bus_connection_get_connections (sender), + transaction, + sender, addressed_recipient, + message, error)) + { + _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n"); + return FALSE; + } + + _dbus_verbose ("security policy allowing message\n"); + return TRUE; +} diff --git a/bus/bus.h b/bus/bus.h new file mode 100644 index 00000000..8a04daa1 --- /dev/null +++ b/bus/bus.h @@ -0,0 +1,122 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* bus.h message bus context object + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_BUS_H +#define BUS_BUS_H + +#include + +#include +#include +#include + +typedef struct BusActivation BusActivation; +typedef struct BusConnections BusConnections; +typedef struct BusContext BusContext; +typedef struct BusPolicy BusPolicy; +typedef struct BusClientPolicy BusClientPolicy; +typedef struct BusPolicyRule BusPolicyRule; +typedef struct BusRegistry BusRegistry; +typedef struct BusSELinuxID BusSELinuxID; +typedef struct BusService BusService; +typedef struct BusOwner BusOwner; +typedef struct BusTransaction BusTransaction; +typedef struct BusMatchmaker BusMatchmaker; +typedef struct BusMatchRule BusMatchRule; + +typedef struct +{ + long max_incoming_bytes; /**< How many incoming message bytes for a single connection */ + long max_outgoing_bytes; /**< How many outgoing bytes can be queued for a single connection */ + long max_message_size; /**< Max size of a single message in bytes */ + int activation_timeout; /**< How long to wait for an activation to time out */ + int auth_timeout; /**< How long to wait for an authentication to time out */ + int max_completed_connections; /**< Max number of authorized connections */ + int max_incomplete_connections; /**< Max number of incomplete connections */ + int max_connections_per_user; /**< Max number of connections auth'd as same user */ + int max_pending_activations; /**< Max number of pending activations for the entire bus */ + int max_services_per_connection; /**< Max number of owned services for a single connection */ + int max_match_rules_per_connection; /**< Max number of match rules for a single connection */ + int max_replies_per_connection; /**< Max number of replies that can be pending for each connection */ + int reply_timeout; /**< How long to wait before timing out a reply */ +} BusLimits; + +typedef enum +{ + FORK_FOLLOW_CONFIG_FILE, + FORK_ALWAYS, + FORK_NEVER +} ForceForkSetting; + +BusContext* bus_context_new (const DBusString *config_file, + ForceForkSetting force_fork, + DBusPipe *print_addr_pipe, + DBusPipe *print_pid_pipe, + DBusError *error); +dbus_bool_t bus_context_reload_config (BusContext *context, + DBusError *error); +void bus_context_shutdown (BusContext *context); +BusContext* bus_context_ref (BusContext *context); +void bus_context_unref (BusContext *context); +dbus_bool_t bus_context_get_id (BusContext *context, + DBusString *uuid); +const char* bus_context_get_type (BusContext *context); +const char* bus_context_get_address (BusContext *context); +const char* bus_context_get_servicehelper (BusContext *context); +BusRegistry* bus_context_get_registry (BusContext *context); +BusConnections* bus_context_get_connections (BusContext *context); +BusActivation* bus_context_get_activation (BusContext *context); +BusMatchmaker* bus_context_get_matchmaker (BusContext *context); +DBusLoop* bus_context_get_loop (BusContext *context); +dbus_bool_t bus_context_allow_unix_user (BusContext *context, + unsigned long uid); +dbus_bool_t bus_context_allow_windows_user (BusContext *context, + const char *windows_sid); +BusPolicy* bus_context_get_policy (BusContext *context); + +BusClientPolicy* bus_context_create_client_policy (BusContext *context, + DBusConnection *connection, + DBusError *error); +int bus_context_get_activation_timeout (BusContext *context); +int bus_context_get_auth_timeout (BusContext *context); +int bus_context_get_max_completed_connections (BusContext *context); +int bus_context_get_max_incomplete_connections (BusContext *context); +int bus_context_get_max_connections_per_user (BusContext *context); +int bus_context_get_max_pending_activations (BusContext *context); +int bus_context_get_max_services_per_connection (BusContext *context); +int bus_context_get_max_match_rules_per_connection (BusContext *context); +int bus_context_get_max_replies_per_connection (BusContext *context); +int bus_context_get_reply_timeout (BusContext *context); +void bus_context_log (BusContext *context, + DBusSystemLogSeverity severity, + const char *msg, + ...); +dbus_bool_t bus_context_check_security_policy (BusContext *context, + BusTransaction *transaction, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, + DBusMessage *message, + DBusError *error); + +#endif /* BUS_BUS_H */ diff --git a/bus/config-loader-expat.c b/bus/config-loader-expat.c new file mode 100644 index 00000000..c0620aed --- /dev/null +++ b/bus/config-loader-expat.c @@ -0,0 +1,294 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* config-loader-expat.c expat XML loader + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config-parser.h" +#include +#include + +static XML_Memory_Handling_Suite memsuite = +{ + dbus_malloc, + dbus_realloc, + dbus_free +}; + +typedef struct +{ + BusConfigParser *parser; + const char *filename; + DBusString content; + DBusError *error; + dbus_bool_t failed; +} ExpatParseContext; + +static dbus_bool_t +process_content (ExpatParseContext *context) +{ + if (context->failed) + return FALSE; + + if (_dbus_string_get_length (&context->content) > 0) + { + if (!bus_config_parser_content (context->parser, + &context->content, + context->error)) + { + context->failed = TRUE; + return FALSE; + } + _dbus_string_set_length (&context->content, 0); + } + + return TRUE; +} + +static void +expat_StartElementHandler (void *userData, + const XML_Char *name, + const XML_Char **atts) +{ + ExpatParseContext *context = userData; + int i; + char **names; + char **values; + + /* Expat seems to suck and can't abort the parse if we + * throw an error. Expat 2.0 is supposed to fix this. + */ + if (context->failed) + return; + + if (!process_content (context)) + return; + + /* "atts" is key, value, key, value, NULL */ + for (i = 0; atts[i] != NULL; ++i) + ; /* nothing */ + + _dbus_assert (i % 2 == 0); + names = dbus_new0 (char *, i / 2 + 1); + values = dbus_new0 (char *, i / 2 + 1); + + if (names == NULL || values == NULL) + { + dbus_set_error (context->error, DBUS_ERROR_NO_MEMORY, NULL); + context->failed = TRUE; + dbus_free (names); + dbus_free (values); + return; + } + + i = 0; + while (atts[i] != NULL) + { + _dbus_assert (i % 2 == 0); + names [i / 2] = (char*) atts[i]; + values[i / 2] = (char*) atts[i+1]; + + i += 2; + } + + if (!bus_config_parser_start_element (context->parser, + name, + (const char **) names, + (const char **) values, + context->error)) + { + dbus_free (names); + dbus_free (values); + context->failed = TRUE; + return; + } + + dbus_free (names); + dbus_free (values); +} + +static void +expat_EndElementHandler (void *userData, + const XML_Char *name) +{ + ExpatParseContext *context = userData; + + if (!process_content (context)) + return; + + if (!bus_config_parser_end_element (context->parser, + name, + context->error)) + { + context->failed = TRUE; + return; + } +} + +/* s is not 0 terminated. */ +static void +expat_CharacterDataHandler (void *userData, + const XML_Char *s, + int len) +{ + ExpatParseContext *context = userData; + if (context->failed) + return; + + if (!_dbus_string_append_len (&context->content, + s, len)) + { + dbus_set_error (context->error, DBUS_ERROR_NO_MEMORY, NULL); + context->failed = TRUE; + return; + } +} + + +BusConfigParser* +bus_config_load (const DBusString *file, + dbus_bool_t is_toplevel, + const BusConfigParser *parent, + DBusError *error) +{ + XML_Parser expat; + const char *filename; + BusConfigParser *parser; + ExpatParseContext context; + DBusString dirname; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + parser = NULL; + expat = NULL; + context.error = error; + context.failed = FALSE; + + filename = _dbus_string_get_const_data (file); + + if (!_dbus_string_init (&context.content)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (!_dbus_string_init (&dirname)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (&context.content); + return NULL; + } + + expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL); + if (expat == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed; + } + + if (!_dbus_string_get_dirname (file, &dirname)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed; + } + + parser = bus_config_parser_new (&dirname, is_toplevel, parent); + if (parser == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed; + } + context.parser = parser; + + XML_SetUserData (expat, &context); + XML_SetElementHandler (expat, + expat_StartElementHandler, + expat_EndElementHandler); + XML_SetCharacterDataHandler (expat, + expat_CharacterDataHandler); + + { + DBusString data; + const char *data_str; + + if (!_dbus_string_init (&data)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed; + } + + if (!_dbus_file_get_contents (&data, file, error)) + { + _dbus_string_free (&data); + goto failed; + } + + data_str = _dbus_string_get_const_data (&data); + + if (!XML_Parse (expat, data_str, _dbus_string_get_length (&data), TRUE)) + { + if (context.error != NULL && + !dbus_error_is_set (context.error)) + { + enum XML_Error e; + + e = XML_GetErrorCode (expat); + if (e == XML_ERROR_NO_MEMORY) + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + else + dbus_set_error (error, DBUS_ERROR_FAILED, + "Error in file %s, line %d, column %d: %s\n", + filename, + XML_GetCurrentLineNumber (expat), + XML_GetCurrentColumnNumber (expat), + XML_ErrorString (e)); + } + + _dbus_string_free (&data); + goto failed; + } + + _dbus_string_free (&data); + + if (context.failed) + goto failed; + } + + if (!bus_config_parser_finished (parser, error)) + goto failed; + + _dbus_string_free (&dirname); + _dbus_string_free (&context.content); + XML_ParserFree (expat); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return parser; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + + _dbus_string_free (&dirname); + _dbus_string_free (&context.content); + if (expat) + XML_ParserFree (expat); + if (parser) + bus_config_parser_unref (parser); + return NULL; +} diff --git a/bus/config-loader-libxml.c b/bus/config-loader-libxml.c new file mode 100644 index 00000000..3d82a633 --- /dev/null +++ b/bus/config-loader-libxml.c @@ -0,0 +1,323 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* config-loader-libxml.c libxml2 XML loader + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config-parser.h" +#include +#include +#include +#include +#include +#ifdef HAVE_ERRNO_H +#include +#endif +#include + +/* About the error handling: + * - setup a "structured" error handler that catches structural + * errors and some oom errors + * - assume that a libxml function returning an error code means + * out-of-memory + */ +#define _DBUS_MAYBE_SET_OOM(e) (dbus_error_is_set(e) ? (void)0 : _DBUS_SET_OOM(e)) + + +static dbus_bool_t +xml_text_start_element (BusConfigParser *parser, + xmlTextReader *reader, + DBusError *error) +{ + const char *name; + int n_attributes; + const char **attribute_names, **attribute_values; + dbus_bool_t ret; + int i, status, is_empty; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + ret = FALSE; + attribute_names = NULL; + attribute_values = NULL; + + name = xmlTextReaderConstName (reader); + n_attributes = xmlTextReaderAttributeCount (reader); + is_empty = xmlTextReaderIsEmptyElement (reader); + + if (name == NULL || n_attributes < 0 || is_empty == -1) + { + _DBUS_MAYBE_SET_OOM (error); + goto out; + } + + attribute_names = dbus_new0 (const char *, n_attributes + 1); + attribute_values = dbus_new0 (const char *, n_attributes + 1); + if (attribute_names == NULL || attribute_values == NULL) + { + _DBUS_SET_OOM (error); + goto out; + } + i = 0; + while ((status = xmlTextReaderMoveToNextAttribute (reader)) == 1) + { + _dbus_assert (i < n_attributes); + attribute_names[i] = xmlTextReaderConstName (reader); + attribute_values[i] = xmlTextReaderConstValue (reader); + if (attribute_names[i] == NULL || attribute_values[i] == NULL) + { + _DBUS_MAYBE_SET_OOM (error); + goto out; + } + i++; + } + if (status == -1) + { + _DBUS_MAYBE_SET_OOM (error); + goto out; + } + _dbus_assert (i == n_attributes); + + ret = bus_config_parser_start_element (parser, name, + attribute_names, attribute_values, + error); + if (ret && is_empty == 1) + ret = bus_config_parser_end_element (parser, name, error); + + out: + dbus_free (attribute_names); + dbus_free (attribute_values); + + return ret; +} + +static void xml_shut_up (void *ctx, const char *msg, ...) +{ + return; +} + +static void +xml_text_reader_error (void *arg, xmlErrorPtr xml_error) +{ + DBusError *error = arg; + +#if 0 + _dbus_verbose ("XML_ERROR level=%d, domain=%d, code=%d, msg=%s\n", + xml_error->level, xml_error->domain, + xml_error->code, xml_error->message); +#endif + + if (!dbus_error_is_set (error)) + { + if (xml_error->code == XML_ERR_NO_MEMORY) + _DBUS_SET_OOM (error); + else if (xml_error->level == XML_ERR_ERROR || + xml_error->level == XML_ERR_FATAL) + dbus_set_error (error, DBUS_ERROR_FAILED, + "Error loading config file: '%s'", + xml_error->message); + } +} + + +BusConfigParser* +bus_config_load (const DBusString *file, + dbus_bool_t is_toplevel, + const BusConfigParser *parent, + DBusError *error) + +{ + xmlTextReader *reader; + BusConfigParser *parser; + DBusString dirname, data; + DBusError tmp_error; + int ret; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + parser = NULL; + reader = NULL; + + if (!_dbus_string_init (&dirname)) + { + _DBUS_SET_OOM (error); + return NULL; + } + + if (!_dbus_string_init (&data)) + { + _DBUS_SET_OOM (error); + _dbus_string_free (&dirname); + return NULL; + } + + if (is_toplevel) + { + /* xmlMemSetup only fails if one of the functions is NULL */ + xmlMemSetup (dbus_free, + dbus_malloc, + dbus_realloc, + _dbus_strdup); + xmlInitParser (); + xmlSetGenericErrorFunc (NULL, xml_shut_up); + } + + if (!_dbus_string_get_dirname (file, &dirname)) + { + _DBUS_SET_OOM (error); + goto failed; + } + + parser = bus_config_parser_new (&dirname, is_toplevel, parent); + if (parser == NULL) + { + _DBUS_SET_OOM (error); + goto failed; + } + + if (!_dbus_file_get_contents (&data, file, error)) + goto failed; + + reader = xmlReaderForMemory (_dbus_string_get_const_data (&data), + _dbus_string_get_length (&data), + NULL, NULL, 0); + if (reader == NULL) + { + _DBUS_SET_OOM (error); + goto failed; + } + + xmlTextReaderSetParserProp (reader, XML_PARSER_SUBST_ENTITIES, 1); + + dbus_error_init (&tmp_error); + xmlTextReaderSetStructuredErrorHandler (reader, xml_text_reader_error, &tmp_error); + + while ((ret = xmlTextReaderRead (reader)) == 1) + { + int type; + + if (dbus_error_is_set (&tmp_error)) + goto reader_out; + + type = xmlTextReaderNodeType (reader); + if (type == -1) + { + _DBUS_MAYBE_SET_OOM (&tmp_error); + goto reader_out; + } + + switch ((xmlReaderTypes) type) { + case XML_READER_TYPE_ELEMENT: + xml_text_start_element (parser, reader, &tmp_error); + break; + + case XML_READER_TYPE_TEXT: + case XML_READER_TYPE_CDATA: + { + DBusString content; + const char *value; + value = xmlTextReaderConstValue (reader); + if (value != NULL) + { + _dbus_string_init_const (&content, value); + bus_config_parser_content (parser, &content, &tmp_error); + } + else + _DBUS_MAYBE_SET_OOM (&tmp_error); + break; + } + + case XML_READER_TYPE_DOCUMENT_TYPE: + { + const char *name; + name = xmlTextReaderConstName (reader); + if (name != NULL) + bus_config_parser_check_doctype (parser, name, &tmp_error); + else + _DBUS_MAYBE_SET_OOM (&tmp_error); + break; + } + + case XML_READER_TYPE_END_ELEMENT: + { + const char *name; + name = xmlTextReaderConstName (reader); + if (name != NULL) + bus_config_parser_end_element (parser, name, &tmp_error); + else + _DBUS_MAYBE_SET_OOM (&tmp_error); + break; + } + + case XML_READER_TYPE_DOCUMENT: + case XML_READER_TYPE_DOCUMENT_FRAGMENT: + case XML_READER_TYPE_PROCESSING_INSTRUCTION: + case XML_READER_TYPE_COMMENT: + case XML_READER_TYPE_ENTITY: + case XML_READER_TYPE_NOTATION: + case XML_READER_TYPE_WHITESPACE: + case XML_READER_TYPE_SIGNIFICANT_WHITESPACE: + case XML_READER_TYPE_END_ENTITY: + case XML_READER_TYPE_XML_DECLARATION: + /* nothing to do, just read on */ + break; + + case XML_READER_TYPE_NONE: + case XML_READER_TYPE_ATTRIBUTE: + case XML_READER_TYPE_ENTITY_REFERENCE: + _dbus_assert_not_reached ("unexpected nodes in XML"); + } + + if (dbus_error_is_set (&tmp_error)) + goto reader_out; + } + + if (ret == -1) + _DBUS_MAYBE_SET_OOM (&tmp_error); + + reader_out: + xmlFreeTextReader (reader); + reader = NULL; + if (dbus_error_is_set (&tmp_error)) + { + dbus_move_error (&tmp_error, error); + goto failed; + } + + if (!bus_config_parser_finished (parser, error)) + goto failed; + _dbus_string_free (&dirname); + _dbus_string_free (&data); + if (is_toplevel) + xmlCleanupParser(); + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return parser; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_string_free (&dirname); + _dbus_string_free (&data); + if (is_toplevel) + xmlCleanupParser(); + if (parser) + bus_config_parser_unref (parser); + _dbus_assert (reader == NULL); /* must go to reader_out first */ + return NULL; +} diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c new file mode 100644 index 00000000..54a67468 --- /dev/null +++ b/bus/config-parser-common.c @@ -0,0 +1,183 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* config-parser-common.c Common defines and routines for config file parsing + * + * Copyright (C) 2007 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include + +#include "config-parser-common.h" +#include "utils.h" + +ElementType +bus_config_parser_element_name_to_type (const char *name) +{ + if (strcmp (name, "none") == 0) + { + return ELEMENT_NONE; + } + else if (strcmp (name, "busconfig") == 0) + { + return ELEMENT_BUSCONFIG; + } + else if (strcmp (name, "user") == 0) + { + return ELEMENT_USER; + } + else if (strcmp (name, "auth") == 0) + { + return ELEMENT_AUTH; + } + else if (strcmp (name, "type") == 0) + { + return ELEMENT_TYPE; + } + else if (strcmp (name, "fork") == 0) + { + return ELEMENT_FORK; + } + else if (strcmp (name, "pidfile") == 0) + { + return ELEMENT_PIDFILE; + } + else if (strcmp (name, "listen") == 0) + { + return ELEMENT_LISTEN; + } + else if (strcmp (name, "auth") == 0) + { + return ELEMENT_AUTH; + } + else if (strcmp (name, "allow") == 0) + { + return ELEMENT_ALLOW; + } + else if (strcmp (name, "deny") == 0) + { + return ELEMENT_DENY; + } + else if (strcmp (name, "servicehelper") == 0) + { + return ELEMENT_SERVICEHELPER; + } + else if (strcmp (name, "includedir") == 0) + { + return ELEMENT_INCLUDEDIR; + } + else if (strcmp (name, "standard_session_servicedirs") == 0) + { + return ELEMENT_STANDARD_SESSION_SERVICEDIRS; + } + else if (strcmp (name, "standard_system_servicedirs") == 0) + { + return ELEMENT_STANDARD_SYSTEM_SERVICEDIRS; + } + else if (strcmp (name, "servicedir") == 0) + { + return ELEMENT_SERVICEDIR; + } + else if (strcmp (name, "include") == 0) + { + return ELEMENT_INCLUDE; + } + else if (strcmp (name, "policy") == 0) + { + return ELEMENT_POLICY; + } + else if (strcmp (name, "limit") == 0) + { + return ELEMENT_LIMIT; + } + else if (strcmp (name, "selinux") == 0) + { + return ELEMENT_SELINUX; + } + else if (strcmp (name, "associate") == 0) + { + return ELEMENT_ASSOCIATE; + } + else if (strcmp (name, "syslog") == 0) + { + return ELEMENT_SYSLOG; + } + else if (strcmp (name, "keep_umask") == 0) + { + return ELEMENT_KEEP_UMASK; + } + return ELEMENT_NONE; +} + +const char* +bus_config_parser_element_type_to_name (ElementType type) +{ + switch (type) + { + case ELEMENT_NONE: + return NULL; + case ELEMENT_BUSCONFIG: + return "busconfig"; + case ELEMENT_INCLUDE: + return "include"; + case ELEMENT_USER: + return "user"; + case ELEMENT_LISTEN: + return "listen"; + case ELEMENT_AUTH: + return "auth"; + case ELEMENT_POLICY: + return "policy"; + case ELEMENT_LIMIT: + return "limit"; + case ELEMENT_ALLOW: + return "allow"; + case ELEMENT_DENY: + return "deny"; + case ELEMENT_FORK: + return "fork"; + case ELEMENT_PIDFILE: + return "pidfile"; + case ELEMENT_STANDARD_SESSION_SERVICEDIRS: + return "standard_session_servicedirs"; + case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS: + return "standard_system_servicedirs"; + case ELEMENT_SERVICEDIR: + return "servicedir"; + case ELEMENT_SERVICEHELPER: + return "servicehelper"; + case ELEMENT_INCLUDEDIR: + return "includedir"; + case ELEMENT_TYPE: + return "type"; + case ELEMENT_SELINUX: + return "selinux"; + case ELEMENT_ASSOCIATE: + return "associate"; + case ELEMENT_SYSLOG: + return "syslog"; + case ELEMENT_KEEP_UMASK: + return "keep_umask"; + } + + _dbus_assert_not_reached ("bad element type"); + + return NULL; +} + diff --git a/bus/config-parser-common.h b/bus/config-parser-common.h new file mode 100644 index 00000000..8451ce08 --- /dev/null +++ b/bus/config-parser-common.h @@ -0,0 +1,59 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* config-parser-common.h Common defines and routines for config file parsing + * + * Copyright (C) 2007 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_CONFIG_PARSER_COMMON_H +#define BUS_CONFIG_PARSER_COMMON_H + +#include + +typedef enum +{ + ELEMENT_NONE, + ELEMENT_BUSCONFIG, + ELEMENT_INCLUDE, + ELEMENT_USER, + ELEMENT_LISTEN, + ELEMENT_AUTH, + ELEMENT_POLICY, + ELEMENT_LIMIT, + ELEMENT_ALLOW, + ELEMENT_DENY, + ELEMENT_FORK, + ELEMENT_PIDFILE, + ELEMENT_SERVICEDIR, + ELEMENT_SERVICEHELPER, + ELEMENT_INCLUDEDIR, + ELEMENT_TYPE, + ELEMENT_SELINUX, + ELEMENT_ASSOCIATE, + ELEMENT_STANDARD_SESSION_SERVICEDIRS, + ELEMENT_STANDARD_SYSTEM_SERVICEDIRS, + ELEMENT_SYSLOG, + ELEMENT_KEEP_UMASK +} ElementType; + +ElementType bus_config_parser_element_name_to_type (const char *element_name); +const char* bus_config_parser_element_type_to_name (ElementType type); + +#endif /* BUS_CONFIG_PARSER_COMMON_H */ + diff --git a/bus/config-parser-trivial.c b/bus/config-parser-trivial.c new file mode 100644 index 00000000..fd016a84 --- /dev/null +++ b/bus/config-parser-trivial.c @@ -0,0 +1,696 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* config-parser-trivial.c XML-library-agnostic configuration file parser + * Does not do includes or anything remotely complicated. + * + * Copyright (C) 2003, 2004, 2007 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config-parser-common.h" +#include "config-parser-trivial.h" +#include "utils.h" +#include +#include +#include + +/** + * TRIVIAL parser for bus configuration file. + */ +struct BusConfigParser +{ + ElementType type; + DBusString user; /**< User the dbus-daemon runs as */ + DBusString bus_type; /**< Message bus type */ + DBusString service_helper; /**< Location of the setuid helper */ + DBusList *service_dirs; /**< Directories to look for services in */ +}; + +static dbus_bool_t +service_dirs_find_dir (DBusList **service_dirs, + const char *dir) +{ + DBusList *link; + + _dbus_assert (dir != NULL); + + for (link = *service_dirs; link; link = _dbus_list_get_next_link(service_dirs, link)) + { + const char *link_dir; + + link_dir = (const char *)link->data; + if (strcmp (dir, link_dir) == 0) + return TRUE; + } + + return FALSE; +} + +static void +service_dirs_append_link_unique_or_free (DBusList **service_dirs, + DBusList *dir_link) +{ + if (!service_dirs_find_dir (service_dirs, dir_link->data)) + { + _dbus_list_append_link (service_dirs, dir_link); + } + else + { + dbus_free (dir_link->data); + _dbus_list_free_link (dir_link); + } +} + +BusConfigParser* +bus_config_parser_new (const DBusString *basedir, + dbus_bool_t is_toplevel, + const BusConfigParser *parent) +{ + BusConfigParser *parser; + + parser = dbus_new0 (BusConfigParser, 1); + if (parser == NULL) + goto failed; + + parser->type = ELEMENT_NONE; + + /* init the lists */ + parser->service_dirs = NULL; + + /* init the strings */ + if (!_dbus_string_init (&parser->user)) + goto failed_parser; + if (!_dbus_string_init (&parser->bus_type)) + goto failed_type; + if (!_dbus_string_init (&parser->service_helper)) + goto failed_helper; + + /* woot! */ + return parser; + +/* argh. we have do do this carefully because of OOM */ +failed_helper: + _dbus_string_free (&parser->bus_type); +failed_type: + _dbus_string_free (&parser->user); +failed_parser: + dbus_free (parser); +failed: + return NULL; +} + +void +bus_config_parser_unref (BusConfigParser *parser) +{ + _dbus_string_free (&parser->user); + _dbus_string_free (&parser->service_helper); + _dbus_string_free (&parser->bus_type); + + _dbus_list_foreach (&parser->service_dirs, + (DBusForeachFunction) dbus_free, + NULL); + + _dbus_list_clear (&parser->service_dirs); + + dbus_free (parser); +} + +dbus_bool_t +bus_config_parser_start_element (BusConfigParser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + DBusError *error) +{ + /* we don't do processing of attribute names, we don't need to */ + parser->type = bus_config_parser_element_name_to_type (element_name); + + switch (parser->type) + { + case ELEMENT_SERVICEHELPER: + case ELEMENT_USER: + case ELEMENT_TYPE: + /* content about to be handled */ + break; + + case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS: + { + DBusList *link; + DBusList *dirs; + dirs = NULL; + + if (!_dbus_get_standard_system_servicedirs (&dirs)) + { + BUS_SET_OOM (error); + return FALSE; + } + + while ((link = _dbus_list_pop_first_link (&dirs))) + service_dirs_append_link_unique_or_free (&parser->service_dirs, link); + break; + } + + default: + { + /* we really don't care about the others... */ + _dbus_verbose (" START We dont care about '%s' type '%i'\n", element_name, parser->type); + break; + } + } + return TRUE; +} + +dbus_bool_t +bus_config_parser_end_element (BusConfigParser *parser, + const char *element_name, + DBusError *error) +{ + /* we don't care */ + return TRUE; +} + +dbus_bool_t +bus_config_parser_content (BusConfigParser *parser, + const DBusString *content, + DBusError *error) +{ + DBusString content_sane; + dbus_bool_t retval; + + retval = FALSE; + + if (!_dbus_string_init (&content_sane)) + { + BUS_SET_OOM (error); + goto out; + } + if (!_dbus_string_copy (content, 0, &content_sane, 0)) + { + BUS_SET_OOM (error); + goto out_content; + } + + /* rip out white space */ + _dbus_string_chop_white (&content_sane); + if (_dbus_string_get_length (&content_sane) == 0) + { + /* optimise, there is no content */ + retval = TRUE; + goto out_content; + } + + switch (parser->type) + { + case ELEMENT_SERVICEDIR: + { + char *cpath; + + /* copy the sane data into a char array */ + if (!_dbus_string_copy_data(&content_sane, &cpath)) + { + BUS_SET_OOM (error); + goto out_content; + } + + /* append the dynamic char string to service dirs */ + if (!_dbus_list_append (&parser->service_dirs, cpath)) + { + dbus_free (cpath); + BUS_SET_OOM (error); + goto out_content; + } + } + break; + + case ELEMENT_SERVICEHELPER: + { + if (!_dbus_string_copy (&content_sane, 0, &parser->service_helper, 0)) + { + BUS_SET_OOM (error); + goto out_content; + } + } + break; + + case ELEMENT_USER: + { + if (!_dbus_string_copy (&content_sane, 0, &parser->user, 0)) + { + BUS_SET_OOM (error); + goto out_content; + } + } + break; + + case ELEMENT_TYPE: + { + if (!_dbus_string_copy (&content_sane, 0, &parser->bus_type, 0)) + { + BUS_SET_OOM (error); + goto out_content; + } + } + break; + default: + { + /* we don't care about the others... really */ + _dbus_verbose (" CONTENTS We dont care '%s' type '%i'\n", _dbus_string_get_const_data (&content_sane), parser->type); + break; + } + } + + /* woot! */ + retval = TRUE; + +out_content: + _dbus_string_free (&content_sane); +out: + return retval; +} + +dbus_bool_t +bus_config_parser_finished (BusConfigParser *parser, + DBusError *error) +{ + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + _dbus_verbose ("finished scanning!\n"); + return TRUE; +} + +const char* +bus_config_parser_get_user (BusConfigParser *parser) +{ + return _dbus_string_get_const_data (&parser->user); +} + +const char* +bus_config_parser_get_type (BusConfigParser *parser) +{ + return _dbus_string_get_const_data (&parser->bus_type); +} + +DBusList** +bus_config_parser_get_service_dirs (BusConfigParser *parser) +{ + return &parser->service_dirs; +} + +#ifdef DBUS_BUILD_TESTS +#include +#include "test.h" + +typedef enum +{ + VALID, + INVALID, + UNKNOWN +} Validity; + +static dbus_bool_t +check_return_values (const DBusString *full_path) +{ + BusConfigParser *parser; + DBusError error; + dbus_bool_t retval; + const char *user; + const char *type; + DBusList **dirs; + + dbus_error_init (&error); + retval = FALSE; + + printf ("Testing values from: %s\n", _dbus_string_get_const_data (full_path)); + + parser = bus_config_load (full_path, TRUE, NULL, &error); + if (parser == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (&error); + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + _dbus_verbose ("Failed to load valid file due to OOM\n"); + goto finish; + } + _DBUS_ASSERT_ERROR_IS_CLEAR (&error); + + /* check user return value is okay */ + user = bus_config_parser_get_user (parser); + if (user == NULL) + { + _dbus_warn ("User was NULL!\n"); + goto finish; + } +#if 0 + /* the username can be configured in configure.in so this test doesn't work */ + if (strcmp (user, "dbus") != 0) + { + _dbus_warn ("User was invalid; '%s'!\n", user); + goto finish; + } + printf (" dbus OKAY!\n"); +#endif + + /* check type return value is okay */ + type = bus_config_parser_get_type (parser); + if (type == NULL) + { + _dbus_warn ("Type was NULL!\n"); + goto finish; + } + if (strcmp (type, "system") != 0) + { + _dbus_warn ("Type was invalid; '%s'!\n", user); + goto finish; + } + printf (" system OKAY!\n"); + + /* check dirs return value is okay */ + dirs = bus_config_parser_get_service_dirs (parser); + if (dirs == NULL) + { + _dbus_warn ("Service dirs are NULL!\n"); + goto finish; + } + printf (" OKAY!\n"); + /* NOTE: We tested the specific return values in the config-parser tests */ + + /* woohoo! */ + retval = TRUE; +finish: + if (parser != NULL) + bus_config_parser_unref (parser); + dbus_error_free (&error); + return retval; +} + +static dbus_bool_t +do_load (const DBusString *full_path, + Validity validity, + dbus_bool_t oom_possible) +{ + BusConfigParser *parser; + DBusError error; + + dbus_error_init (&error); + + parser = bus_config_load (full_path, TRUE, NULL, &error); + if (parser == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (&error); + + if (oom_possible && + dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + _dbus_verbose ("Failed to load valid file due to OOM\n"); + dbus_error_free (&error); + return TRUE; + } + else if (validity == VALID) + { + _dbus_warn ("Failed to load valid file but still had memory: %s\n", + error.message); + + dbus_error_free (&error); + return FALSE; + } + else + { + dbus_error_free (&error); + return TRUE; + } + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (&error); + + bus_config_parser_unref (parser); + + if (validity == INVALID) + { + _dbus_warn ("Accepted invalid file\n"); + return FALSE; + } + + return TRUE; + } +} + +typedef struct +{ + const DBusString *full_path; + Validity validity; +} LoaderOomData; + +static dbus_bool_t +check_loader_oom_func (void *data) +{ + LoaderOomData *d = data; + + return do_load (d->full_path, d->validity, TRUE); +} + +static dbus_bool_t +process_test_valid_subdir (const DBusString *test_base_dir, + const char *subdir, + Validity validity) +{ + DBusString test_directory; + DBusString filename; + DBusDirIter *dir; + dbus_bool_t retval; + DBusError error; + + retval = FALSE; + dir = NULL; + + if (!_dbus_string_init (&test_directory)) + _dbus_assert_not_reached ("didn't allocate test_directory\n"); + + _dbus_string_init_const (&filename, subdir); + + if (!_dbus_string_copy (test_base_dir, 0, + &test_directory, 0)) + _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); + + if (!_dbus_concat_dir_and_file (&test_directory, &filename)) + _dbus_assert_not_reached ("couldn't allocate full path"); + + _dbus_string_free (&filename); + if (!_dbus_string_init (&filename)) + _dbus_assert_not_reached ("didn't allocate filename string\n"); + + dbus_error_init (&error); + dir = _dbus_directory_open (&test_directory, &error); + if (dir == NULL) + { + _dbus_warn ("Could not open %s: %s\n", + _dbus_string_get_const_data (&test_directory), + error.message); + dbus_error_free (&error); + goto failed; + } + + if (validity == VALID) + printf ("Testing valid files:\n"); + else if (validity == INVALID) + printf ("Testing invalid files:\n"); + else + printf ("Testing unknown files:\n"); + + next: + while (_dbus_directory_get_next_file (dir, &filename, &error)) + { + DBusString full_path; + LoaderOomData d; + + if (!_dbus_string_init (&full_path)) + _dbus_assert_not_reached ("couldn't init string"); + + if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) + _dbus_assert_not_reached ("couldn't copy dir to full_path"); + + if (!_dbus_concat_dir_and_file (&full_path, &filename)) + _dbus_assert_not_reached ("couldn't concat file to dir"); + + if (!_dbus_string_ends_with_c_str (&full_path, ".conf")) + { + _dbus_verbose ("Skipping non-.conf file %s\n", + _dbus_string_get_const_data (&filename)); + _dbus_string_free (&full_path); + goto next; + } + + printf (" %s\n", _dbus_string_get_const_data (&filename)); + + _dbus_verbose (" expecting %s\n", + validity == VALID ? "valid" : + (validity == INVALID ? "invalid" : + (validity == UNKNOWN ? "unknown" : "???"))); + + d.full_path = &full_path; + d.validity = validity; + + /* FIXME hackaround for an expat problem, see + * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=124747 + * http://freedesktop.org/pipermail/dbus/2004-May/001153.html + */ + /* if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d)) */ + if (!check_loader_oom_func (&d)) + _dbus_assert_not_reached ("test failed"); + + _dbus_string_free (&full_path); + } + + if (dbus_error_is_set (&error)) + { + _dbus_warn ("Could not get next file in %s: %s\n", + _dbus_string_get_const_data (&test_directory), + error.message); + dbus_error_free (&error); + goto failed; + } + + retval = TRUE; + + failed: + + if (dir) + _dbus_directory_close (dir); + _dbus_string_free (&test_directory); + _dbus_string_free (&filename); + + return retval; +} + +/* convenience function, do not reuse outside of TEST */ +static dbus_bool_t +make_full_path (const DBusString *test_data_dir, + const char *subdir, + const char *file, + DBusString *full_path) +{ + DBusString filename; + dbus_bool_t retval; + + retval = FALSE; + + if (!_dbus_string_init (full_path)) + { + _dbus_warn ("couldn't allocate full path"); + goto finish; + } + + if (!_dbus_string_copy (test_data_dir, 0, full_path, 0)) + { + _dbus_warn ("couldn't allocate full path"); + goto finish; + } + + _dbus_string_init_const (&filename, subdir); + if (!_dbus_concat_dir_and_file (full_path, &filename)) + { + _dbus_warn ("couldn't allocate full path"); + goto finish; + } + _dbus_string_free (&filename); + + _dbus_string_init_const (&filename, file); + if (!_dbus_concat_dir_and_file (full_path, &filename)) + { + _dbus_warn ("couldn't allocate full path"); + goto finish; + } + + /* woot! */ + retval = TRUE; + +finish: + _dbus_string_free (&filename); + return retval; +} + +static dbus_bool_t +check_file_valid (DBusString *full_path, + Validity validity) +{ + dbus_bool_t retval; + + if (validity == VALID) + printf ("Testing valid file:\n"); + else if (validity == INVALID) + printf ("Testing invalid file:\n"); + else + printf ("Testing unknown file:\n"); + + /* print the filename, just so we match the other output */ + printf (" %s\n", _dbus_string_get_const_data (full_path)); + + /* only test one file */ + retval = do_load (full_path, validity, TRUE); + + return retval; +} + +dbus_bool_t +bus_config_parser_trivial_test (const DBusString *test_data_dir) +{ + DBusString full_path; + dbus_bool_t retval; + + retval = FALSE; + + if (test_data_dir == NULL || + _dbus_string_get_length (test_data_dir) == 0) + { + printf ("No test data\n"); + return TRUE; + } + + /* We already test default_session_servicedirs and default_system_servicedirs + * in bus_config_parser_test() */ + if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID)) + goto finish; + + /* we don't process all the invalid files, as the trivial parser can't hope + * to validate them all for all different syntaxes. We just check one broken + * file to see if junk is received */ + if (!make_full_path (test_data_dir, "invalid-config-files", "not-well-formed.conf", &full_path)) + goto finish; + if (!check_file_valid (&full_path, INVALID)) + goto finish; + _dbus_string_free (&full_path); + + /* just test if the check_file_valid works okay and we got sane values */ + if (!make_full_path (test_data_dir, "valid-config-files", "system.conf", &full_path)) + goto finish; + if (!check_file_valid (&full_path, VALID)) + goto finish; + /* check to see if we got the correct values from the parser */ + if (!check_return_values (&full_path)) + goto finish; + + /* woot! */ + retval = TRUE; + +finish: + _dbus_string_free (&full_path); + + /* we don't process equiv-config-files as we don't handle */ + return retval; +} + +#endif /* DBUS_BUILD_TESTS */ + diff --git a/bus/config-parser-trivial.h b/bus/config-parser-trivial.h new file mode 100644 index 00000000..ce542bfb --- /dev/null +++ b/bus/config-parser-trivial.h @@ -0,0 +1,71 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* config-parser-trivial.h XML-library-agnostic configuration file parser + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_CONFIG_PARSER_TRIVIAL_H +#define BUS_CONFIG_PARSER_TRIVIAL_H + +#include + +#include +#include +#include +#include + +/* Whatever XML library we're using just pushes data into this API */ + +typedef struct BusConfigParser BusConfigParser; + +BusConfigParser* bus_config_parser_new (const DBusString *basedir, + dbus_bool_t is_toplevel, + const BusConfigParser *parent); + +BusConfigParser* bus_config_parser_ref (BusConfigParser *parser); +void bus_config_parser_unref (BusConfigParser *parser); +dbus_bool_t bus_config_parser_start_element (BusConfigParser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + DBusError *error); +dbus_bool_t bus_config_parser_end_element (BusConfigParser *parser, + const char *element_name, + DBusError *error); +dbus_bool_t bus_config_parser_content (BusConfigParser *parser, + const DBusString *content, + DBusError *error); +dbus_bool_t bus_config_parser_finished (BusConfigParser *parser, + DBusError *error); + +/* Functions for extracting the parse results */ +const char* bus_config_parser_get_user (BusConfigParser *parser); +const char* bus_config_parser_get_type (BusConfigParser *parser); +DBusList** bus_config_parser_get_service_dirs (BusConfigParser *parser); + +/* Loader functions (backended off one of the XML parsers). Returns a + * finished ConfigParser. + */ +BusConfigParser* bus_config_load (const DBusString *file, + dbus_bool_t is_toplevel, + const BusConfigParser *parent, + DBusError *error); + +#endif /* BUS_CONFIG_PARSER_TRIVIAL_H */ diff --git a/bus/config-parser.c b/bus/config-parser.c new file mode 100644 index 00000000..5218910b --- /dev/null +++ b/bus/config-parser.c @@ -0,0 +1,3466 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* config-parser.c XML-library-agnostic configuration file parser + * + * Copyright (C) 2003, 2004 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "config-parser-common.h" +#include "config-parser.h" +#include "test.h" +#include "utils.h" +#include "policy.h" +#include "selinux.h" +#include +#include +#include + +typedef enum +{ + /* we ignore policies for unknown groups/users */ + POLICY_IGNORED, + + /* non-ignored */ + POLICY_DEFAULT, + POLICY_MANDATORY, + POLICY_USER, + POLICY_GROUP, + POLICY_CONSOLE +} PolicyType; + +typedef struct +{ + ElementType type; + + unsigned int had_content : 1; + + union + { + struct + { + unsigned int ignore_missing : 1; + unsigned int if_selinux_enabled : 1; + unsigned int selinux_root_relative : 1; + } include; + + struct + { + PolicyType type; + unsigned long gid_uid_or_at_console; + } policy; + + struct + { + char *name; + long value; + } limit; + + } d; + +} Element; + +/** + * Parser for bus configuration file. + */ +struct BusConfigParser +{ + int refcount; /**< Reference count */ + + DBusString basedir; /**< Directory we resolve paths relative to */ + + DBusList *stack; /**< stack of Element */ + + char *user; /**< user to run as */ + + char *servicehelper; /**< location of the setuid helper */ + + char *bus_type; /**< Message bus type */ + + DBusList *listen_on; /**< List of addresses to listen to */ + + DBusList *mechanisms; /**< Auth mechanisms */ + + DBusList *service_dirs; /**< Directories to look for session services in */ + + DBusList *conf_dirs; /**< Directories to look for policy configuration in */ + + BusPolicy *policy; /**< Security policy */ + + BusLimits limits; /**< Limits */ + + char *pidfile; /**< PID file */ + + DBusList *included_files; /**< Included files stack */ + + DBusHashTable *service_context_table; /**< Map service names to SELinux contexts */ + + unsigned int fork : 1; /**< TRUE to fork into daemon mode */ + + unsigned int syslog : 1; /**< TRUE to enable syslog */ + unsigned int keep_umask : 1; /**< TRUE to keep original umask when forking */ + + unsigned int is_toplevel : 1; /**< FALSE if we are a sub-config-file inside another one */ +}; + +static Element* +push_element (BusConfigParser *parser, + ElementType type) +{ + Element *e; + + _dbus_assert (type != ELEMENT_NONE); + + e = dbus_new0 (Element, 1); + if (e == NULL) + return NULL; + + if (!_dbus_list_append (&parser->stack, e)) + { + dbus_free (e); + return NULL; + } + + e->type = type; + + return e; +} + +static void +element_free (Element *e) +{ + if (e->type == ELEMENT_LIMIT) + dbus_free (e->d.limit.name); + + dbus_free (e); +} + +static void +pop_element (BusConfigParser *parser) +{ + Element *e; + + e = _dbus_list_pop_last (&parser->stack); + + element_free (e); +} + +static Element* +peek_element (BusConfigParser *parser) +{ + Element *e; + + e = _dbus_list_get_last (&parser->stack); + + return e; +} + +static ElementType +top_element_type (BusConfigParser *parser) +{ + Element *e; + + e = _dbus_list_get_last (&parser->stack); + + if (e) + return e->type; + else + return ELEMENT_NONE; +} + +static dbus_bool_t +merge_service_context_hash (DBusHashTable *dest, + DBusHashTable *from) +{ + DBusHashIter iter; + char *service_copy; + char *context_copy; + + service_copy = NULL; + context_copy = NULL; + + _dbus_hash_iter_init (from, &iter); + while (_dbus_hash_iter_next (&iter)) + { + const char *service = _dbus_hash_iter_get_string_key (&iter); + const char *context = _dbus_hash_iter_get_value (&iter); + + service_copy = _dbus_strdup (service); + if (service_copy == NULL) + goto fail; + context_copy = _dbus_strdup (context); + if (context_copy == NULL) + goto fail; + + if (!_dbus_hash_table_insert_string (dest, service_copy, context_copy)) + goto fail; + + service_copy = NULL; + context_copy = NULL; + } + + return TRUE; + + fail: + if (service_copy) + dbus_free (service_copy); + + if (context_copy) + dbus_free (context_copy); + + return FALSE; +} + +static dbus_bool_t +service_dirs_find_dir (DBusList **service_dirs, + const char *dir) +{ + DBusList *link; + + _dbus_assert (dir != NULL); + + for (link = *service_dirs; link; link = _dbus_list_get_next_link(service_dirs, link)) + { + const char *link_dir; + + link_dir = (const char *)link->data; + if (strcmp (dir, link_dir) == 0) + return TRUE; + } + + return FALSE; +} + +static dbus_bool_t +service_dirs_append_unique_or_free (DBusList **service_dirs, + char *dir) +{ + if (!service_dirs_find_dir (service_dirs, dir)) + return _dbus_list_append (service_dirs, dir); + + dbus_free (dir); + return TRUE; +} + +static void +service_dirs_append_link_unique_or_free (DBusList **service_dirs, + DBusList *dir_link) +{ + if (!service_dirs_find_dir (service_dirs, dir_link->data)) + { + _dbus_list_append_link (service_dirs, dir_link); + } + else + { + dbus_free (dir_link->data); + _dbus_list_free_link (dir_link); + } +} + +static dbus_bool_t +merge_included (BusConfigParser *parser, + BusConfigParser *included, + DBusError *error) +{ + DBusList *link; + + if (!bus_policy_merge (parser->policy, + included->policy)) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!merge_service_context_hash (parser->service_context_table, + included->service_context_table)) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (included->user != NULL) + { + dbus_free (parser->user); + parser->user = included->user; + included->user = NULL; + } + + if (included->bus_type != NULL) + { + dbus_free (parser->bus_type); + parser->bus_type = included->bus_type; + included->bus_type = NULL; + } + + if (included->fork) + parser->fork = TRUE; + + if (included->keep_umask) + parser->keep_umask = TRUE; + + if (included->pidfile != NULL) + { + dbus_free (parser->pidfile); + parser->pidfile = included->pidfile; + included->pidfile = NULL; + } + + while ((link = _dbus_list_pop_first_link (&included->listen_on))) + _dbus_list_append_link (&parser->listen_on, link); + + while ((link = _dbus_list_pop_first_link (&included->mechanisms))) + _dbus_list_append_link (&parser->mechanisms, link); + + while ((link = _dbus_list_pop_first_link (&included->service_dirs))) + service_dirs_append_link_unique_or_free (&parser->service_dirs, link); + + while ((link = _dbus_list_pop_first_link (&included->conf_dirs))) + _dbus_list_append_link (&parser->conf_dirs, link); + + return TRUE; +} + +static dbus_bool_t +seen_include (BusConfigParser *parser, + const DBusString *file) +{ + DBusList *iter; + + iter = parser->included_files; + while (iter != NULL) + { + if (! strcmp (_dbus_string_get_const_data (file), iter->data)) + return TRUE; + + iter = _dbus_list_get_next_link (&parser->included_files, iter); + } + + return FALSE; +} + +BusConfigParser* +bus_config_parser_new (const DBusString *basedir, + dbus_bool_t is_toplevel, + const BusConfigParser *parent) +{ + BusConfigParser *parser; + + parser = dbus_new0 (BusConfigParser, 1); + if (parser == NULL) + return NULL; + + parser->is_toplevel = !!is_toplevel; + + if (!_dbus_string_init (&parser->basedir)) + { + dbus_free (parser); + return NULL; + } + + if (((parser->policy = bus_policy_new ()) == NULL) || + !_dbus_string_copy (basedir, 0, &parser->basedir, 0) || + ((parser->service_context_table = _dbus_hash_table_new (DBUS_HASH_STRING, + dbus_free, + dbus_free)) == NULL)) + { + if (parser->policy) + bus_policy_unref (parser->policy); + + _dbus_string_free (&parser->basedir); + + dbus_free (parser); + return NULL; + } + + if (parent != NULL) + { + /* Initialize the parser's limits from the parent. */ + parser->limits = parent->limits; + + /* Use the parent's list of included_files to avoid + circular inclusions. */ + parser->included_files = parent->included_files; + } + else + { + + /* Make up some numbers! woot! */ + parser->limits.max_incoming_bytes = _DBUS_ONE_MEGABYTE * 127; + parser->limits.max_outgoing_bytes = _DBUS_ONE_MEGABYTE * 127; + parser->limits.max_message_size = _DBUS_ONE_MEGABYTE * 32; + + /* Making this long means the user has to wait longer for an error + * message if something screws up, but making it too short means + * they might see a false failure. + */ + parser->limits.activation_timeout = 25000; /* 25 seconds */ + + /* Making this long risks making a DOS attack easier, but too short + * and legitimate auth will fail. If interactive auth (ask user for + * password) is allowed, then potentially it has to be quite long. + */ + parser->limits.auth_timeout = 30000; /* 30 seconds */ + + parser->limits.max_incomplete_connections = 64; + parser->limits.max_connections_per_user = 256; + + /* Note that max_completed_connections / max_connections_per_user + * is the number of users that would have to work together to + * DOS all the other users. + */ + parser->limits.max_completed_connections = 2048; + + parser->limits.max_pending_activations = 512; + parser->limits.max_services_per_connection = 512; + + /* For this one, keep in mind that it isn't only the memory used + * by the match rules, but slowdown from linearly walking a big + * list of them. A client adding more than this is almost + * certainly a bad idea for that reason, and should change to a + * smaller number of wider-net match rules - getting every last + * message to the bus is probably better than having a thousand + * match rules. + */ + parser->limits.max_match_rules_per_connection = 512; + + parser->limits.reply_timeout = -1; /* never */ + + /* this is effectively a limit on message queue size for messages + * that require a reply + */ + parser->limits.max_replies_per_connection = 1024*8; + } + + parser->refcount = 1; + + return parser; +} + +BusConfigParser * +bus_config_parser_ref (BusConfigParser *parser) +{ + _dbus_assert (parser->refcount > 0); + + parser->refcount += 1; + + return parser; +} + +void +bus_config_parser_unref (BusConfigParser *parser) +{ + _dbus_assert (parser->refcount > 0); + + parser->refcount -= 1; + + if (parser->refcount == 0) + { + while (parser->stack != NULL) + pop_element (parser); + + dbus_free (parser->user); + dbus_free (parser->servicehelper); + dbus_free (parser->bus_type); + dbus_free (parser->pidfile); + + _dbus_list_foreach (&parser->listen_on, + (DBusForeachFunction) dbus_free, + NULL); + + _dbus_list_clear (&parser->listen_on); + + _dbus_list_foreach (&parser->service_dirs, + (DBusForeachFunction) dbus_free, + NULL); + + _dbus_list_clear (&parser->service_dirs); + + _dbus_list_foreach (&parser->conf_dirs, + (DBusForeachFunction) dbus_free, + NULL); + + _dbus_list_clear (&parser->conf_dirs); + + _dbus_list_foreach (&parser->mechanisms, + (DBusForeachFunction) dbus_free, + NULL); + + _dbus_list_clear (&parser->mechanisms); + + _dbus_string_free (&parser->basedir); + + if (parser->policy) + bus_policy_unref (parser->policy); + + if (parser->service_context_table) + _dbus_hash_table_unref (parser->service_context_table); + + dbus_free (parser); + } +} + +dbus_bool_t +bus_config_parser_check_doctype (BusConfigParser *parser, + const char *doctype, + DBusError *error) +{ + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (strcmp (doctype, "busconfig") != 0) + { + dbus_set_error (error, + DBUS_ERROR_FAILED, + "Configuration file has the wrong document type %s", + doctype); + return FALSE; + } + else + return TRUE; +} + +typedef struct +{ + const char *name; + const char **retloc; +} LocateAttr; + +static dbus_bool_t +locate_attributes (BusConfigParser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + DBusError *error, + const char *first_attribute_name, + const char **first_attribute_retloc, + ...) +{ + va_list args; + const char *name; + const char **retloc; + int n_attrs; +#define MAX_ATTRS 24 + LocateAttr attrs[MAX_ATTRS]; + dbus_bool_t retval; + int i; + + _dbus_assert (first_attribute_name != NULL); + _dbus_assert (first_attribute_retloc != NULL); + + retval = TRUE; + + n_attrs = 1; + attrs[0].name = first_attribute_name; + attrs[0].retloc = first_attribute_retloc; + *first_attribute_retloc = NULL; + + va_start (args, first_attribute_retloc); + + name = va_arg (args, const char*); + retloc = va_arg (args, const char**); + + while (name != NULL) + { + _dbus_assert (retloc != NULL); + _dbus_assert (n_attrs < MAX_ATTRS); + + attrs[n_attrs].name = name; + attrs[n_attrs].retloc = retloc; + n_attrs += 1; + *retloc = NULL; + + name = va_arg (args, const char*); + retloc = va_arg (args, const char**); + } + + va_end (args); + + i = 0; + while (attribute_names[i]) + { + int j; + dbus_bool_t found; + + found = FALSE; + j = 0; + while (j < n_attrs) + { + if (strcmp (attrs[j].name, attribute_names[i]) == 0) + { + retloc = attrs[j].retloc; + + if (*retloc != NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Attribute \"%s\" repeated twice on the same <%s> element", + attrs[j].name, element_name); + retval = FALSE; + goto out; + } + + *retloc = attribute_values[i]; + found = TRUE; + } + + ++j; + } + + if (!found) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Attribute \"%s\" is invalid on <%s> element in this context", + attribute_names[i], element_name); + retval = FALSE; + goto out; + } + + ++i; + } + + out: + return retval; +} + +static dbus_bool_t +check_no_attributes (BusConfigParser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + DBusError *error) +{ + if (attribute_names[0] != NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Attribute \"%s\" is invalid on <%s> element in this context", + attribute_names[0], element_name); + return FALSE; + } + + return TRUE; +} + +static dbus_bool_t +start_busconfig_child (BusConfigParser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + DBusError *error) +{ + ElementType element_type; + + element_type = bus_config_parser_element_name_to_type (element_name); + + if (element_type == ELEMENT_USER) + { + if (!check_no_attributes (parser, "user", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_USER) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else if (element_type == ELEMENT_TYPE) + { + if (!check_no_attributes (parser, "type", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_TYPE) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else if (element_type == ELEMENT_FORK) + { + if (!check_no_attributes (parser, "fork", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_FORK) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + parser->fork = TRUE; + + return TRUE; + } + else if (element_type == ELEMENT_SYSLOG) + { + if (!check_no_attributes (parser, "syslog", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_SYSLOG) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + parser->syslog = TRUE; + + return TRUE; + } + else if (element_type == ELEMENT_KEEP_UMASK) + { + if (!check_no_attributes (parser, "keep_umask", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_KEEP_UMASK) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + parser->keep_umask = TRUE; + + return TRUE; + } + else if (element_type == ELEMENT_PIDFILE) + { + if (!check_no_attributes (parser, "pidfile", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_PIDFILE) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else if (element_type == ELEMENT_LISTEN) + { + if (!check_no_attributes (parser, "listen", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_LISTEN) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else if (element_type == ELEMENT_AUTH) + { + if (!check_no_attributes (parser, "auth", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_AUTH) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else if (element_type == ELEMENT_SERVICEHELPER) + { + if (!check_no_attributes (parser, "servicehelper", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_SERVICEHELPER) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else if (element_type == ELEMENT_INCLUDEDIR) + { + if (!check_no_attributes (parser, "includedir", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_INCLUDEDIR) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else if (element_type == ELEMENT_STANDARD_SESSION_SERVICEDIRS) + { + DBusList *link; + DBusList *dirs; + dirs = NULL; + + if (!check_no_attributes (parser, "standard_session_servicedirs", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_STANDARD_SESSION_SERVICEDIRS) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_get_standard_session_servicedirs (&dirs)) + { + BUS_SET_OOM (error); + return FALSE; + } + + while ((link = _dbus_list_pop_first_link (&dirs))) + service_dirs_append_link_unique_or_free (&parser->service_dirs, link); + + return TRUE; + } + else if (element_type == ELEMENT_STANDARD_SYSTEM_SERVICEDIRS) + { + DBusList *link; + DBusList *dirs; + dirs = NULL; + + if (!check_no_attributes (parser, "standard_system_servicedirs", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_STANDARD_SYSTEM_SERVICEDIRS) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_get_standard_system_servicedirs (&dirs)) + { + BUS_SET_OOM (error); + return FALSE; + } + + while ((link = _dbus_list_pop_first_link (&dirs))) + service_dirs_append_link_unique_or_free (&parser->service_dirs, link); + + return TRUE; + } + else if (element_type == ELEMENT_SERVICEDIR) + { + if (!check_no_attributes (parser, "servicedir", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_SERVICEDIR) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else if (element_type == ELEMENT_INCLUDE) + { + Element *e; + const char *if_selinux_enabled; + const char *ignore_missing; + const char *selinux_root_relative; + + if ((e = push_element (parser, ELEMENT_INCLUDE)) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + e->d.include.ignore_missing = FALSE; + e->d.include.if_selinux_enabled = FALSE; + e->d.include.selinux_root_relative = FALSE; + + if (!locate_attributes (parser, "include", + attribute_names, + attribute_values, + error, + "ignore_missing", &ignore_missing, + "if_selinux_enabled", &if_selinux_enabled, + "selinux_root_relative", &selinux_root_relative, + NULL)) + return FALSE; + + if (ignore_missing != NULL) + { + if (strcmp (ignore_missing, "yes") == 0) + e->d.include.ignore_missing = TRUE; + else if (strcmp (ignore_missing, "no") == 0) + e->d.include.ignore_missing = FALSE; + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "ignore_missing attribute must have value \"yes\" or \"no\""); + return FALSE; + } + } + + if (if_selinux_enabled != NULL) + { + if (strcmp (if_selinux_enabled, "yes") == 0) + e->d.include.if_selinux_enabled = TRUE; + else if (strcmp (if_selinux_enabled, "no") == 0) + e->d.include.if_selinux_enabled = FALSE; + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "if_selinux_enabled attribute must have value" + " \"yes\" or \"no\""); + return FALSE; + } + } + + if (selinux_root_relative != NULL) + { + if (strcmp (selinux_root_relative, "yes") == 0) + e->d.include.selinux_root_relative = TRUE; + else if (strcmp (selinux_root_relative, "no") == 0) + e->d.include.selinux_root_relative = FALSE; + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "selinux_root_relative attribute must have value" + " \"yes\" or \"no\""); + return FALSE; + } + } + + return TRUE; + } + else if (element_type == ELEMENT_POLICY) + { + Element *e; + const char *context; + const char *user; + const char *group; + const char *at_console; + + if ((e = push_element (parser, ELEMENT_POLICY)) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + e->d.policy.type = POLICY_IGNORED; + + if (!locate_attributes (parser, "policy", + attribute_names, + attribute_values, + error, + "context", &context, + "user", &user, + "group", &group, + "at_console", &at_console, + NULL)) + return FALSE; + + if (((context && user) || + (context && group) || + (context && at_console)) || + ((user && group) || + (user && at_console)) || + (group && at_console) || + !(context || user || group || at_console)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + " element must have exactly one of (context|user|group|at_console) attributes"); + return FALSE; + } + + if (context != NULL) + { + if (strcmp (context, "default") == 0) + { + e->d.policy.type = POLICY_DEFAULT; + } + else if (strcmp (context, "mandatory") == 0) + { + e->d.policy.type = POLICY_MANDATORY; + } + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "context attribute on must have the value \"default\" or \"mandatory\", not \"%s\"", + context); + return FALSE; + } + } + else if (user != NULL) + { + DBusString username; + _dbus_string_init_const (&username, user); + + if (_dbus_parse_unix_user_from_config (&username, + &e->d.policy.gid_uid_or_at_console)) + e->d.policy.type = POLICY_USER; + else + _dbus_warn ("Unknown username \"%s\" in message bus configuration file\n", + user); + } + else if (group != NULL) + { + DBusString group_name; + _dbus_string_init_const (&group_name, group); + + if (_dbus_parse_unix_group_from_config (&group_name, + &e->d.policy.gid_uid_or_at_console)) + e->d.policy.type = POLICY_GROUP; + else + _dbus_warn ("Unknown group \"%s\" in message bus configuration file\n", + group); + } + else if (at_console != NULL) + { + dbus_bool_t t; + t = (strcmp (at_console, "true") == 0); + if (t || strcmp (at_console, "false") == 0) + { + e->d.policy.gid_uid_or_at_console = t; + e->d.policy.type = POLICY_CONSOLE; + } + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Unknown value \"%s\" for at_console in message bus configuration file", + at_console); + + return FALSE; + } + } + else + { + _dbus_assert_not_reached ("all attributes null and we didn't set error"); + } + + return TRUE; + } + else if (element_type == ELEMENT_LIMIT) + { + Element *e; + const char *name; + + if ((e = push_element (parser, ELEMENT_LIMIT)) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!locate_attributes (parser, "limit", + attribute_names, + attribute_values, + error, + "name", &name, + NULL)) + return FALSE; + + if (name == NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + " element must have a \"name\" attribute"); + return FALSE; + } + + e->d.limit.name = _dbus_strdup (name); + if (e->d.limit.name == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else if (element_type == ELEMENT_SELINUX) + { + if (!check_no_attributes (parser, "selinux", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_SELINUX) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Element <%s> not allowed inside <%s> in configuration file", + element_name, "busconfig"); + return FALSE; + } +} + +static dbus_bool_t +append_rule_from_element (BusConfigParser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + dbus_bool_t allow, + DBusError *error) +{ + const char *log; + const char *send_interface; + const char *send_member; + const char *send_error; + const char *send_destination; + const char *send_path; + const char *send_type; + const char *receive_interface; + const char *receive_member; + const char *receive_error; + const char *receive_sender; + const char *receive_path; + const char *receive_type; + const char *eavesdrop; + const char *send_requested_reply; + const char *receive_requested_reply; + const char *own; + const char *user; + const char *group; + + BusPolicyRule *rule; + + if (!locate_attributes (parser, element_name, + attribute_names, + attribute_values, + error, + "send_interface", &send_interface, + "send_member", &send_member, + "send_error", &send_error, + "send_destination", &send_destination, + "send_path", &send_path, + "send_type", &send_type, + "receive_interface", &receive_interface, + "receive_member", &receive_member, + "receive_error", &receive_error, + "receive_sender", &receive_sender, + "receive_path", &receive_path, + "receive_type", &receive_type, + "eavesdrop", &eavesdrop, + "send_requested_reply", &send_requested_reply, + "receive_requested_reply", &receive_requested_reply, + "own", &own, + "user", &user, + "group", &group, + "log", &log, + NULL)) + return FALSE; + + if (!(send_interface || send_member || send_error || send_destination || + send_type || send_path || + receive_interface || receive_member || receive_error || receive_sender || + receive_type || receive_path || eavesdrop || + send_requested_reply || receive_requested_reply || + own || user || group)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Element <%s> must have one or more attributes", + element_name); + return FALSE; + } + + if ((send_member && (send_interface == NULL && send_path == NULL)) || + (receive_member && (receive_interface == NULL && receive_path == NULL))) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "On element <%s>, if you specify a member you must specify an interface or a path. Keep in mind that not all messages have an interface field.", + element_name); + return FALSE; + } + + /* Allowed combinations of elements are: + * + * base, must be all send or all receive: + * nothing + * interface + * interface + member + * error + * + * base send_ can combine with send_destination, send_path, send_type, send_requested_reply + * base receive_ with receive_sender, receive_path, receive_type, receive_requested_reply, eavesdrop + * + * user, group, own must occur alone + * + * Pretty sure the below stuff is broken, FIXME think about it more. + */ + + if (((send_interface && send_error) || + (send_interface && receive_interface) || + (send_interface && receive_member) || + (send_interface && receive_error) || + (send_interface && receive_sender) || + (send_interface && receive_requested_reply) || + (send_interface && own) || + (send_interface && user) || + (send_interface && group)) || + + ((send_member && send_error) || + (send_member && receive_interface) || + (send_member && receive_member) || + (send_member && receive_error) || + (send_member && receive_sender) || + (send_member && receive_requested_reply) || + (send_member && own) || + (send_member && user) || + (send_member && group)) || + + ((send_error && receive_interface) || + (send_error && receive_member) || + (send_error && receive_error) || + (send_error && receive_sender) || + (send_error && receive_requested_reply) || + (send_error && own) || + (send_error && user) || + (send_error && group)) || + + ((send_destination && receive_interface) || + (send_destination && receive_member) || + (send_destination && receive_error) || + (send_destination && receive_sender) || + (send_destination && receive_requested_reply) || + (send_destination && own) || + (send_destination && user) || + (send_destination && group)) || + + ((send_type && receive_interface) || + (send_type && receive_member) || + (send_type && receive_error) || + (send_type && receive_sender) || + (send_type && receive_requested_reply) || + (send_type && own) || + (send_type && user) || + (send_type && group)) || + + ((send_path && receive_interface) || + (send_path && receive_member) || + (send_path && receive_error) || + (send_path && receive_sender) || + (send_path && receive_requested_reply) || + (send_path && own) || + (send_path && user) || + (send_path && group)) || + + ((send_requested_reply && receive_interface) || + (send_requested_reply && receive_member) || + (send_requested_reply && receive_error) || + (send_requested_reply && receive_sender) || + (send_requested_reply && receive_requested_reply) || + (send_requested_reply && own) || + (send_requested_reply && user) || + (send_requested_reply && group)) || + + ((receive_interface && receive_error) || + (receive_interface && own) || + (receive_interface && user) || + (receive_interface && group)) || + + ((receive_member && receive_error) || + (receive_member && own) || + (receive_member && user) || + (receive_member && group)) || + + ((receive_error && own) || + (receive_error && user) || + (receive_error && group)) || + + ((eavesdrop && own) || + (eavesdrop && user) || + (eavesdrop && group)) || + + ((receive_requested_reply && own) || + (receive_requested_reply && user) || + (receive_requested_reply && group)) || + + ((own && user) || + (own && group)) || + + ((user && group))) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Invalid combination of attributes on element <%s>", + element_name); + return FALSE; + } + + rule = NULL; + + /* In BusPolicyRule, NULL represents wildcard. + * In the config file, '*' represents it. + */ +#define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0') + + if (send_interface || send_member || send_error || send_destination || + send_path || send_type || send_requested_reply) + { + int message_type; + + if (IS_WILDCARD (send_interface)) + send_interface = NULL; + if (IS_WILDCARD (send_member)) + send_member = NULL; + if (IS_WILDCARD (send_error)) + send_error = NULL; + if (IS_WILDCARD (send_destination)) + send_destination = NULL; + if (IS_WILDCARD (send_path)) + send_path = NULL; + if (IS_WILDCARD (send_type)) + send_type = NULL; + + message_type = DBUS_MESSAGE_TYPE_INVALID; + if (send_type != NULL) + { + message_type = dbus_message_type_from_string (send_type); + if (message_type == DBUS_MESSAGE_TYPE_INVALID) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad message type \"%s\"", + send_type); + return FALSE; + } + } + + if (eavesdrop && + !(strcmp (eavesdrop, "true") == 0 || + strcmp (eavesdrop, "false") == 0)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad value \"%s\" for %s attribute, must be true or false", + "eavesdrop", eavesdrop); + return FALSE; + } + + if (send_requested_reply && + !(strcmp (send_requested_reply, "true") == 0 || + strcmp (send_requested_reply, "false") == 0)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad value \"%s\" for %s attribute, must be true or false", + "send_requested_reply", send_requested_reply); + return FALSE; + } + + rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow); + if (rule == NULL) + goto nomem; + + if (eavesdrop) + rule->d.send.eavesdrop = (strcmp (eavesdrop, "true") == 0); + + if (log) + rule->d.send.log = (strcmp (log, "true") == 0); + + if (send_requested_reply) + rule->d.send.requested_reply = (strcmp (send_requested_reply, "true") == 0); + + rule->d.send.message_type = message_type; + rule->d.send.path = _dbus_strdup (send_path); + rule->d.send.interface = _dbus_strdup (send_interface); + rule->d.send.member = _dbus_strdup (send_member); + rule->d.send.error = _dbus_strdup (send_error); + rule->d.send.destination = _dbus_strdup (send_destination); + if (send_path && rule->d.send.path == NULL) + goto nomem; + if (send_interface && rule->d.send.interface == NULL) + goto nomem; + if (send_member && rule->d.send.member == NULL) + goto nomem; + if (send_error && rule->d.send.error == NULL) + goto nomem; + if (send_destination && rule->d.send.destination == NULL) + goto nomem; + } + else if (receive_interface || receive_member || receive_error || receive_sender || + receive_path || receive_type || eavesdrop || receive_requested_reply) + { + int message_type; + + if (IS_WILDCARD (receive_interface)) + receive_interface = NULL; + if (IS_WILDCARD (receive_member)) + receive_member = NULL; + if (IS_WILDCARD (receive_error)) + receive_error = NULL; + if (IS_WILDCARD (receive_sender)) + receive_sender = NULL; + if (IS_WILDCARD (receive_path)) + receive_path = NULL; + if (IS_WILDCARD (receive_type)) + receive_type = NULL; + + message_type = DBUS_MESSAGE_TYPE_INVALID; + if (receive_type != NULL) + { + message_type = dbus_message_type_from_string (receive_type); + if (message_type == DBUS_MESSAGE_TYPE_INVALID) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad message type \"%s\"", + receive_type); + return FALSE; + } + } + + + if (eavesdrop && + !(strcmp (eavesdrop, "true") == 0 || + strcmp (eavesdrop, "false") == 0)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad value \"%s\" for %s attribute, must be true or false", + "eavesdrop", eavesdrop); + return FALSE; + } + + if (receive_requested_reply && + !(strcmp (receive_requested_reply, "true") == 0 || + strcmp (receive_requested_reply, "false") == 0)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Bad value \"%s\" for %s attribute, must be true or false", + "receive_requested_reply", receive_requested_reply); + return FALSE; + } + + rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow); + if (rule == NULL) + goto nomem; + + if (eavesdrop) + rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0); + + if (receive_requested_reply) + rule->d.receive.requested_reply = (strcmp (receive_requested_reply, "true") == 0); + + rule->d.receive.message_type = message_type; + rule->d.receive.path = _dbus_strdup (receive_path); + rule->d.receive.interface = _dbus_strdup (receive_interface); + rule->d.receive.member = _dbus_strdup (receive_member); + rule->d.receive.error = _dbus_strdup (receive_error); + rule->d.receive.origin = _dbus_strdup (receive_sender); + + if (receive_path && rule->d.receive.path == NULL) + goto nomem; + if (receive_interface && rule->d.receive.interface == NULL) + goto nomem; + if (receive_member && rule->d.receive.member == NULL) + goto nomem; + if (receive_error && rule->d.receive.error == NULL) + goto nomem; + if (receive_sender && rule->d.receive.origin == NULL) + goto nomem; + } + else if (own) + { + rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow); + if (rule == NULL) + goto nomem; + + if (IS_WILDCARD (own)) + own = NULL; + + rule->d.own.service_name = _dbus_strdup (own); + if (own && rule->d.own.service_name == NULL) + goto nomem; + } + else if (user) + { + if (IS_WILDCARD (user)) + { + rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); + if (rule == NULL) + goto nomem; + + rule->d.user.uid = DBUS_UID_UNSET; + } + else + { + DBusString username; + dbus_uid_t uid; + + _dbus_string_init_const (&username, user); + + if (_dbus_parse_unix_user_from_config (&username, &uid)) + { + rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow); + if (rule == NULL) + goto nomem; + + rule->d.user.uid = uid; + } + else + { + _dbus_warn ("Unknown username \"%s\" on element <%s>\n", + user, element_name); + } + } + } + else if (group) + { + if (IS_WILDCARD (group)) + { + rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); + if (rule == NULL) + goto nomem; + + rule->d.group.gid = DBUS_GID_UNSET; + } + else + { + DBusString groupname; + dbus_gid_t gid; + + _dbus_string_init_const (&groupname, group); + + if (_dbus_parse_unix_group_from_config (&groupname, &gid)) + { + rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow); + if (rule == NULL) + goto nomem; + + rule->d.group.gid = gid; + } + else + { + _dbus_warn ("Unknown group \"%s\" on element <%s>\n", + group, element_name); + } + } + } + else + _dbus_assert_not_reached ("Did not handle some combination of attributes on or "); + + if (rule != NULL) + { + Element *pe; + + pe = peek_element (parser); + _dbus_assert (pe != NULL); + _dbus_assert (pe->type == ELEMENT_POLICY); + + switch (pe->d.policy.type) + { + case POLICY_IGNORED: + /* drop the rule on the floor */ + break; + + case POLICY_DEFAULT: + if (!bus_policy_append_default_rule (parser->policy, rule)) + goto nomem; + break; + case POLICY_MANDATORY: + if (!bus_policy_append_mandatory_rule (parser->policy, rule)) + goto nomem; + break; + case POLICY_USER: + if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "<%s> rule cannot be per-user because it has bus-global semantics", + element_name); + goto failed; + } + + if (!bus_policy_append_user_rule (parser->policy, pe->d.policy.gid_uid_or_at_console, + rule)) + goto nomem; + break; + case POLICY_GROUP: + if (!BUS_POLICY_RULE_IS_PER_CLIENT (rule)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "<%s> rule cannot be per-group because it has bus-global semantics", + element_name); + goto failed; + } + + if (!bus_policy_append_group_rule (parser->policy, pe->d.policy.gid_uid_or_at_console, + rule)) + goto nomem; + break; + + + case POLICY_CONSOLE: + if (!bus_policy_append_console_rule (parser->policy, pe->d.policy.gid_uid_or_at_console, + rule)) + goto nomem; + break; + } + + bus_policy_rule_unref (rule); + rule = NULL; + } + + return TRUE; + + nomem: + BUS_SET_OOM (error); + failed: + if (rule) + bus_policy_rule_unref (rule); + return FALSE; +} + +static dbus_bool_t +start_policy_child (BusConfigParser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + DBusError *error) +{ + if (strcmp (element_name, "allow") == 0) + { + if (!append_rule_from_element (parser, element_name, + attribute_names, attribute_values, + TRUE, error)) + return FALSE; + + if (push_element (parser, ELEMENT_ALLOW) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else if (strcmp (element_name, "deny") == 0) + { + if (!append_rule_from_element (parser, element_name, + attribute_names, attribute_values, + FALSE, error)) + return FALSE; + + if (push_element (parser, ELEMENT_DENY) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Element <%s> not allowed inside <%s> in configuration file", + element_name, "policy"); + return FALSE; + } +} + +static dbus_bool_t +start_selinux_child (BusConfigParser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + DBusError *error) +{ + char *own_copy; + char *context_copy; + + own_copy = NULL; + context_copy = NULL; + + if (strcmp (element_name, "associate") == 0) + { + const char *own; + const char *context; + + if (!locate_attributes (parser, "associate", + attribute_names, + attribute_values, + error, + "own", &own, + "context", &context, + NULL)) + return FALSE; + + if (push_element (parser, ELEMENT_ASSOCIATE) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (own == NULL || context == NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Element must have attributes own=\"\" and context=\"\""); + return FALSE; + } + + own_copy = _dbus_strdup (own); + if (own_copy == NULL) + goto oom; + context_copy = _dbus_strdup (context); + if (context_copy == NULL) + goto oom; + + if (!_dbus_hash_table_insert_string (parser->service_context_table, + own_copy, context_copy)) + goto oom; + + return TRUE; + } + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Element <%s> not allowed inside <%s> in configuration file", + element_name, "selinux"); + return FALSE; + } + + oom: + if (own_copy) + dbus_free (own_copy); + + if (context_copy) + dbus_free (context_copy); + + BUS_SET_OOM (error); + return FALSE; +} + +dbus_bool_t +bus_config_parser_start_element (BusConfigParser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + DBusError *error) +{ + ElementType t; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* printf ("START: %s\n", element_name); */ + + t = top_element_type (parser); + + if (t == ELEMENT_NONE) + { + if (strcmp (element_name, "busconfig") == 0) + { + if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error)) + return FALSE; + + if (push_element (parser, ELEMENT_BUSCONFIG) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; + } + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Unknown element <%s> at root of configuration file", + element_name); + return FALSE; + } + } + else if (t == ELEMENT_BUSCONFIG) + { + return start_busconfig_child (parser, element_name, + attribute_names, attribute_values, + error); + } + else if (t == ELEMENT_POLICY) + { + return start_policy_child (parser, element_name, + attribute_names, attribute_values, + error); + } + else if (t == ELEMENT_SELINUX) + { + return start_selinux_child (parser, element_name, + attribute_names, attribute_values, + error); + } + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Element <%s> is not allowed in this context", + element_name); + return FALSE; + } +} + +static dbus_bool_t +set_limit (BusConfigParser *parser, + const char *name, + long value, + DBusError *error) +{ + dbus_bool_t must_be_positive; + dbus_bool_t must_be_int; + + must_be_int = FALSE; + must_be_positive = FALSE; + + if (strcmp (name, "max_incoming_bytes") == 0) + { + must_be_positive = TRUE; + parser->limits.max_incoming_bytes = value; + } + else if (strcmp (name, "max_outgoing_bytes") == 0) + { + must_be_positive = TRUE; + parser->limits.max_outgoing_bytes = value; + } + else if (strcmp (name, "max_message_size") == 0) + { + must_be_positive = TRUE; + parser->limits.max_message_size = value; + } + else if (strcmp (name, "service_start_timeout") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.activation_timeout = value; + } + else if (strcmp (name, "auth_timeout") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.auth_timeout = value; + } + else if (strcmp (name, "reply_timeout") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.reply_timeout = value; + } + else if (strcmp (name, "max_completed_connections") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.max_completed_connections = value; + } + else if (strcmp (name, "max_incomplete_connections") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.max_incomplete_connections = value; + } + else if (strcmp (name, "max_connections_per_user") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.max_connections_per_user = value; + } + else if (strcmp (name, "max_pending_service_starts") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.max_pending_activations = value; + } + else if (strcmp (name, "max_names_per_connection") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.max_services_per_connection = value; + } + else if (strcmp (name, "max_match_rules_per_connection") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.max_match_rules_per_connection = value; + } + else if (strcmp (name, "max_replies_per_connection") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.max_replies_per_connection = value; + } + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "There is no limit called \"%s\"\n", + name); + return FALSE; + } + + if (must_be_positive && value < 0) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + " must be a positive number\n", + name); + return FALSE; + } + + if (must_be_int && + (value < _DBUS_INT_MIN || value > _DBUS_INT_MAX)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + " value is too large\n", + name); + return FALSE; + } + + return TRUE; +} + +dbus_bool_t +bus_config_parser_end_element (BusConfigParser *parser, + const char *element_name, + DBusError *error) +{ + ElementType t; + const char *n; + Element *e; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* printf ("END: %s\n", element_name); */ + + t = top_element_type (parser); + + if (t == ELEMENT_NONE) + { + /* should probably be an assertion failure but + * being paranoid about XML parsers + */ + dbus_set_error (error, DBUS_ERROR_FAILED, + "XML parser ended element with no element on the stack"); + return FALSE; + } + + n = bus_config_parser_element_type_to_name (t); + _dbus_assert (n != NULL); + if (strcmp (n, element_name) != 0) + { + /* should probably be an assertion failure but + * being paranoid about XML parsers + */ + dbus_set_error (error, DBUS_ERROR_FAILED, + "XML element <%s> ended but topmost element on the stack was <%s>", + element_name, n); + return FALSE; + } + + e = peek_element (parser); + _dbus_assert (e != NULL); + + switch (e->type) + { + case ELEMENT_NONE: + _dbus_assert_not_reached ("element in stack has no type"); + break; + + case ELEMENT_INCLUDE: + case ELEMENT_USER: + case ELEMENT_TYPE: + case ELEMENT_LISTEN: + case ELEMENT_PIDFILE: + case ELEMENT_AUTH: + case ELEMENT_SERVICEDIR: + case ELEMENT_SERVICEHELPER: + case ELEMENT_INCLUDEDIR: + case ELEMENT_LIMIT: + if (!e->had_content) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "XML element <%s> was expected to have content inside it", + bus_config_parser_element_type_to_name (e->type)); + return FALSE; + } + + if (e->type == ELEMENT_LIMIT) + { + if (!set_limit (parser, e->d.limit.name, e->d.limit.value, + error)) + return FALSE; + } + break; + + case ELEMENT_BUSCONFIG: + case ELEMENT_POLICY: + case ELEMENT_ALLOW: + case ELEMENT_DENY: + case ELEMENT_FORK: + case ELEMENT_SYSLOG: + case ELEMENT_KEEP_UMASK: + case ELEMENT_SELINUX: + case ELEMENT_ASSOCIATE: + case ELEMENT_STANDARD_SESSION_SERVICEDIRS: + case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS: + break; + } + + pop_element (parser); + + return TRUE; +} + +static dbus_bool_t +all_whitespace (const DBusString *str) +{ + int i; + + _dbus_string_skip_white (str, 0, &i); + + return i == _dbus_string_get_length (str); +} + +static dbus_bool_t +make_full_path (const DBusString *basedir, + const DBusString *filename, + DBusString *full_path) +{ + if (_dbus_path_is_absolute (filename)) + { + return _dbus_string_copy (filename, 0, full_path, 0); + } + else + { + if (!_dbus_string_copy (basedir, 0, full_path, 0)) + return FALSE; + + if (!_dbus_concat_dir_and_file (full_path, filename)) + return FALSE; + + return TRUE; + } +} + +static dbus_bool_t +include_file (BusConfigParser *parser, + const DBusString *filename, + dbus_bool_t ignore_missing, + DBusError *error) +{ + /* FIXME good test case for this would load each config file in the + * test suite both alone, and as an include, and check + * that the result is the same + */ + BusConfigParser *included; + const char *filename_str; + DBusError tmp_error; + + dbus_error_init (&tmp_error); + + filename_str = _dbus_string_get_const_data (filename); + + /* Check to make sure this file hasn't already been included. */ + if (seen_include (parser, filename)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Circular inclusion of file '%s'", + filename_str); + return FALSE; + } + + if (! _dbus_list_append (&parser->included_files, (void *) filename_str)) + { + BUS_SET_OOM (error); + return FALSE; + } + + /* Since parser is passed in as the parent, included + inherits parser's limits. */ + included = bus_config_load (filename, FALSE, parser, &tmp_error); + + _dbus_list_pop_last (&parser->included_files); + + if (included == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + + if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) && + ignore_missing) + { + dbus_error_free (&tmp_error); + return TRUE; + } + else + { + dbus_move_error (&tmp_error, error); + return FALSE; + } + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); + + if (!merge_included (parser, included, error)) + { + bus_config_parser_unref (included); + return FALSE; + } + + /* Copy included's limits back to parser. */ + parser->limits = included->limits; + + bus_config_parser_unref (included); + return TRUE; + } +} + +static dbus_bool_t +servicehelper_path (BusConfigParser *parser, + const DBusString *filename, + DBusError *error) +{ + const char *filename_str; + char *servicehelper; + + filename_str = _dbus_string_get_const_data (filename); + + /* copy to avoid overwriting with NULL on OOM */ + servicehelper = _dbus_strdup (filename_str); + + /* check for OOM */ + if (servicehelper == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + /* save the latest servicehelper only if not OOM */ + dbus_free (parser->servicehelper); + parser->servicehelper = servicehelper; + + /* We don't check whether the helper exists; instead we + * would just fail to ever activate anything if it doesn't. + * This allows an admin to fix the problem if it doesn't exist. + * It also allows the parser test suite to successfully parse + * test cases without installing the helper. ;-) + */ + + return TRUE; +} + +static dbus_bool_t +include_dir (BusConfigParser *parser, + const DBusString *dirname, + DBusError *error) +{ + DBusString filename; + dbus_bool_t retval; + DBusError tmp_error; + DBusDirIter *dir; + char *s; + + if (!_dbus_string_init (&filename)) + { + BUS_SET_OOM (error); + return FALSE; + } + + retval = FALSE; + + dir = _dbus_directory_open (dirname, error); + + if (dir == NULL) + goto failed; + + dbus_error_init (&tmp_error); + while (_dbus_directory_get_next_file (dir, &filename, &tmp_error)) + { + DBusString full_path; + + if (!_dbus_string_init (&full_path)) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!_dbus_string_copy (dirname, 0, &full_path, 0)) + { + BUS_SET_OOM (error); + _dbus_string_free (&full_path); + goto failed; + } + + if (!_dbus_concat_dir_and_file (&full_path, &filename)) + { + BUS_SET_OOM (error); + _dbus_string_free (&full_path); + goto failed; + } + + if (_dbus_string_ends_with_c_str (&full_path, ".conf")) + { + if (!include_file (parser, &full_path, TRUE, error)) + { + _dbus_string_free (&full_path); + goto failed; + } + } + + _dbus_string_free (&full_path); + } + + if (dbus_error_is_set (&tmp_error)) + { + dbus_move_error (&tmp_error, error); + goto failed; + } + + + if (!_dbus_string_copy_data (dirname, &s)) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!_dbus_list_append (&parser->conf_dirs, s)) + { + dbus_free (s); + BUS_SET_OOM (error); + goto failed; + } + + retval = TRUE; + + failed: + _dbus_string_free (&filename); + + if (dir) + _dbus_directory_close (dir); + + return retval; +} + +dbus_bool_t +bus_config_parser_content (BusConfigParser *parser, + const DBusString *content, + DBusError *error) +{ + Element *e; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + +#if 0 + { + const char *c_str; + + _dbus_string_get_const_data (content, &c_str); + + printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str); + } +#endif + + e = peek_element (parser); + if (e == NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Text content outside of any XML element in configuration file"); + return FALSE; + } + else if (e->had_content) + { + _dbus_assert_not_reached ("Element had multiple content blocks"); + return FALSE; + } + + switch (top_element_type (parser)) + { + case ELEMENT_NONE: + _dbus_assert_not_reached ("element at top of stack has no type"); + return FALSE; + + case ELEMENT_BUSCONFIG: + case ELEMENT_POLICY: + case ELEMENT_ALLOW: + case ELEMENT_DENY: + case ELEMENT_FORK: + case ELEMENT_SYSLOG: + case ELEMENT_KEEP_UMASK: + case ELEMENT_STANDARD_SESSION_SERVICEDIRS: + case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS: + case ELEMENT_SELINUX: + case ELEMENT_ASSOCIATE: + if (all_whitespace (content)) + return TRUE; + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "No text content expected inside XML element %s in configuration file", + bus_config_parser_element_type_to_name (top_element_type (parser))); + return FALSE; + } + + case ELEMENT_PIDFILE: + { + char *s; + + e->had_content = TRUE; + + if (!_dbus_string_copy_data (content, &s)) + goto nomem; + + dbus_free (parser->pidfile); + parser->pidfile = s; + } + break; + + case ELEMENT_INCLUDE: + { + DBusString full_path, selinux_policy_root; + + e->had_content = TRUE; + + if (e->d.include.if_selinux_enabled + && !bus_selinux_enabled ()) + break; + + if (!_dbus_string_init (&full_path)) + goto nomem; + + if (e->d.include.selinux_root_relative) + { + if (!bus_selinux_get_policy_root ()) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Could not determine SELinux policy root for relative inclusion"); + _dbus_string_free (&full_path); + return FALSE; + } + _dbus_string_init_const (&selinux_policy_root, + bus_selinux_get_policy_root ()); + if (!make_full_path (&selinux_policy_root, content, &full_path)) + { + _dbus_string_free (&full_path); + goto nomem; + } + } + else if (!make_full_path (&parser->basedir, content, &full_path)) + { + _dbus_string_free (&full_path); + goto nomem; + } + + if (!include_file (parser, &full_path, + e->d.include.ignore_missing, error)) + { + _dbus_string_free (&full_path); + return FALSE; + } + + _dbus_string_free (&full_path); + } + break; + + case ELEMENT_SERVICEHELPER: + { + DBusString full_path; + + e->had_content = TRUE; + + if (!_dbus_string_init (&full_path)) + goto nomem; + + if (!make_full_path (&parser->basedir, content, &full_path)) + { + _dbus_string_free (&full_path); + goto nomem; + } + + if (!servicehelper_path (parser, &full_path, error)) + { + _dbus_string_free (&full_path); + return FALSE; + } + + _dbus_string_free (&full_path); + } + break; + + case ELEMENT_INCLUDEDIR: + { + DBusString full_path; + + e->had_content = TRUE; + + if (!_dbus_string_init (&full_path)) + goto nomem; + + if (!make_full_path (&parser->basedir, content, &full_path)) + { + _dbus_string_free (&full_path); + goto nomem; + } + + if (!include_dir (parser, &full_path, error)) + { + _dbus_string_free (&full_path); + return FALSE; + } + + _dbus_string_free (&full_path); + } + break; + + case ELEMENT_USER: + { + char *s; + + e->had_content = TRUE; + + if (!_dbus_string_copy_data (content, &s)) + goto nomem; + + dbus_free (parser->user); + parser->user = s; + } + break; + + case ELEMENT_TYPE: + { + char *s; + + e->had_content = TRUE; + + if (!_dbus_string_copy_data (content, &s)) + goto nomem; + + dbus_free (parser->bus_type); + parser->bus_type = s; + } + break; + + case ELEMENT_LISTEN: + { + char *s; + + e->had_content = TRUE; + + if (!_dbus_string_copy_data (content, &s)) + goto nomem; + + if (!_dbus_list_append (&parser->listen_on, + s)) + { + dbus_free (s); + goto nomem; + } + } + break; + + case ELEMENT_AUTH: + { + char *s; + + e->had_content = TRUE; + + if (!_dbus_string_copy_data (content, &s)) + goto nomem; + + if (!_dbus_list_append (&parser->mechanisms, + s)) + { + dbus_free (s); + goto nomem; + } + } + break; + + case ELEMENT_SERVICEDIR: + { + char *s; + DBusString full_path; + + e->had_content = TRUE; + + if (!_dbus_string_init (&full_path)) + goto nomem; + + if (!make_full_path (&parser->basedir, content, &full_path)) + { + _dbus_string_free (&full_path); + goto nomem; + } + + if (!_dbus_string_copy_data (&full_path, &s)) + { + _dbus_string_free (&full_path); + goto nomem; + } + + /* _only_ extra session directories can be specified */ + if (!service_dirs_append_unique_or_free (&parser->service_dirs, s)) + { + _dbus_string_free (&full_path); + dbus_free (s); + goto nomem; + } + + _dbus_string_free (&full_path); + } + break; + + case ELEMENT_LIMIT: + { + long val; + + e->had_content = TRUE; + + val = 0; + if (!_dbus_string_parse_int (content, 0, &val, NULL)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + " element has invalid value (could not parse as integer)", + e->d.limit.name); + return FALSE; + } + + e->d.limit.value = val; + + _dbus_verbose ("Loaded value %ld for limit %s\n", + e->d.limit.value, + e->d.limit.name); + } + break; + } + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return TRUE; + + nomem: + BUS_SET_OOM (error); + return FALSE; +} + +dbus_bool_t +bus_config_parser_finished (BusConfigParser *parser, + DBusError *error) +{ + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (parser->stack != NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Element <%s> was not closed in configuration file", + bus_config_parser_element_type_to_name (top_element_type (parser))); + + return FALSE; + } + + if (parser->is_toplevel && parser->listen_on == NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Configuration file needs one or more elements giving addresses"); + return FALSE; + } + + return TRUE; +} + +const char* +bus_config_parser_get_user (BusConfigParser *parser) +{ + return parser->user; +} + +const char* +bus_config_parser_get_type (BusConfigParser *parser) +{ + return parser->bus_type; +} + +DBusList** +bus_config_parser_get_addresses (BusConfigParser *parser) +{ + return &parser->listen_on; +} + +DBusList** +bus_config_parser_get_mechanisms (BusConfigParser *parser) +{ + return &parser->mechanisms; +} + +DBusList** +bus_config_parser_get_service_dirs (BusConfigParser *parser) +{ + return &parser->service_dirs; +} + +DBusList** +bus_config_parser_get_conf_dirs (BusConfigParser *parser) +{ + return &parser->conf_dirs; +} + +dbus_bool_t +bus_config_parser_get_fork (BusConfigParser *parser) +{ + return parser->fork; +} + +dbus_bool_t +bus_config_parser_get_syslog (BusConfigParser *parser) +{ + return parser->syslog; +} + +dbus_bool_t +bus_config_parser_get_keep_umask (BusConfigParser *parser) +{ + return parser->keep_umask; +} + +const char * +bus_config_parser_get_pidfile (BusConfigParser *parser) +{ + return parser->pidfile; +} + +const char * +bus_config_parser_get_servicehelper (BusConfigParser *parser) +{ + return parser->servicehelper; +} + +BusPolicy* +bus_config_parser_steal_policy (BusConfigParser *parser) +{ + BusPolicy *policy; + + _dbus_assert (parser->policy != NULL); /* can only steal the policy 1 time */ + + policy = parser->policy; + + parser->policy = NULL; + + return policy; +} + +/* Overwrite any limits that were set in the configuration file */ +void +bus_config_parser_get_limits (BusConfigParser *parser, + BusLimits *limits) +{ + *limits = parser->limits; +} + +DBusHashTable* +bus_config_parser_steal_service_context_table (BusConfigParser *parser) +{ + DBusHashTable *table; + + _dbus_assert (parser->service_context_table != NULL); /* can only steal once */ + + table = parser->service_context_table; + + parser->service_context_table = NULL; + + return table; +} + +#ifdef DBUS_BUILD_TESTS +#include + +typedef enum +{ + VALID, + INVALID, + UNKNOWN +} Validity; + +static dbus_bool_t +do_load (const DBusString *full_path, + Validity validity, + dbus_bool_t oom_possible) +{ + BusConfigParser *parser; + DBusError error; + + dbus_error_init (&error); + + parser = bus_config_load (full_path, TRUE, NULL, &error); + if (parser == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (&error); + + if (oom_possible && + dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + _dbus_verbose ("Failed to load valid file due to OOM\n"); + dbus_error_free (&error); + return TRUE; + } + else if (validity == VALID) + { + _dbus_warn ("Failed to load valid file but still had memory: %s\n", + error.message); + + dbus_error_free (&error); + return FALSE; + } + else + { + dbus_error_free (&error); + return TRUE; + } + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (&error); + + bus_config_parser_unref (parser); + + if (validity == INVALID) + { + _dbus_warn ("Accepted invalid file\n"); + return FALSE; + } + + return TRUE; + } +} + +typedef struct +{ + const DBusString *full_path; + Validity validity; +} LoaderOomData; + +static dbus_bool_t +check_loader_oom_func (void *data) +{ + LoaderOomData *d = data; + + return do_load (d->full_path, d->validity, TRUE); +} + +static dbus_bool_t +process_test_valid_subdir (const DBusString *test_base_dir, + const char *subdir, + Validity validity) +{ + DBusString test_directory; + DBusString filename; + DBusDirIter *dir; + dbus_bool_t retval; + DBusError error; + + retval = FALSE; + dir = NULL; + + if (!_dbus_string_init (&test_directory)) + _dbus_assert_not_reached ("didn't allocate test_directory\n"); + + _dbus_string_init_const (&filename, subdir); + + if (!_dbus_string_copy (test_base_dir, 0, + &test_directory, 0)) + _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); + + if (!_dbus_concat_dir_and_file (&test_directory, &filename)) + _dbus_assert_not_reached ("couldn't allocate full path"); + + _dbus_string_free (&filename); + if (!_dbus_string_init (&filename)) + _dbus_assert_not_reached ("didn't allocate filename string\n"); + + dbus_error_init (&error); + dir = _dbus_directory_open (&test_directory, &error); + if (dir == NULL) + { + _dbus_warn ("Could not open %s: %s\n", + _dbus_string_get_const_data (&test_directory), + error.message); + dbus_error_free (&error); + goto failed; + } + + if (validity == VALID) + printf ("Testing valid files:\n"); + else if (validity == INVALID) + printf ("Testing invalid files:\n"); + else + printf ("Testing unknown files:\n"); + + next: + while (_dbus_directory_get_next_file (dir, &filename, &error)) + { + DBusString full_path; + LoaderOomData d; + + if (!_dbus_string_init (&full_path)) + _dbus_assert_not_reached ("couldn't init string"); + + if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) + _dbus_assert_not_reached ("couldn't copy dir to full_path"); + + if (!_dbus_concat_dir_and_file (&full_path, &filename)) + _dbus_assert_not_reached ("couldn't concat file to dir"); + + if (!_dbus_string_ends_with_c_str (&full_path, ".conf")) + { + _dbus_verbose ("Skipping non-.conf file %s\n", + _dbus_string_get_const_data (&filename)); + _dbus_string_free (&full_path); + goto next; + } + + printf (" %s\n", _dbus_string_get_const_data (&filename)); + + _dbus_verbose (" expecting %s\n", + validity == VALID ? "valid" : + (validity == INVALID ? "invalid" : + (validity == UNKNOWN ? "unknown" : "???"))); + + d.full_path = &full_path; + d.validity = validity; + + /* FIXME hackaround for an expat problem, see + * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=124747 + * http://freedesktop.org/pipermail/dbus/2004-May/001153.html + */ + /* if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d)) */ + if (!check_loader_oom_func (&d)) + _dbus_assert_not_reached ("test failed"); + + _dbus_string_free (&full_path); + } + + if (dbus_error_is_set (&error)) + { + _dbus_warn ("Could not get next file in %s: %s\n", + _dbus_string_get_const_data (&test_directory), + error.message); + dbus_error_free (&error); + goto failed; + } + + retval = TRUE; + + failed: + + if (dir) + _dbus_directory_close (dir); + _dbus_string_free (&test_directory); + _dbus_string_free (&filename); + + return retval; +} + +static dbus_bool_t +bools_equal (dbus_bool_t a, + dbus_bool_t b) +{ + return a ? b : !b; +} + +static dbus_bool_t +strings_equal_or_both_null (const char *a, + const char *b) +{ + if (a == NULL || b == NULL) + return a == b; + else + return !strcmp (a, b); +} + +static dbus_bool_t +elements_equal (const Element *a, + const Element *b) +{ + if (a->type != b->type) + return FALSE; + + if (!bools_equal (a->had_content, b->had_content)) + return FALSE; + + switch (a->type) + { + + case ELEMENT_INCLUDE: + if (!bools_equal (a->d.include.ignore_missing, + b->d.include.ignore_missing)) + return FALSE; + break; + + case ELEMENT_POLICY: + if (a->d.policy.type != b->d.policy.type) + return FALSE; + if (a->d.policy.gid_uid_or_at_console != b->d.policy.gid_uid_or_at_console) + return FALSE; + break; + + case ELEMENT_LIMIT: + if (strcmp (a->d.limit.name, b->d.limit.name)) + return FALSE; + if (a->d.limit.value != b->d.limit.value) + return FALSE; + break; + + default: + /* do nothing */ + break; + } + + return TRUE; + +} + +static dbus_bool_t +lists_of_elements_equal (DBusList *a, + DBusList *b) +{ + DBusList *ia; + DBusList *ib; + + ia = a; + ib = b; + + while (ia != NULL && ib != NULL) + { + if (elements_equal (ia->data, ib->data)) + return FALSE; + ia = _dbus_list_get_next_link (&a, ia); + ib = _dbus_list_get_next_link (&b, ib); + } + + return ia == NULL && ib == NULL; +} + +static dbus_bool_t +lists_of_c_strings_equal (DBusList *a, + DBusList *b) +{ + DBusList *ia; + DBusList *ib; + + ia = a; + ib = b; + + while (ia != NULL && ib != NULL) + { + if (strcmp (ia->data, ib->data)) + return FALSE; + ia = _dbus_list_get_next_link (&a, ia); + ib = _dbus_list_get_next_link (&b, ib); + } + + return ia == NULL && ib == NULL; +} + +static dbus_bool_t +limits_equal (const BusLimits *a, + const BusLimits *b) +{ + return + (a->max_incoming_bytes == b->max_incoming_bytes + || a->max_outgoing_bytes == b->max_outgoing_bytes + || a->max_message_size == b->max_message_size + || a->activation_timeout == b->activation_timeout + || a->auth_timeout == b->auth_timeout + || a->max_completed_connections == b->max_completed_connections + || a->max_incomplete_connections == b->max_incomplete_connections + || a->max_connections_per_user == b->max_connections_per_user + || a->max_pending_activations == b->max_pending_activations + || a->max_services_per_connection == b->max_services_per_connection + || a->max_match_rules_per_connection == b->max_match_rules_per_connection + || a->max_replies_per_connection == b->max_replies_per_connection + || a->reply_timeout == b->reply_timeout); +} + +static dbus_bool_t +config_parsers_equal (const BusConfigParser *a, + const BusConfigParser *b) +{ + if (!_dbus_string_equal (&a->basedir, &b->basedir)) + return FALSE; + + if (!lists_of_elements_equal (a->stack, b->stack)) + return FALSE; + + if (!strings_equal_or_both_null (a->user, b->user)) + return FALSE; + + if (!lists_of_c_strings_equal (a->listen_on, b->listen_on)) + return FALSE; + + if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms)) + return FALSE; + + if (!lists_of_c_strings_equal (a->service_dirs, b->service_dirs)) + return FALSE; + + /* FIXME: compare policy */ + + /* FIXME: compare service selinux ID table */ + + if (! limits_equal (&a->limits, &b->limits)) + return FALSE; + + if (!strings_equal_or_both_null (a->pidfile, b->pidfile)) + return FALSE; + + if (! bools_equal (a->fork, b->fork)) + return FALSE; + + if (! bools_equal (a->keep_umask, b->keep_umask)) + return FALSE; + + if (! bools_equal (a->is_toplevel, b->is_toplevel)) + return FALSE; + + return TRUE; +} + +static dbus_bool_t +all_are_equiv (const DBusString *target_directory) +{ + DBusString filename; + DBusDirIter *dir; + BusConfigParser *first_parser; + BusConfigParser *parser; + DBusError error; + dbus_bool_t equal; + dbus_bool_t retval; + + dir = NULL; + first_parser = NULL; + parser = NULL; + retval = FALSE; + + if (!_dbus_string_init (&filename)) + _dbus_assert_not_reached ("didn't allocate filename string"); + + dbus_error_init (&error); + dir = _dbus_directory_open (target_directory, &error); + if (dir == NULL) + { + _dbus_warn ("Could not open %s: %s\n", + _dbus_string_get_const_data (target_directory), + error.message); + dbus_error_free (&error); + goto finished; + } + + printf ("Comparing equivalent files:\n"); + + next: + while (_dbus_directory_get_next_file (dir, &filename, &error)) + { + DBusString full_path; + + if (!_dbus_string_init (&full_path)) + _dbus_assert_not_reached ("couldn't init string"); + + if (!_dbus_string_copy (target_directory, 0, &full_path, 0)) + _dbus_assert_not_reached ("couldn't copy dir to full_path"); + + if (!_dbus_concat_dir_and_file (&full_path, &filename)) + _dbus_assert_not_reached ("couldn't concat file to dir"); + + if (!_dbus_string_ends_with_c_str (&full_path, ".conf")) + { + _dbus_verbose ("Skipping non-.conf file %s\n", + _dbus_string_get_const_data (&filename)); + _dbus_string_free (&full_path); + goto next; + } + + printf (" %s\n", _dbus_string_get_const_data (&filename)); + + parser = bus_config_load (&full_path, TRUE, NULL, &error); + + if (parser == NULL) + { + _dbus_warn ("Could not load file %s: %s\n", + _dbus_string_get_const_data (&full_path), + error.message); + _dbus_string_free (&full_path); + dbus_error_free (&error); + goto finished; + } + else if (first_parser == NULL) + { + _dbus_string_free (&full_path); + first_parser = parser; + } + else + { + _dbus_string_free (&full_path); + equal = config_parsers_equal (first_parser, parser); + bus_config_parser_unref (parser); + if (! equal) + goto finished; + } + } + + retval = TRUE; + + finished: + _dbus_string_free (&filename); + if (first_parser) + bus_config_parser_unref (first_parser); + if (dir) + _dbus_directory_close (dir); + + return retval; + +} + +static dbus_bool_t +process_test_equiv_subdir (const DBusString *test_base_dir, + const char *subdir) +{ + DBusString test_directory; + DBusString filename; + DBusDirIter *dir; + DBusError error; + dbus_bool_t equal; + dbus_bool_t retval; + + dir = NULL; + retval = FALSE; + + if (!_dbus_string_init (&test_directory)) + _dbus_assert_not_reached ("didn't allocate test_directory"); + + _dbus_string_init_const (&filename, subdir); + + if (!_dbus_string_copy (test_base_dir, 0, + &test_directory, 0)) + _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); + + if (!_dbus_concat_dir_and_file (&test_directory, &filename)) + _dbus_assert_not_reached ("couldn't allocate full path"); + + _dbus_string_free (&filename); + if (!_dbus_string_init (&filename)) + _dbus_assert_not_reached ("didn't allocate filename string"); + + dbus_error_init (&error); + dir = _dbus_directory_open (&test_directory, &error); + if (dir == NULL) + { + _dbus_warn ("Could not open %s: %s\n", + _dbus_string_get_const_data (&test_directory), + error.message); + dbus_error_free (&error); + goto finished; + } + + while (_dbus_directory_get_next_file (dir, &filename, &error)) + { + DBusString full_path; + + /* Skip CVS's magic directories! */ + if (_dbus_string_equal_c_str (&filename, "CVS")) + continue; + + if (!_dbus_string_init (&full_path)) + _dbus_assert_not_reached ("couldn't init string"); + + if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) + _dbus_assert_not_reached ("couldn't copy dir to full_path"); + + if (!_dbus_concat_dir_and_file (&full_path, &filename)) + _dbus_assert_not_reached ("couldn't concat file to dir"); + + equal = all_are_equiv (&full_path); + _dbus_string_free (&full_path); + + if (!equal) + goto finished; + } + + retval = TRUE; + + finished: + _dbus_string_free (&test_directory); + _dbus_string_free (&filename); + if (dir) + _dbus_directory_close (dir); + + return retval; + +} + +static const char *test_session_service_dir_matches[] = + { +#ifdef DBUS_UNIX + "/testusr/testlocal/testshare/dbus-1/services", + "/testusr/testshare/dbus-1/services", +#endif + DBUS_DATADIR"/dbus-1/services", +#ifdef DBUS_UNIX + "/testhome/foo/.testlocal/testshare/dbus-1/services", +#endif + NULL + }; + +static dbus_bool_t +test_default_session_servicedirs (void) +{ + DBusList *dirs; + DBusList *link; + DBusString progs; + const char *common_progs; + int i; + + /* On Unix we don't actually use this variable, but it's easier to handle the + * deallocation if we always allocate it, whether needed or not */ + if (!_dbus_string_init (&progs)) + _dbus_assert_not_reached ("OOM allocating progs"); + + common_progs = _dbus_getenv ("CommonProgramFiles"); +#ifndef DBUS_UNIX + if (common_progs) + { + if (!_dbus_string_append (&progs, common_progs)) + { + _dbus_string_free (&progs); + return FALSE; + } + + if (!_dbus_string_append (&progs, "/dbus-1/services")) + { + _dbus_string_free (&progs); + return FALSE; + } + test_session_service_dir_matches[1] = _dbus_string_get_const_data(&progs); + } +#endif + dirs = NULL; + + printf ("Testing retrieving the default session service directories\n"); + if (!_dbus_get_standard_session_servicedirs (&dirs)) + _dbus_assert_not_reached ("couldn't get stardard dirs"); + + /* make sure our defaults end with share/dbus-1/service */ + while ((link = _dbus_list_pop_first_link (&dirs))) + { + DBusString path; + + printf (" default service dir: %s\n", (char *)link->data); + _dbus_string_init_const (&path, (char *)link->data); + if (!_dbus_string_ends_with_c_str (&path, "dbus-1/services")) + { + printf ("error with default session service directories\n"); + dbus_free (link->data); + _dbus_list_free_link (link); + _dbus_string_free (&progs); + return FALSE; + } + + dbus_free (link->data); + _dbus_list_free_link (link); + } + +#ifdef DBUS_UNIX + if (!_dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare")) + _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME"); + + if (!_dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:")) + _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS"); +#endif + if (!_dbus_get_standard_session_servicedirs (&dirs)) + _dbus_assert_not_reached ("couldn't get stardard dirs"); + + /* make sure we read and parse the env variable correctly */ + i = 0; + while ((link = _dbus_list_pop_first_link (&dirs))) + { + printf (" test service dir: %s\n", (char *)link->data); + if (test_session_service_dir_matches[i] == NULL) + { + printf ("more directories parsed than in match set\n"); + dbus_free (link->data); + _dbus_list_free_link (link); + _dbus_string_free (&progs); + return FALSE; + } + + if (strcmp (test_session_service_dir_matches[i], + (char *)link->data) != 0) + { + printf ("%s directory does not match %s in the match set\n", + (char *)link->data, + test_session_service_dir_matches[i]); + dbus_free (link->data); + _dbus_list_free_link (link); + _dbus_string_free (&progs); + return FALSE; + } + + ++i; + + dbus_free (link->data); + _dbus_list_free_link (link); + } + + if (test_session_service_dir_matches[i] != NULL) + { + printf ("extra data %s in the match set was not matched\n", + test_session_service_dir_matches[i]); + + _dbus_string_free (&progs); + return FALSE; + } + + _dbus_string_free (&progs); + return TRUE; +} + +static const char *test_system_service_dir_matches[] = + { +#ifdef DBUS_UNIX + "/testusr/testlocal/testshare/dbus-1/system-services", + "/testusr/testshare/dbus-1/system-services", +#endif + DBUS_DATADIR"/dbus-1/system-services", + NULL + }; + +static dbus_bool_t +test_default_system_servicedirs (void) +{ + DBusList *dirs; + DBusList *link; + DBusString progs; + const char *common_progs; + int i; + + /* On Unix we don't actually use this variable, but it's easier to handle the + * deallocation if we always allocate it, whether needed or not */ + if (!_dbus_string_init (&progs)) + _dbus_assert_not_reached ("OOM allocating progs"); + + common_progs = _dbus_getenv ("CommonProgramFiles"); +#ifndef DBUS_UNIX + if (common_progs) + { + if (!_dbus_string_append (&progs, common_progs)) + { + _dbus_string_free (&progs); + return FALSE; + } + + if (!_dbus_string_append (&progs, "/dbus-1/system-services")) + { + _dbus_string_free (&progs); + return FALSE; + } + test_system_service_dir_matches[1] = _dbus_string_get_const_data(&progs); + } +#endif + dirs = NULL; + + printf ("Testing retrieving the default system service directories\n"); + if (!_dbus_get_standard_system_servicedirs (&dirs)) + _dbus_assert_not_reached ("couldn't get stardard dirs"); + + /* make sure our defaults end with share/dbus-1/system-service */ + while ((link = _dbus_list_pop_first_link (&dirs))) + { + DBusString path; + + printf (" default service dir: %s\n", (char *)link->data); + _dbus_string_init_const (&path, (char *)link->data); + if (!_dbus_string_ends_with_c_str (&path, "dbus-1/system-services")) + { + printf ("error with default system service directories\n"); + dbus_free (link->data); + _dbus_list_free_link (link); + _dbus_string_free (&progs); + return FALSE; + } + + dbus_free (link->data); + _dbus_list_free_link (link); + } + +#ifdef DBUS_UNIX + if (!_dbus_setenv ("XDG_DATA_HOME", "/testhome/foo/.testlocal/testshare")) + _dbus_assert_not_reached ("couldn't setenv XDG_DATA_HOME"); + + if (!_dbus_setenv ("XDG_DATA_DIRS", ":/testusr/testlocal/testshare: :/testusr/testshare:")) + _dbus_assert_not_reached ("couldn't setenv XDG_DATA_DIRS"); +#endif + if (!_dbus_get_standard_system_servicedirs (&dirs)) + _dbus_assert_not_reached ("couldn't get stardard dirs"); + + /* make sure we read and parse the env variable correctly */ + i = 0; + while ((link = _dbus_list_pop_first_link (&dirs))) + { + printf (" test service dir: %s\n", (char *)link->data); + if (test_system_service_dir_matches[i] == NULL) + { + printf ("more directories parsed than in match set\n"); + dbus_free (link->data); + _dbus_list_free_link (link); + _dbus_string_free (&progs); + return FALSE; + } + + if (strcmp (test_system_service_dir_matches[i], + (char *)link->data) != 0) + { + printf ("%s directory does not match %s in the match set\n", + (char *)link->data, + test_system_service_dir_matches[i]); + dbus_free (link->data); + _dbus_list_free_link (link); + _dbus_string_free (&progs); + return FALSE; + } + + ++i; + + dbus_free (link->data); + _dbus_list_free_link (link); + } + + if (test_system_service_dir_matches[i] != NULL) + { + printf ("extra data %s in the match set was not matched\n", + test_system_service_dir_matches[i]); + + _dbus_string_free (&progs); + return FALSE; + } + + _dbus_string_free (&progs); + return TRUE; +} + +dbus_bool_t +bus_config_parser_test (const DBusString *test_data_dir) +{ + if (test_data_dir == NULL || + _dbus_string_get_length (test_data_dir) == 0) + { + printf ("No test data\n"); + return TRUE; + } + + if (!test_default_session_servicedirs()) + return FALSE; + + if (!test_default_system_servicedirs()) + return FALSE; + + if (!process_test_valid_subdir (test_data_dir, "valid-config-files", VALID)) + return FALSE; + + if (!process_test_valid_subdir (test_data_dir, "invalid-config-files", INVALID)) + return FALSE; + + if (!process_test_equiv_subdir (test_data_dir, "equiv-config-files")) + return FALSE; + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ + diff --git a/bus/config-parser.h b/bus/config-parser.h new file mode 100644 index 00000000..3aac1ed3 --- /dev/null +++ b/bus/config-parser.h @@ -0,0 +1,89 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* config-parser.h XML-library-agnostic configuration file parser + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_CONFIG_PARSER_H +#define BUS_CONFIG_PARSER_H + +#include + +#include +#include +#include +#include +#include "bus.h" + +/* Whatever XML library we're using just pushes data into this API */ + +typedef struct BusConfigParser BusConfigParser; + +BusConfigParser* bus_config_parser_new (const DBusString *basedir, + dbus_bool_t is_toplevel, + const BusConfigParser *parent); + +BusConfigParser* bus_config_parser_ref (BusConfigParser *parser); +void bus_config_parser_unref (BusConfigParser *parser); +dbus_bool_t bus_config_parser_check_doctype (BusConfigParser *parser, + const char *doctype, + DBusError *error); +dbus_bool_t bus_config_parser_start_element (BusConfigParser *parser, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + DBusError *error); +dbus_bool_t bus_config_parser_end_element (BusConfigParser *parser, + const char *element_name, + DBusError *error); +dbus_bool_t bus_config_parser_content (BusConfigParser *parser, + const DBusString *content, + DBusError *error); +dbus_bool_t bus_config_parser_finished (BusConfigParser *parser, + DBusError *error); + +/* Functions for extracting the parse results */ +const char* bus_config_parser_get_user (BusConfigParser *parser); +const char* bus_config_parser_get_type (BusConfigParser *parser); +DBusList** bus_config_parser_get_addresses (BusConfigParser *parser); +DBusList** bus_config_parser_get_mechanisms (BusConfigParser *parser); +dbus_bool_t bus_config_parser_get_fork (BusConfigParser *parser); +dbus_bool_t bus_config_parser_get_allow_anonymous (BusConfigParser *parser); +dbus_bool_t bus_config_parser_get_syslog (BusConfigParser *parser); +dbus_bool_t bus_config_parser_get_keep_umask (BusConfigParser *parser); +const char* bus_config_parser_get_pidfile (BusConfigParser *parser); +const char* bus_config_parser_get_servicehelper (BusConfigParser *parser); +DBusList** bus_config_parser_get_service_dirs (BusConfigParser *parser); +DBusList** bus_config_parser_get_conf_dirs (BusConfigParser *parser); +BusPolicy* bus_config_parser_steal_policy (BusConfigParser *parser); +void bus_config_parser_get_limits (BusConfigParser *parser, + BusLimits *limits); + +DBusHashTable* bus_config_parser_steal_service_context_table (BusConfigParser *parser); + +/* Loader functions (backended off one of the XML parsers). Returns a + * finished ConfigParser. + */ +BusConfigParser* bus_config_load (const DBusString *file, + dbus_bool_t is_toplevel, + const BusConfigParser *parent, + DBusError *error); + +#endif /* BUS_CONFIG_PARSER_H */ diff --git a/bus/connection.c b/bus/connection.c new file mode 100644 index 00000000..50807f1a --- /dev/null +++ b/bus/connection.c @@ -0,0 +1,2303 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* connection.c Client connections + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "connection.h" +#include "dispatch.h" +#include "policy.h" +#include "services.h" +#include "utils.h" +#include "signals.h" +#include "expirelist.h" +#include "selinux.h" +#include +#include +#include + +/* Trim executed commands to this length; we want to keep logs readable */ +#define MAX_LOG_COMMAND_LEN 50 + +static void bus_connection_remove_transactions (DBusConnection *connection); + +typedef struct +{ + BusExpireItem expire_item; + + DBusConnection *will_get_reply; + DBusConnection *will_send_reply; + + dbus_uint32_t reply_serial; + +} BusPendingReply; + +struct BusConnections +{ + int refcount; + DBusList *completed; /**< List of all completed connections */ + int n_completed; /**< Length of completed list */ + DBusList *incomplete; /**< List of all not-yet-active connections */ + int n_incomplete; /**< Length of incomplete list */ + BusContext *context; + DBusHashTable *completed_by_user; /**< Number of completed connections for each UID */ + DBusTimeout *expire_timeout; /**< Timeout for expiring incomplete connections. */ + int stamp; /**< Incrementing number */ + BusExpireList *pending_replies; /**< List of pending replies */ +}; + +static dbus_int32_t connection_data_slot = -1; + +typedef struct +{ + BusConnections *connections; + DBusList *link_in_connection_list; + DBusConnection *connection; + DBusList *services_owned; + int n_services_owned; + DBusList *match_rules; + int n_match_rules; + char *name; + DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */ + DBusMessage *oom_message; + DBusPreallocatedSend *oom_preallocated; + BusClientPolicy *policy; + + char *cached_loginfo_string; + BusSELinuxID *selinux_id; + + long connection_tv_sec; /**< Time when we connected (seconds component) */ + long connection_tv_usec; /**< Time when we connected (microsec component) */ + int stamp; /**< connections->stamp last time we were traversed */ +} BusConnectionData; + +static dbus_bool_t bus_pending_reply_expired (BusExpireList *list, + DBusList *link, + void *data); + +static void bus_connection_drop_pending_replies (BusConnections *connections, + DBusConnection *connection); + +static dbus_bool_t expire_incomplete_timeout (void *data); + +#define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot)) + +static DBusLoop* +connection_get_loop (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + return bus_context_get_loop (d->connections->context); +} + + +static int +get_connections_for_uid (BusConnections *connections, + dbus_uid_t uid) +{ + void *val; + int current_count; + + /* val is NULL is 0 when it isn't in the hash yet */ + + val = _dbus_hash_table_lookup_ulong (connections->completed_by_user, + uid); + + current_count = _DBUS_POINTER_TO_INT (val); + + return current_count; +} + +static dbus_bool_t +adjust_connections_for_uid (BusConnections *connections, + dbus_uid_t uid, + int adjustment) +{ + int current_count; + + current_count = get_connections_for_uid (connections, uid); + + _dbus_verbose ("Adjusting connection count for UID " DBUS_UID_FORMAT + ": was %d adjustment %d making %d\n", + uid, current_count, adjustment, current_count + adjustment); + + _dbus_assert (current_count >= 0); + + current_count += adjustment; + + _dbus_assert (current_count >= 0); + + if (current_count == 0) + { + _dbus_hash_table_remove_ulong (connections->completed_by_user, uid); + return TRUE; + } + else + { + dbus_bool_t retval; + + retval = _dbus_hash_table_insert_ulong (connections->completed_by_user, + uid, _DBUS_INT_TO_POINTER (current_count)); + + /* only positive adjustment can fail as otherwise + * a hash entry should already exist + */ + _dbus_assert (adjustment > 0 || + (adjustment <= 0 && retval)); + + return retval; + } +} + +void +bus_connection_disconnected (DBusConnection *connection) +{ + BusConnectionData *d; + BusService *service; + BusMatchmaker *matchmaker; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n", + d->name ? d->name : "(inactive)"); + + /* Delete our match rules */ + if (d->n_match_rules > 0) + { + matchmaker = bus_context_get_matchmaker (d->connections->context); + bus_matchmaker_disconnected (matchmaker, connection); + } + + /* Drop any service ownership. Unfortunately, this requires + * memory allocation and there doesn't seem to be a good way to + * handle it other than sleeping; we can't "fail" the operation of + * disconnecting a client, and preallocating a broadcast "service is + * now gone" message for every client-service pair seems kind of + * involved. + */ + while ((service = _dbus_list_get_last (&d->services_owned))) + { + BusTransaction *transaction; + DBusError error; + + retry: + + dbus_error_init (&error); + + while ((transaction = bus_transaction_new (d->connections->context)) == NULL) + _dbus_wait_for_memory (); + + if (!bus_service_remove_owner (service, connection, + transaction, &error)) + { + _DBUS_ASSERT_ERROR_IS_SET (&error); + + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + dbus_error_free (&error); + bus_transaction_cancel_and_free (transaction); + _dbus_wait_for_memory (); + goto retry; + } + else + { + _dbus_verbose ("Failed to remove service owner: %s %s\n", + error.name, error.message); + _dbus_assert_not_reached ("Removing service owner failed for non-memory-related reason"); + } + } + + bus_transaction_execute_and_free (transaction); + } + + bus_dispatch_remove_connection (connection); + + /* no more watching */ + if (!dbus_connection_set_watch_functions (connection, + NULL, NULL, NULL, + connection, + NULL)) + _dbus_assert_not_reached ("setting watch functions to NULL failed"); + + if (!dbus_connection_set_timeout_functions (connection, + NULL, NULL, NULL, + connection, + NULL)) + _dbus_assert_not_reached ("setting timeout functions to NULL failed"); + + dbus_connection_set_unix_user_function (connection, + NULL, NULL, NULL); + dbus_connection_set_windows_user_function (connection, + NULL, NULL, NULL); + + dbus_connection_set_dispatch_status_function (connection, + NULL, NULL, NULL); + + bus_connection_remove_transactions (connection); + + if (d->link_in_connection_list != NULL) + { + if (d->name != NULL) + { + unsigned long uid; + + _dbus_list_remove_link (&d->connections->completed, d->link_in_connection_list); + d->link_in_connection_list = NULL; + d->connections->n_completed -= 1; + + if (dbus_connection_get_unix_user (connection, &uid)) + { + if (!adjust_connections_for_uid (d->connections, + uid, -1)) + _dbus_assert_not_reached ("adjusting downward should never fail"); + } + } + else + { + _dbus_list_remove_link (&d->connections->incomplete, d->link_in_connection_list); + d->link_in_connection_list = NULL; + d->connections->n_incomplete -= 1; + } + + _dbus_assert (d->connections->n_incomplete >= 0); + _dbus_assert (d->connections->n_completed >= 0); + } + + bus_connection_drop_pending_replies (d->connections, connection); + + /* frees "d" as side effect */ + dbus_connection_set_data (connection, + connection_data_slot, + NULL, NULL); + + dbus_connection_unref (connection); +} + +static dbus_bool_t +connection_watch_callback (DBusWatch *watch, + unsigned int condition, + void *data) +{ + /* FIXME this can be done in dbus-mainloop.c + * if the code in activation.c for the babysitter + * watch handler is fixed. + */ + +#if 0 + _dbus_verbose ("Calling handle_watch\n"); +#endif + return dbus_watch_handle (watch, condition); +} + +static dbus_bool_t +add_connection_watch (DBusWatch *watch, + void *data) +{ + DBusConnection *connection = data; + + return _dbus_loop_add_watch (connection_get_loop (connection), + watch, connection_watch_callback, connection, + NULL); +} + +static void +remove_connection_watch (DBusWatch *watch, + void *data) +{ + DBusConnection *connection = data; + + _dbus_loop_remove_watch (connection_get_loop (connection), + watch, connection_watch_callback, connection); +} + +static void +connection_timeout_callback (DBusTimeout *timeout, + void *data) +{ + /* DBusConnection *connection = data; */ + + /* can return FALSE on OOM but we just let it fire again later */ + dbus_timeout_handle (timeout); +} + +static dbus_bool_t +add_connection_timeout (DBusTimeout *timeout, + void *data) +{ + DBusConnection *connection = data; + + return _dbus_loop_add_timeout (connection_get_loop (connection), + timeout, connection_timeout_callback, connection, NULL); +} + +static void +remove_connection_timeout (DBusTimeout *timeout, + void *data) +{ + DBusConnection *connection = data; + + _dbus_loop_remove_timeout (connection_get_loop (connection), + timeout, connection_timeout_callback, connection); +} + +static void +dispatch_status_function (DBusConnection *connection, + DBusDispatchStatus new_status, + void *data) +{ + DBusLoop *loop = data; + + if (new_status != DBUS_DISPATCH_COMPLETE) + { + while (!_dbus_loop_queue_dispatch (loop, connection)) + _dbus_wait_for_memory (); + } +} + +static dbus_bool_t +allow_unix_user_function (DBusConnection *connection, + unsigned long uid, + void *data) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + return bus_context_allow_unix_user (d->connections->context, uid); +} + +static void +free_connection_data (void *data) +{ + BusConnectionData *d = data; + + /* services_owned should be NULL since we should be disconnected */ + _dbus_assert (d->services_owned == NULL); + _dbus_assert (d->n_services_owned == 0); + /* similarly */ + _dbus_assert (d->transaction_messages == NULL); + + if (d->oom_preallocated) + dbus_connection_free_preallocated_send (d->connection, d->oom_preallocated); + + if (d->oom_message) + dbus_message_unref (d->oom_message); + + if (d->policy) + bus_client_policy_unref (d->policy); + + if (d->selinux_id) + bus_selinux_id_unref (d->selinux_id); + + dbus_free (d->cached_loginfo_string); + + dbus_free (d->name); + + dbus_free (d); +} + +static void +call_timeout_callback (DBusTimeout *timeout, + void *data) +{ + /* can return FALSE on OOM but we just let it fire again later */ + dbus_timeout_handle (timeout); +} + +BusConnections* +bus_connections_new (BusContext *context) +{ + BusConnections *connections; + + if (!dbus_connection_allocate_data_slot (&connection_data_slot)) + goto failed_0; + + connections = dbus_new0 (BusConnections, 1); + if (connections == NULL) + goto failed_1; + + connections->completed_by_user = _dbus_hash_table_new (DBUS_HASH_ULONG, + NULL, NULL); + if (connections->completed_by_user == NULL) + goto failed_2; + + connections->expire_timeout = _dbus_timeout_new (100, /* irrelevant */ + expire_incomplete_timeout, + connections, NULL); + if (connections->expire_timeout == NULL) + goto failed_3; + + _dbus_timeout_set_enabled (connections->expire_timeout, FALSE); + + connections->pending_replies = bus_expire_list_new (bus_context_get_loop (context), + bus_context_get_reply_timeout (context), + bus_pending_reply_expired, + connections); + if (connections->pending_replies == NULL) + goto failed_4; + + if (!_dbus_loop_add_timeout (bus_context_get_loop (context), + connections->expire_timeout, + call_timeout_callback, NULL, NULL)) + goto failed_5; + + connections->refcount = 1; + connections->context = context; + + return connections; + + failed_5: + bus_expire_list_free (connections->pending_replies); + failed_4: + _dbus_timeout_unref (connections->expire_timeout); + failed_3: + _dbus_hash_table_unref (connections->completed_by_user); + failed_2: + dbus_free (connections); + failed_1: + dbus_connection_free_data_slot (&connection_data_slot); + failed_0: + return NULL; +} + +BusConnections * +bus_connections_ref (BusConnections *connections) +{ + _dbus_assert (connections->refcount > 0); + connections->refcount += 1; + + return connections; +} + +void +bus_connections_unref (BusConnections *connections) +{ + _dbus_assert (connections->refcount > 0); + connections->refcount -= 1; + if (connections->refcount == 0) + { + /* drop all incomplete */ + while (connections->incomplete != NULL) + { + DBusConnection *connection; + + connection = connections->incomplete->data; + + dbus_connection_ref (connection); + dbus_connection_close (connection); + bus_connection_disconnected (connection); + dbus_connection_unref (connection); + } + + _dbus_assert (connections->n_incomplete == 0); + + /* drop all real connections */ + while (connections->completed != NULL) + { + DBusConnection *connection; + + connection = connections->completed->data; + + dbus_connection_ref (connection); + dbus_connection_close (connection); + bus_connection_disconnected (connection); + dbus_connection_unref (connection); + } + + _dbus_assert (connections->n_completed == 0); + + bus_expire_list_free (connections->pending_replies); + + _dbus_loop_remove_timeout (bus_context_get_loop (connections->context), + connections->expire_timeout, + call_timeout_callback, NULL); + + _dbus_timeout_unref (connections->expire_timeout); + + _dbus_hash_table_unref (connections->completed_by_user); + + dbus_free (connections); + + dbus_connection_free_data_slot (&connection_data_slot); + } +} + +/* Used for logging */ +static dbus_bool_t +cache_peer_loginfo_string (BusConnectionData *d, + DBusConnection *connection) +{ + DBusString loginfo_buf; + unsigned long uid; + unsigned long pid; + char *windows_sid; + dbus_bool_t prev_added; + + if (!_dbus_string_init (&loginfo_buf)) + return FALSE; + + prev_added = FALSE; + if (dbus_connection_get_unix_user (connection, &uid)) + { + if (!_dbus_string_append_printf (&loginfo_buf, "uid=%ld", uid)) + goto oom; + else + prev_added = TRUE; + } + + if (dbus_connection_get_unix_process_id (connection, &pid)) + { + if (prev_added) + { + if (!_dbus_string_append_byte (&loginfo_buf, ' ')) + goto oom; + } + if (!_dbus_string_append_printf (&loginfo_buf, "pid=%ld comm=\"", pid)) + goto oom; + /* Ignore errors here; we may not have permissions to read the + * proc file. */ + _dbus_command_for_pid (pid, &loginfo_buf, MAX_LOG_COMMAND_LEN, NULL); + if (!_dbus_string_append_byte (&loginfo_buf, '"')) + goto oom; + } + + if (dbus_connection_get_windows_user (connection, &windows_sid)) + { + if (!_dbus_string_append_printf (&loginfo_buf, "sid=\"%s\" ", windows_sid)) + goto oom; + dbus_free (windows_sid); + } + + if (!_dbus_string_steal_data (&loginfo_buf, &(d->cached_loginfo_string))) + goto oom; + + _dbus_string_free (&loginfo_buf); + + return TRUE; +oom: + _dbus_string_free (&loginfo_buf); + return FALSE; +} + +dbus_bool_t +bus_connections_setup_connection (BusConnections *connections, + DBusConnection *connection) +{ + + BusConnectionData *d; + dbus_bool_t retval; + DBusError error; + + + d = dbus_new0 (BusConnectionData, 1); + + if (d == NULL) + return FALSE; + + d->connections = connections; + d->connection = connection; + + _dbus_get_current_time (&d->connection_tv_sec, + &d->connection_tv_usec); + + _dbus_assert (connection_data_slot >= 0); + + if (!dbus_connection_set_data (connection, + connection_data_slot, + d, free_connection_data)) + { + dbus_free (d); + return FALSE; + } + + dbus_connection_set_route_peer_messages (connection, TRUE); + + retval = FALSE; + + dbus_error_init (&error); + d->selinux_id = bus_selinux_init_connection_id (connection, + &error); + if (dbus_error_is_set (&error)) + { + /* This is a bit bogus because we pretend all errors + * are OOM; this is done because we know that in bus.c + * an OOM error disconnects the connection, which is + * the same thing we want on any other error. + */ + dbus_error_free (&error); + goto out; + } + + if (!dbus_connection_set_watch_functions (connection, + add_connection_watch, + remove_connection_watch, + NULL, + connection, + NULL)) + goto out; + + if (!dbus_connection_set_timeout_functions (connection, + add_connection_timeout, + remove_connection_timeout, + NULL, + connection, NULL)) + goto out; + + /* For now we don't need to set a Windows user function because + * there are no policies in the config file controlling what + * Windows users can connect. The default 'same user that owns the + * bus can connect' behavior of DBusConnection is fine on Windows. + */ + dbus_connection_set_unix_user_function (connection, + allow_unix_user_function, + NULL, NULL); + + dbus_connection_set_dispatch_status_function (connection, + dispatch_status_function, + bus_context_get_loop (connections->context), + NULL); + + d->link_in_connection_list = _dbus_list_alloc_link (connection); + if (d->link_in_connection_list == NULL) + goto out; + + /* Setup the connection with the dispatcher */ + if (!bus_dispatch_add_connection (connection)) + goto out; + + if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE) + { + if (!_dbus_loop_queue_dispatch (bus_context_get_loop (connections->context), connection)) + { + bus_dispatch_remove_connection (connection); + goto out; + } + } + + _dbus_list_append_link (&connections->incomplete, d->link_in_connection_list); + connections->n_incomplete += 1; + + dbus_connection_ref (connection); + + /* Note that we might disconnect ourselves here, but it only takes + * effect on return to the main loop. We call this to free up + * expired connections if possible, and to queue the timeout for our + * own expiration. + */ + bus_connections_expire_incomplete (connections); + + /* And we might also disconnect ourselves here, but again it + * only takes effect on return to main loop. + */ + if (connections->n_incomplete > + bus_context_get_max_incomplete_connections (connections->context)) + { + _dbus_verbose ("Number of incomplete connections exceeds max, dropping oldest one\n"); + + _dbus_assert (connections->incomplete != NULL); + /* Disconnect the oldest unauthenticated connection. FIXME + * would it be more secure to drop a *random* connection? This + * algorithm seems to mean that if someone can create new + * connections quickly enough, they can keep anyone else from + * completing authentication. But random may or may not really + * help with that, a more elaborate solution might be required. + */ + dbus_connection_close (connections->incomplete->data); + } + + retval = TRUE; + + out: + if (!retval) + { + if (d->selinux_id) + bus_selinux_id_unref (d->selinux_id); + d->selinux_id = NULL; + + if (!dbus_connection_set_watch_functions (connection, + NULL, NULL, NULL, + connection, + NULL)) + _dbus_assert_not_reached ("setting watch functions to NULL failed"); + + if (!dbus_connection_set_timeout_functions (connection, + NULL, NULL, NULL, + connection, + NULL)) + _dbus_assert_not_reached ("setting timeout functions to NULL failed"); + + dbus_connection_set_unix_user_function (connection, + NULL, NULL, NULL); + + dbus_connection_set_windows_user_function (connection, + NULL, NULL, NULL); + + dbus_connection_set_dispatch_status_function (connection, + NULL, NULL, NULL); + + if (d->link_in_connection_list != NULL) + { + _dbus_assert (d->link_in_connection_list->next == NULL); + _dbus_assert (d->link_in_connection_list->prev == NULL); + _dbus_list_free_link (d->link_in_connection_list); + d->link_in_connection_list = NULL; + } + + if (!dbus_connection_set_data (connection, + connection_data_slot, + NULL, NULL)) + _dbus_assert_not_reached ("failed to set connection data to null"); + + /* "d" has now been freed */ + } + + return retval; +} + +void +bus_connections_expire_incomplete (BusConnections *connections) +{ + int next_interval; + + next_interval = -1; + + if (connections->incomplete != NULL) + { + long tv_sec, tv_usec; + DBusList *link; + int auth_timeout; + + _dbus_get_current_time (&tv_sec, &tv_usec); + auth_timeout = bus_context_get_auth_timeout (connections->context); + + link = _dbus_list_get_first_link (&connections->incomplete); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link); + DBusConnection *connection; + BusConnectionData *d; + double elapsed; + + connection = link->data; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + elapsed = ELAPSED_MILLISECONDS_SINCE (d->connection_tv_sec, + d->connection_tv_usec, + tv_sec, tv_usec); + + if (elapsed >= (double) auth_timeout) + { + _dbus_verbose ("Timing out authentication for connection %p\n", connection); + dbus_connection_close (connection); + } + else + { + /* We can end the loop, since the connections are in oldest-first order */ + next_interval = ((double)auth_timeout) - elapsed; + _dbus_verbose ("Connection %p authentication expires in %d milliseconds\n", + connection, next_interval); + + break; + } + + link = next; + } + } + + bus_expire_timeout_set_interval (connections->expire_timeout, + next_interval); +} + +static dbus_bool_t +expire_incomplete_timeout (void *data) +{ + BusConnections *connections = data; + + _dbus_verbose ("Running %s\n", _DBUS_FUNCTION_NAME); + + /* note that this may remove the timeout */ + bus_connections_expire_incomplete (connections); + + return TRUE; +} + +dbus_bool_t +bus_connection_get_unix_groups (DBusConnection *connection, + unsigned long **groups, + int *n_groups, + DBusError *error) +{ + BusConnectionData *d; + unsigned long uid; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + *groups = NULL; + *n_groups = 0; + + if (dbus_connection_get_unix_user (connection, &uid)) + { + if (!_dbus_unix_groups_from_uid (uid, groups, n_groups)) + { + _dbus_verbose ("Did not get any groups for UID %lu\n", + uid); + return FALSE; + } + else + { + _dbus_verbose ("Got %d groups for UID %lu\n", + *n_groups, uid); + return TRUE; + } + } + else + return TRUE; /* successfully got 0 groups */ +} + +dbus_bool_t +bus_connection_is_in_unix_group (DBusConnection *connection, + unsigned long gid) +{ + int i; + unsigned long *group_ids; + int n_group_ids; + + if (!bus_connection_get_unix_groups (connection, &group_ids, &n_group_ids, + NULL)) + return FALSE; + + i = 0; + while (i < n_group_ids) + { + if (group_ids[i] == gid) + { + dbus_free (group_ids); + return TRUE; + } + ++i; + } + + dbus_free (group_ids); + return FALSE; +} + +const char * +bus_connection_get_loginfo (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + if (!bus_connection_is_active (connection)) + return "inactive"; + return d->cached_loginfo_string; +} + +BusClientPolicy* +bus_connection_get_policy (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + _dbus_assert (d->policy != NULL); + + return d->policy; +} + +static dbus_bool_t +foreach_active (BusConnections *connections, + BusConnectionForeachFunction function, + void *data) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&connections->completed); + while (link != NULL) + { + DBusConnection *connection = link->data; + DBusList *next = _dbus_list_get_next_link (&connections->completed, link); + + if (!(* function) (connection, data)) + return FALSE; + + link = next; + } + + return TRUE; +} + +static dbus_bool_t +foreach_inactive (BusConnections *connections, + BusConnectionForeachFunction function, + void *data) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&connections->incomplete); + while (link != NULL) + { + DBusConnection *connection = link->data; + DBusList *next = _dbus_list_get_next_link (&connections->incomplete, link); + + if (!(* function) (connection, data)) + return FALSE; + + link = next; + } + + return TRUE; +} + +/** + * Calls function on each active connection; if the function returns + * #FALSE, stops iterating. Active connections are authenticated + * and have sent a Hello message. + * + * @param connections the connections object + * @param function the function + * @param data data to pass to it as a second arg + */ +void +bus_connections_foreach_active (BusConnections *connections, + BusConnectionForeachFunction function, + void *data) +{ + foreach_active (connections, function, data); +} + +/** + * Calls function on each connection; if the function returns + * #FALSE, stops iterating. + * + * @param connections the connections object + * @param function the function + * @param data data to pass to it as a second arg + */ +void +bus_connections_foreach (BusConnections *connections, + BusConnectionForeachFunction function, + void *data) +{ + if (!foreach_active (connections, function, data)) + return; + + foreach_inactive (connections, function, data); +} + +BusContext* +bus_connections_get_context (BusConnections *connections) +{ + return connections->context; +} + +/* + * This is used to avoid covering the same connection twice when + * traversing connections. Note that it assumes we will + * bus_connection_mark_stamp() each connection at least once per + * INT_MAX increments of the global stamp, or wraparound would break + * things. + */ +void +bus_connections_increment_stamp (BusConnections *connections) +{ + connections->stamp += 1; +} + +/* Mark connection with current stamp, return TRUE if it + * didn't already have that stamp + */ +dbus_bool_t +bus_connection_mark_stamp (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + if (d->stamp == d->connections->stamp) + return FALSE; + else + { + d->stamp = d->connections->stamp; + return TRUE; + } +} + +BusContext* +bus_connection_get_context (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + return d->connections->context; +} + +BusConnections* +bus_connection_get_connections (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + return d->connections; +} + +BusRegistry* +bus_connection_get_registry (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + return bus_context_get_registry (d->connections->context); +} + +BusActivation* +bus_connection_get_activation (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + return bus_context_get_activation (d->connections->context); +} + +BusMatchmaker* +bus_connection_get_matchmaker (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + return bus_context_get_matchmaker (d->connections->context); +} + +BusSELinuxID* +bus_connection_get_selinux_id (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + return d->selinux_id; +} + +/** + * Checks whether the connection is registered with the message bus. + * + * @param connection the connection + * @returns #TRUE if we're an active message bus participant + */ +dbus_bool_t +bus_connection_is_active (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + return d != NULL && d->name != NULL; +} + +dbus_bool_t +bus_connection_preallocate_oom_error (DBusConnection *connection) +{ + DBusMessage *message; + DBusPreallocatedSend *preallocated; + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + if (d->oom_preallocated != NULL) + return TRUE; + + preallocated = dbus_connection_preallocate_send (connection); + if (preallocated == NULL) + return FALSE; + + message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); + + if (message == NULL) + { + dbus_connection_free_preallocated_send (connection, preallocated); + return FALSE; + } + + /* d->name may be NULL, but that is OK */ + if (!dbus_message_set_error_name (message, DBUS_ERROR_NO_MEMORY) || + !dbus_message_set_destination (message, d->name) || + !dbus_message_set_sender (message, + DBUS_SERVICE_DBUS)) + { + dbus_connection_free_preallocated_send (connection, preallocated); + dbus_message_unref (message); + return FALSE; + } + + /* set reply serial to placeholder value just so space is already allocated + * for it. + */ + if (!dbus_message_set_reply_serial (message, 14)) + { + dbus_connection_free_preallocated_send (connection, preallocated); + dbus_message_unref (message); + return FALSE; + } + + d->oom_message = message; + d->oom_preallocated = preallocated; + + return TRUE; +} + +void +bus_connection_send_oom_error (DBusConnection *connection, + DBusMessage *in_reply_to) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + _dbus_assert (d->oom_message != NULL); + + /* should always succeed since we set it to a placeholder earlier */ + if (!dbus_message_set_reply_serial (d->oom_message, + dbus_message_get_serial (in_reply_to))) + _dbus_assert_not_reached ("Failed to set reply serial for preallocated oom message"); + + _dbus_assert (dbus_message_get_sender (d->oom_message) != NULL); + + dbus_connection_send_preallocated (connection, d->oom_preallocated, + d->oom_message, NULL); + + dbus_message_unref (d->oom_message); + d->oom_message = NULL; + d->oom_preallocated = NULL; +} + +void +bus_connection_add_match_rule_link (DBusConnection *connection, + DBusList *link) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + _dbus_list_append_link (&d->match_rules, link); + + d->n_match_rules += 1; +} + +dbus_bool_t +bus_connection_add_match_rule (DBusConnection *connection, + BusMatchRule *rule) +{ + DBusList *link; + + link = _dbus_list_alloc_link (rule); + + if (link == NULL) + return FALSE; + + bus_connection_add_match_rule_link (connection, link); + + return TRUE; +} + +void +bus_connection_remove_match_rule (DBusConnection *connection, + BusMatchRule *rule) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + _dbus_list_remove_last (&d->match_rules, rule); + + d->n_match_rules -= 1; + _dbus_assert (d->n_match_rules >= 0); +} + +int +bus_connection_get_n_match_rules (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + return d->n_match_rules; +} + +void +bus_connection_add_owned_service_link (DBusConnection *connection, + DBusList *link) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + _dbus_list_append_link (&d->services_owned, link); + + d->n_services_owned += 1; +} + +dbus_bool_t +bus_connection_add_owned_service (DBusConnection *connection, + BusService *service) +{ + DBusList *link; + + link = _dbus_list_alloc_link (service); + + if (link == NULL) + return FALSE; + + bus_connection_add_owned_service_link (connection, link); + + return TRUE; +} + +void +bus_connection_remove_owned_service (DBusConnection *connection, + BusService *service) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + _dbus_list_remove_last (&d->services_owned, service); + + d->n_services_owned -= 1; + _dbus_assert (d->n_services_owned >= 0); +} + +int +bus_connection_get_n_services_owned (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + return d->n_services_owned; +} + +dbus_bool_t +bus_connection_complete (DBusConnection *connection, + const DBusString *name, + DBusError *error) +{ + BusConnectionData *d; + unsigned long uid; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + _dbus_assert (d->name == NULL); + _dbus_assert (d->policy == NULL); + + _dbus_assert (!bus_connection_is_active (connection)); + + if (!_dbus_string_copy_data (name, &d->name)) + { + BUS_SET_OOM (error); + return FALSE; + } + + _dbus_assert (d->name != NULL); + + _dbus_verbose ("Name %s assigned to %p\n", d->name, connection); + + d->policy = bus_context_create_client_policy (d->connections->context, + connection, + error); + + /* we may have a NULL policy on OOM or error getting list of + * groups for a user. In the latter case we don't handle it so + * well currently, as it will just keep failing over and over. + */ + + if (d->policy == NULL) + { + _dbus_verbose ("Failed to create security policy for connection %p\n", + connection); + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_free (d->name); + d->name = NULL; + return FALSE; + } + + if (dbus_connection_get_unix_user (connection, &uid)) + { + if (!adjust_connections_for_uid (d->connections, + uid, 1)) + goto fail; + } + + /* Create and cache a string which holds information about the + * peer process; used for logging purposes. + */ + if (!cache_peer_loginfo_string (d, connection)) + goto fail; + + /* Now the connection is active, move it between lists */ + _dbus_list_unlink (&d->connections->incomplete, + d->link_in_connection_list); + d->connections->n_incomplete -= 1; + _dbus_list_append_link (&d->connections->completed, + d->link_in_connection_list); + d->connections->n_completed += 1; + + _dbus_assert (d->connections->n_incomplete >= 0); + _dbus_assert (d->connections->n_completed > 0); + + /* See if we can remove the timeout */ + bus_connections_expire_incomplete (d->connections); + + _dbus_assert (bus_connection_is_active (connection)); + + return TRUE; +fail: + BUS_SET_OOM (error); + dbus_free (d->name); + d->name = NULL; + if (d->policy) + bus_client_policy_unref (d->policy); + d->policy = NULL; + return FALSE; +} + +const char * +bus_connection_get_name (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + return d->name; +} + +/** + * Check whether completing the passed-in connection would + * exceed limits, and if so set error and return #FALSE + */ +dbus_bool_t +bus_connections_check_limits (BusConnections *connections, + DBusConnection *requesting_completion, + DBusError *error) +{ + BusConnectionData *d; + unsigned long uid; + + d = BUS_CONNECTION_DATA (requesting_completion); + _dbus_assert (d != NULL); + + _dbus_assert (d->name == NULL); + + if (connections->n_completed >= + bus_context_get_max_completed_connections (connections->context)) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "The maximum number of active connections has been reached"); + return FALSE; + } + + if (dbus_connection_get_unix_user (requesting_completion, &uid)) + { + if (get_connections_for_uid (connections, uid) >= + bus_context_get_max_connections_per_user (connections->context)) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "The maximum number of active connections for UID %lu has been reached", + uid); + return FALSE; + } + } + + return TRUE; +} + +static void +bus_pending_reply_free (BusPendingReply *pending) +{ + _dbus_verbose ("Freeing pending reply %p, replier %p receiver %p serial %u\n", + pending, + pending->will_send_reply, + pending->will_get_reply, + pending->reply_serial); + + dbus_free (pending); +} + +static dbus_bool_t +bus_pending_reply_send_no_reply (BusConnections *connections, + BusTransaction *transaction, + BusPendingReply *pending) +{ + DBusMessage *message; + DBusMessageIter iter; + dbus_bool_t retval; + const char *errmsg; + + retval = FALSE; + + message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); + if (message == NULL) + return FALSE; + + dbus_message_set_no_reply (message, TRUE); + + if (!dbus_message_set_reply_serial (message, + pending->reply_serial)) + goto out; + + if (!dbus_message_set_error_name (message, + DBUS_ERROR_NO_REPLY)) + goto out; + + errmsg = "Message did not receive a reply (timeout by message bus)"; + dbus_message_iter_init_append (message, &iter); + if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &errmsg)) + goto out; + + if (!bus_transaction_send_from_driver (transaction, pending->will_get_reply, + message)) + goto out; + + retval = TRUE; + + out: + dbus_message_unref (message); + return retval; +} + +static dbus_bool_t +bus_pending_reply_expired (BusExpireList *list, + DBusList *link, + void *data) +{ + BusPendingReply *pending = link->data; + BusConnections *connections = data; + BusTransaction *transaction; + + /* No reply is forthcoming. So nuke it if we can. If not, + * leave it in the list to try expiring again later when we + * get more memory. + */ + + _dbus_verbose ("Expiring pending reply %p, replier %p receiver %p serial %u\n", + pending, + pending->will_send_reply, + pending->will_get_reply, + pending->reply_serial); + + transaction = bus_transaction_new (connections->context); + if (transaction == NULL) + return FALSE; + + if (!bus_pending_reply_send_no_reply (connections, + transaction, + pending)) + { + bus_transaction_cancel_and_free (transaction); + return FALSE; + } + + bus_expire_list_remove_link (connections->pending_replies, link); + + bus_pending_reply_free (pending); + bus_transaction_execute_and_free (transaction); + + return TRUE; +} + +static void +bus_connection_drop_pending_replies (BusConnections *connections, + DBusConnection *connection) +{ + /* The DBusConnection is almost 100% finalized here, so you can't + * do anything with it except check for pointer equality + */ + DBusList *link; + + _dbus_verbose ("Dropping pending replies that involve connection %p\n", + connection); + + link = bus_expire_list_get_first_link (connections->pending_replies); + while (link != NULL) + { + DBusList *next; + BusPendingReply *pending; + + next = bus_expire_list_get_next_link (connections->pending_replies, + link); + pending = link->data; + + if (pending->will_get_reply == connection) + { + /* We don't need to track this pending reply anymore */ + + _dbus_verbose ("Dropping pending reply %p, replier %p receiver %p serial %u\n", + pending, + pending->will_send_reply, + pending->will_get_reply, + pending->reply_serial); + + bus_expire_list_remove_link (connections->pending_replies, + link); + bus_pending_reply_free (pending); + } + else if (pending->will_send_reply == connection) + { + /* The reply isn't going to be sent, so set things + * up so it will be expired right away + */ + _dbus_verbose ("Will expire pending reply %p, replier %p receiver %p serial %u\n", + pending, + pending->will_send_reply, + pending->will_get_reply, + pending->reply_serial); + + pending->will_send_reply = NULL; + pending->expire_item.added_tv_sec = 0; + pending->expire_item.added_tv_usec = 0; + + bus_expire_list_recheck_immediately (connections->pending_replies); + } + + link = next; + } +} + + +typedef struct +{ + BusPendingReply *pending; + BusConnections *connections; +} CancelPendingReplyData; + +static void +cancel_pending_reply (void *data) +{ + CancelPendingReplyData *d = data; + + _dbus_verbose ("%s: d = %p\n", _DBUS_FUNCTION_NAME, d); + + if (!bus_expire_list_remove (d->connections->pending_replies, + &d->pending->expire_item)) + _dbus_assert_not_reached ("pending reply did not exist to be cancelled"); + + bus_pending_reply_free (d->pending); /* since it's been cancelled */ +} + +static void +cancel_pending_reply_data_free (void *data) +{ + CancelPendingReplyData *d = data; + + _dbus_verbose ("%s: d = %p\n", _DBUS_FUNCTION_NAME, d); + + /* d->pending should be either freed or still + * in the list of pending replies (owned by someone + * else) + */ + + dbus_free (d); +} + +/* + * Record that a reply is allowed; return TRUE on success. + */ +dbus_bool_t +bus_connections_expect_reply (BusConnections *connections, + BusTransaction *transaction, + DBusConnection *will_get_reply, + DBusConnection *will_send_reply, + DBusMessage *reply_to_this, + DBusError *error) +{ + BusPendingReply *pending; + dbus_uint32_t reply_serial; + DBusList *link; + CancelPendingReplyData *cprd; + int count; + + _dbus_assert (will_get_reply != NULL); + _dbus_assert (will_send_reply != NULL); + _dbus_assert (reply_to_this != NULL); + + if (dbus_message_get_no_reply (reply_to_this)) + return TRUE; /* we won't allow a reply, since client doesn't care for one. */ + + reply_serial = dbus_message_get_serial (reply_to_this); + + link = bus_expire_list_get_first_link (connections->pending_replies); + count = 0; + while (link != NULL) + { + pending = link->data; + + if (pending->reply_serial == reply_serial && + pending->will_get_reply == will_get_reply && + pending->will_send_reply == will_send_reply) + { + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Message has the same reply serial as a currently-outstanding existing method call"); + return FALSE; + } + + link = bus_expire_list_get_next_link (connections->pending_replies, + link); + if (pending->will_get_reply == will_get_reply) + ++count; + } + + if (count >= + bus_context_get_max_replies_per_connection (connections->context)) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "The maximum number of pending replies per connection has been reached"); + return FALSE; + } + + pending = dbus_new0 (BusPendingReply, 1); + if (pending == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + +#ifdef DBUS_ENABLE_VERBOSE_MODE + /* so we can see a not-yet-added pending reply */ + pending->expire_item.added_tv_sec = 1; + pending->expire_item.added_tv_usec = 1; +#endif + + pending->will_get_reply = will_get_reply; + pending->will_send_reply = will_send_reply; + pending->reply_serial = reply_serial; + + cprd = dbus_new0 (CancelPendingReplyData, 1); + if (cprd == NULL) + { + BUS_SET_OOM (error); + bus_pending_reply_free (pending); + return FALSE; + } + + if (!bus_expire_list_add (connections->pending_replies, + &pending->expire_item)) + { + BUS_SET_OOM (error); + dbus_free (cprd); + bus_pending_reply_free (pending); + return FALSE; + } + + if (!bus_transaction_add_cancel_hook (transaction, + cancel_pending_reply, + cprd, + cancel_pending_reply_data_free)) + { + BUS_SET_OOM (error); + bus_expire_list_remove (connections->pending_replies, &pending->expire_item); + dbus_free (cprd); + bus_pending_reply_free (pending); + return FALSE; + } + + cprd->pending = pending; + cprd->connections = connections; + + _dbus_get_current_time (&pending->expire_item.added_tv_sec, + &pending->expire_item.added_tv_usec); + + _dbus_verbose ("Added pending reply %p, replier %p receiver %p serial %u\n", + pending, + pending->will_send_reply, + pending->will_get_reply, + pending->reply_serial); + + return TRUE; +} + +typedef struct +{ + DBusList *link; + BusConnections *connections; +} CheckPendingReplyData; + +static void +cancel_check_pending_reply (void *data) +{ + CheckPendingReplyData *d = data; + + _dbus_verbose ("%s: d = %p\n", _DBUS_FUNCTION_NAME, d); + + bus_expire_list_add_link (d->connections->pending_replies, + d->link); + d->link = NULL; +} + +static void +check_pending_reply_data_free (void *data) +{ + CheckPendingReplyData *d = data; + + _dbus_verbose ("%s: d = %p\n", _DBUS_FUNCTION_NAME, d); + + if (d->link != NULL) + { + BusPendingReply *pending = d->link->data; + + _dbus_assert (!bus_expire_list_contains_item (d->connections->pending_replies, + &pending->expire_item)); + + bus_pending_reply_free (pending); + _dbus_list_free_link (d->link); + } + + dbus_free (d); +} + +/* + * Check whether a reply is allowed, remove BusPendingReply + * if so, return TRUE if so. + */ +dbus_bool_t +bus_connections_check_reply (BusConnections *connections, + BusTransaction *transaction, + DBusConnection *sending_reply, + DBusConnection *receiving_reply, + DBusMessage *reply, + DBusError *error) +{ + CheckPendingReplyData *cprd; + DBusList *link; + dbus_uint32_t reply_serial; + + _dbus_assert (sending_reply != NULL); + _dbus_assert (receiving_reply != NULL); + + reply_serial = dbus_message_get_reply_serial (reply); + + link = bus_expire_list_get_first_link (connections->pending_replies); + while (link != NULL) + { + BusPendingReply *pending = link->data; + + if (pending->reply_serial == reply_serial && + pending->will_get_reply == receiving_reply && + pending->will_send_reply == sending_reply) + { + _dbus_verbose ("Found pending reply with serial %u\n", reply_serial); + break; + } + + link = bus_expire_list_get_next_link (connections->pending_replies, + link); + } + + if (link == NULL) + { + _dbus_verbose ("No pending reply expected\n"); + + return FALSE; + } + + cprd = dbus_new0 (CheckPendingReplyData, 1); + if (cprd == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_transaction_add_cancel_hook (transaction, + cancel_check_pending_reply, + cprd, + check_pending_reply_data_free)) + { + BUS_SET_OOM (error); + dbus_free (cprd); + return FALSE; + } + + cprd->link = link; + cprd->connections = connections; + + bus_expire_list_unlink (connections->pending_replies, + link); + + _dbus_assert (!bus_expire_list_contains_item (connections->pending_replies, link->data)); + + return TRUE; +} + +/* + * Transactions + * + * Note that this is fairly fragile; in particular, don't try to use + * one transaction across any main loop iterations. + */ + +typedef struct +{ + BusTransaction *transaction; + DBusMessage *message; + DBusPreallocatedSend *preallocated; +} MessageToSend; + +typedef struct +{ + BusTransactionCancelFunction cancel_function; + DBusFreeFunction free_data_function; + void *data; +} CancelHook; + +struct BusTransaction +{ + DBusList *connections; + BusContext *context; + DBusList *cancel_hooks; +}; + +static void +message_to_send_free (DBusConnection *connection, + MessageToSend *to_send) +{ + if (to_send->message) + dbus_message_unref (to_send->message); + + if (to_send->preallocated) + dbus_connection_free_preallocated_send (connection, to_send->preallocated); + + dbus_free (to_send); +} + +static void +cancel_hook_cancel (void *element, + void *data) +{ + CancelHook *ch = element; + + _dbus_verbose ("Running transaction cancel hook\n"); + + if (ch->cancel_function) + (* ch->cancel_function) (ch->data); +} + +static void +cancel_hook_free (void *element, + void *data) +{ + CancelHook *ch = element; + + if (ch->free_data_function) + (* ch->free_data_function) (ch->data); + + dbus_free (ch); +} + +static void +free_cancel_hooks (BusTransaction *transaction) +{ + _dbus_list_foreach (&transaction->cancel_hooks, + cancel_hook_free, NULL); + + _dbus_list_clear (&transaction->cancel_hooks); +} + +BusTransaction* +bus_transaction_new (BusContext *context) +{ + BusTransaction *transaction; + + transaction = dbus_new0 (BusTransaction, 1); + if (transaction == NULL) + return NULL; + + transaction->context = context; + + return transaction; +} + +BusContext* +bus_transaction_get_context (BusTransaction *transaction) +{ + return transaction->context; +} + +BusConnections* +bus_transaction_get_connections (BusTransaction *transaction) +{ + return bus_context_get_connections (transaction->context); +} + +dbus_bool_t +bus_transaction_send_from_driver (BusTransaction *transaction, + DBusConnection *connection, + DBusMessage *message) +{ + /* We have to set the sender to the driver, and have + * to check security policy since it was not done in + * dispatch.c + */ + _dbus_verbose ("Sending %s %s %s from driver\n", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(no interface)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(no member)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(no error name)"); + + if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) + return FALSE; + + if (bus_connection_is_active (connection)) + { + if (!dbus_message_set_destination (message, + bus_connection_get_name (connection))) + return FALSE; + } + + /* bus driver never wants a reply */ + dbus_message_set_no_reply (message, TRUE); + + /* If security policy doesn't allow the message, we silently + * eat it; the driver doesn't care about getting a reply. + */ + if (!bus_context_check_security_policy (bus_transaction_get_context (transaction), + transaction, + NULL, connection, connection, message, NULL)) + return TRUE; + + return bus_transaction_send (transaction, connection, message); +} + +dbus_bool_t +bus_transaction_send (BusTransaction *transaction, + DBusConnection *connection, + DBusMessage *message) +{ + MessageToSend *to_send; + BusConnectionData *d; + DBusList *link; + + _dbus_verbose (" trying to add %s interface=%s member=%s error=%s to transaction%s\n", + dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? "error" : + dbus_message_get_reply_serial (message) != 0 ? "reply" : + "message", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + dbus_connection_get_is_connected (connection) ? + "" : " (disconnected)"); + + _dbus_assert (dbus_message_get_sender (message) != NULL); + + if (!dbus_connection_get_is_connected (connection)) + return TRUE; /* silently ignore disconnected connections */ + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + to_send = dbus_new (MessageToSend, 1); + if (to_send == NULL) + { + return FALSE; + } + + to_send->preallocated = dbus_connection_preallocate_send (connection); + if (to_send->preallocated == NULL) + { + dbus_free (to_send); + return FALSE; + } + + dbus_message_ref (message); + to_send->message = message; + to_send->transaction = transaction; + + _dbus_verbose ("about to prepend message\n"); + + if (!_dbus_list_prepend (&d->transaction_messages, to_send)) + { + message_to_send_free (connection, to_send); + return FALSE; + } + + _dbus_verbose ("prepended message\n"); + + /* See if we already had this connection in the list + * for this transaction. If we have a pending message, + * then we should already be in transaction->connections + */ + link = _dbus_list_get_first_link (&d->transaction_messages); + _dbus_assert (link->data == to_send); + link = _dbus_list_get_next_link (&d->transaction_messages, link); + while (link != NULL) + { + MessageToSend *m = link->data; + DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link); + + if (m->transaction == transaction) + break; + + link = next; + } + + if (link == NULL) + { + if (!_dbus_list_prepend (&transaction->connections, connection)) + { + _dbus_list_remove (&d->transaction_messages, to_send); + message_to_send_free (connection, to_send); + return FALSE; + } + } + + return TRUE; +} + +static void +connection_cancel_transaction (DBusConnection *connection, + BusTransaction *transaction) +{ + DBusList *link; + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + link = _dbus_list_get_first_link (&d->transaction_messages); + while (link != NULL) + { + MessageToSend *m = link->data; + DBusList *next = _dbus_list_get_next_link (&d->transaction_messages, link); + + if (m->transaction == transaction) + { + _dbus_list_remove_link (&d->transaction_messages, + link); + + message_to_send_free (connection, m); + } + + link = next; + } +} + +void +bus_transaction_cancel_and_free (BusTransaction *transaction) +{ + DBusConnection *connection; + + _dbus_verbose ("TRANSACTION: cancelled\n"); + + while ((connection = _dbus_list_pop_first (&transaction->connections))) + connection_cancel_transaction (connection, transaction); + + _dbus_assert (transaction->connections == NULL); + + _dbus_list_foreach (&transaction->cancel_hooks, + cancel_hook_cancel, NULL); + + free_cancel_hooks (transaction); + + dbus_free (transaction); +} + +static void +connection_execute_transaction (DBusConnection *connection, + BusTransaction *transaction) +{ + DBusList *link; + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + /* Send the queue in order (FIFO) */ + link = _dbus_list_get_last_link (&d->transaction_messages); + while (link != NULL) + { + MessageToSend *m = link->data; + DBusList *prev = _dbus_list_get_prev_link (&d->transaction_messages, link); + + if (m->transaction == transaction) + { + _dbus_list_remove_link (&d->transaction_messages, + link); + + _dbus_assert (dbus_message_get_sender (m->message) != NULL); + + dbus_connection_send_preallocated (connection, + m->preallocated, + m->message, + NULL); + + m->preallocated = NULL; /* so we don't double-free it */ + + message_to_send_free (connection, m); + } + + link = prev; + } +} + +void +bus_transaction_execute_and_free (BusTransaction *transaction) +{ + /* For each connection in transaction->connections + * send the messages + */ + DBusConnection *connection; + + _dbus_verbose ("TRANSACTION: executing\n"); + + while ((connection = _dbus_list_pop_first (&transaction->connections))) + connection_execute_transaction (connection, transaction); + + _dbus_assert (transaction->connections == NULL); + + free_cancel_hooks (transaction); + + dbus_free (transaction); +} + +static void +bus_connection_remove_transactions (DBusConnection *connection) +{ + MessageToSend *to_send; + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + _dbus_assert (d != NULL); + + while ((to_send = _dbus_list_get_first (&d->transaction_messages))) + { + /* only has an effect for the first MessageToSend listing this transaction */ + _dbus_list_remove (&to_send->transaction->connections, + connection); + + _dbus_list_remove (&d->transaction_messages, to_send); + message_to_send_free (connection, to_send); + } +} + +/** + * Converts the DBusError to a message reply + */ +dbus_bool_t +bus_transaction_send_error_reply (BusTransaction *transaction, + DBusConnection *connection, + const DBusError *error, + DBusMessage *in_reply_to) +{ + DBusMessage *reply; + + _dbus_assert (error != NULL); + _DBUS_ASSERT_ERROR_IS_SET (error); + + _dbus_verbose ("Sending error reply %s \"%s\"\n", + error->name, error->message); + + reply = dbus_message_new_error (in_reply_to, + error->name, + error->message); + if (reply == NULL) + return FALSE; + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + { + dbus_message_unref (reply); + return FALSE; + } + + dbus_message_unref (reply); + + return TRUE; +} + +dbus_bool_t +bus_transaction_add_cancel_hook (BusTransaction *transaction, + BusTransactionCancelFunction cancel_function, + void *data, + DBusFreeFunction free_data_function) +{ + CancelHook *ch; + + ch = dbus_new (CancelHook, 1); + if (ch == NULL) + return FALSE; + + _dbus_verbose (" adding cancel hook function = %p data = %p\n", + cancel_function, data); + + ch->cancel_function = cancel_function; + ch->data = data; + ch->free_data_function = free_data_function; + + /* It's important that the hooks get run in reverse order that they + * were added + */ + if (!_dbus_list_prepend (&transaction->cancel_hooks, ch)) + { + dbus_free (ch); + return FALSE; + } + + return TRUE; +} diff --git a/bus/connection.h b/bus/connection.h new file mode 100644 index 00000000..4b9a754b --- /dev/null +++ b/bus/connection.h @@ -0,0 +1,141 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* connection.h Client connections + * + * Copyright (C) 2003, 2004 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_CONNECTION_H +#define BUS_CONNECTION_H + +#include +#include +#include "bus.h" + +typedef dbus_bool_t (* BusConnectionForeachFunction) (DBusConnection *connection, + void *data); + + +BusConnections* bus_connections_new (BusContext *context); +BusConnections* bus_connections_ref (BusConnections *connections); +void bus_connections_unref (BusConnections *connections); +dbus_bool_t bus_connections_setup_connection (BusConnections *connections, + DBusConnection *connection); +void bus_connections_foreach (BusConnections *connections, + BusConnectionForeachFunction function, + void *data); +void bus_connections_foreach_active (BusConnections *connections, + BusConnectionForeachFunction function, + void *data); +BusContext* bus_connections_get_context (BusConnections *connections); +void bus_connections_increment_stamp (BusConnections *connections); +BusContext* bus_connection_get_context (DBusConnection *connection); +BusConnections* bus_connection_get_connections (DBusConnection *connection); +BusRegistry* bus_connection_get_registry (DBusConnection *connection); +BusActivation* bus_connection_get_activation (DBusConnection *connection); +BusMatchmaker* bus_connection_get_matchmaker (DBusConnection *connection); +const char * bus_connection_get_loginfo (DBusConnection *connection); +BusSELinuxID* bus_connection_get_selinux_id (DBusConnection *connection); +dbus_bool_t bus_connections_check_limits (BusConnections *connections, + DBusConnection *requesting_completion, + DBusError *error); +void bus_connections_expire_incomplete (BusConnections *connections); + +dbus_bool_t bus_connections_expect_reply (BusConnections *connections, + BusTransaction *transaction, + DBusConnection *will_get_reply, + DBusConnection *will_send_reply, + DBusMessage *reply_to_this, + DBusError *error); +dbus_bool_t bus_connections_check_reply (BusConnections *connections, + BusTransaction *transaction, + DBusConnection *sending_reply, + DBusConnection *receiving_reply, + DBusMessage *reply, + DBusError *error); + +dbus_bool_t bus_connection_mark_stamp (DBusConnection *connection); + +dbus_bool_t bus_connection_is_active (DBusConnection *connection); +const char *bus_connection_get_name (DBusConnection *connection); + +dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection); +void bus_connection_send_oom_error (DBusConnection *connection, + DBusMessage *in_reply_to); + +/* called by signals.c */ +dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection, + BusMatchRule *rule); +void bus_connection_add_match_rule_link (DBusConnection *connection, + DBusList *link); +void bus_connection_remove_match_rule (DBusConnection *connection, + BusMatchRule *rule); +int bus_connection_get_n_match_rules (DBusConnection *connection); + + +/* called by services.c */ +dbus_bool_t bus_connection_add_owned_service (DBusConnection *connection, + BusService *service); +void bus_connection_remove_owned_service (DBusConnection *connection, + BusService *service); +void bus_connection_add_owned_service_link (DBusConnection *connection, + DBusList *link); +int bus_connection_get_n_services_owned (DBusConnection *connection); + +/* called by driver.c */ +dbus_bool_t bus_connection_complete (DBusConnection *connection, + const DBusString *name, + DBusError *error); + +/* called by dispatch.c when the connection is dropped */ +void bus_connection_disconnected (DBusConnection *connection); + +dbus_bool_t bus_connection_is_in_unix_group (DBusConnection *connection, + unsigned long gid); +dbus_bool_t bus_connection_get_unix_groups (DBusConnection *connection, + unsigned long **groups, + int *n_groups, + DBusError *error); +BusClientPolicy* bus_connection_get_policy (DBusConnection *connection); + +/* transaction API so we can send or not send a block of messages as a whole */ + +typedef void (* BusTransactionCancelFunction) (void *data); + +BusTransaction* bus_transaction_new (BusContext *context); +BusContext* bus_transaction_get_context (BusTransaction *transaction); +BusConnections* bus_transaction_get_connections (BusTransaction *transaction); +dbus_bool_t bus_transaction_send (BusTransaction *transaction, + DBusConnection *connection, + DBusMessage *message); +dbus_bool_t bus_transaction_send_from_driver (BusTransaction *transaction, + DBusConnection *connection, + DBusMessage *message); +dbus_bool_t bus_transaction_send_error_reply (BusTransaction *transaction, + DBusConnection *connection, + const DBusError *error, + DBusMessage *in_reply_to); +void bus_transaction_cancel_and_free (BusTransaction *transaction); +void bus_transaction_execute_and_free (BusTransaction *transaction); +dbus_bool_t bus_transaction_add_cancel_hook (BusTransaction *transaction, + BusTransactionCancelFunction cancel_function, + void *data, + DBusFreeFunction free_data_function); + +#endif /* BUS_CONNECTION_H */ diff --git a/bus/dbus-daemon.1 b/bus/dbus-daemon.1 new file mode 100644 index 00000000..6bfca148 --- /dev/null +++ b/bus/dbus-daemon.1 @@ -0,0 +1,760 @@ +.\" +.\" dbus-daemon manual page. +.\" Copyright (C) 2003,2008 Red Hat, Inc. +.\" +.TH dbus-daemon 1 +.SH NAME +dbus-daemon \- Message bus daemon +.SH SYNOPSIS +.PP +.B dbus-daemon +dbus-daemon [\-\-version] [\-\-session] [\-\-system] [\-\-config-file=FILE] +[\-\-print-address[=DESCRIPTOR]] [\-\-print-pid[=DESCRIPTOR]] [\-\-fork] + +.SH DESCRIPTION + +\fIdbus-daemon\fP is the D-Bus message bus daemon. See +http://www.freedesktop.org/software/dbus/ for more information about +the big picture. D-Bus is first a library that provides one-to-one +communication between any two applications; \fIdbus-daemon\fP is an +application that uses this library to implement a message bus +daemon. Multiple programs connect to the message bus daemon and can +exchange messages with one another. + +.PP +There are two standard message bus instances: the systemwide message bus +(installed on many systems as the "messagebus" init service) and the +per-user-login-session message bus (started each time a user logs in). +\fIdbus-daemon\fP is used for both of these instances, but with +a different configuration file. + +.PP +The \-\-session option is equivalent to +"\-\-config-file=/src/build/dbus/etc/dbus-1/session.conf" and the \-\-system +option is equivalent to +"\-\-config-file=/src/build/dbus/etc/dbus-1/system.conf". By creating +additional configuration files and using the \-\-config-file option, +additional special-purpose message bus daemons could be created. + +.PP +The systemwide daemon is normally launched by an init script, +standardly called simply "messagebus". + +.PP +The systemwide daemon is largely used for broadcasting system events, +such as changes to the printer queue, or adding/removing devices. + +.PP +The per-session daemon is used for various interprocess communication +among desktop applications (however, it is not tied to X or the GUI +in any way). + +.PP +SIGHUP will cause the D-Bus daemon to PARTIALLY reload its +configuration file and to flush its user/group information caches. Some +configuration changes would require kicking all apps off the bus; so they will +only take effect if you restart the daemon. Policy changes should take effect +with SIGHUP. + +.SH OPTIONS +The following options are supported: +.TP +.I "--config-file=FILE" +Use the given configuration file. +.TP +.I "--fork" +Force the message bus to fork and become a daemon, even if +the configuration file does not specify that it should. +In most contexts the configuration file already gets this +right, though. +.TP +.I "--print-address[=DESCRIPTOR]" +Print the address of the message bus to standard output, or +to the given file descriptor. This is used by programs that +launch the message bus. +.TP +.I "--print-pid[=DESCRIPTOR]" +Print the process ID of the message bus to standard output, or +to the given file descriptor. This is used by programs that +launch the message bus. +.TP +.I "--session" +Use the standard configuration file for the per-login-session message +bus. +.TP +.I "--system" +Use the standard configuration file for the systemwide message bus. +.TP +.I "--version" +Print the version of the daemon. + +.SH CONFIGURATION FILE + +A message bus daemon has a configuration file that specializes it +for a particular application. For example, one configuration +file might set up the message bus to be a systemwide message bus, +while another might set it up to be a per-user-login-session bus. + +.PP +The configuration file also establishes resource limits, security +parameters, and so forth. + +.PP +The configuration file is not part of any interoperability +specification and its backward compatibility is not guaranteed; this +document is documentation, not specification. + +.PP +The standard systemwide and per-session message bus setups are +configured in the files "/src/build/dbus/etc/dbus-1/system.conf" and +"/src/build/dbus/etc/dbus-1/session.conf". These files normally + a system-local.conf or session-local.conf; you can put local +overrides in those files to avoid modifying the primary configuration +files. + +.PP +The configuration file is an XML document. It must have the following +doctype declaration: +.nf + + + +.fi + +.PP +The following elements may be present in the configuration file. + +.TP +.I "" + +.PP +Root element. + +.TP +.I "" + +.PP +The well-known type of the message bus. Currently known values are +"system" and "session"; if other values are set, they should be +either added to the D-Bus specification, or namespaced. The last + element "wins" (previous values are ignored). This element +only controls which message bus specific environment variables are +set in activated clients. Most of the policy that distinguishes a +session bus from the system bus is controlled from the other elements +in the configuration file. + +.PP +If the well-known type of the message bus is "session", then the +DBUS_STARTER_BUS_TYPE environment variable will be set to "session" +and the DBUS_SESSION_BUS_ADDRESS environment variable will be set +to the address of the session bus. Likewise, if the type of the +message bus is "system", then the DBUS_STARTER_BUS_TYPE environment +variable will be set to "system" and the DBUS_SESSION_BUS_ADDRESS +environment variable will be set to the address of the system bus +(which is normally well known anyway). + +.PP +Example: session + +.TP +.I "" + +.PP +Include a file filename.conf at this point. If the +filename is relative, it is located relative to the configuration file +doing the including. + +.PP + has an optional attribute "ignore_missing=(yes|no)" +which defaults to "no" if not provided. This attribute +controls whether it's a fatal error for the included file +to be absent. + +.TP +.I "" + +.PP +Include all files in foo.d at this +point. Files in the directory are included in undefined order. +Only files ending in ".conf" are included. + +.PP +This is intended to allow extension of the system bus by particular +packages. For example, if CUPS wants to be able to send out +notification of printer queue changes, it could install a file to +/src/build/dbus/etc/dbus-1/system.d that allowed all apps to receive +this message and allowed the printer daemon user to send it. + +.TP +.I "" + +.PP +The user account the daemon should run as, as either a username or a +UID. If the daemon cannot change to this UID on startup, it will exit. +If this element is not present, the daemon will not change or care +about its UID. + +.PP +The last entry in the file "wins", the others are ignored. + +.PP +The user is changed after the bus has completed initialization. So +sockets etc. will be created before changing user, but no data will be +read from clients before changing user. This means that sockets +and PID files can be created in a location that requires root +privileges for writing. + +.TP +.I "" + +.PP +If present, the bus daemon becomes a real daemon (forks +into the background, etc.). This is generally used +rather than the \-\-fork command line option. + +.TP +.I "" + +.PP +If present, the bus daemon keeps its original umask when forking. +This may be useful to avoid affecting the behavior of child processes. + +.TP +.I "" + +.PP +Add an address that the bus should listen on. The +address is in the standard D-Bus format that contains +a transport name plus possible parameters/options. + +.PP +Example: unix:path=/tmp/foo + +.PP +Example: tcp:host=localhost,port=1234 + +.PP +If there are multiple elements, then the bus listens +on multiple addresses. The bus will pass its address to +started services or other interested parties with +the last address given in first. That is, +apps will try to connect to the last address first. + +.PP +tcp sockets can accept IPv4 addresses, IPv6 addresses or hostnames. +If a hostname resolves to multiple addresses, the server will bind +to all of them. The family=ipv4 or family=ipv6 options can be used +to force it to bind to a subset of addresses + +.PP +Example: tcp:host=localhost,port=0,family=ipv4 + +.PP +A special case is using a port number of zero (or omitting the port), +which means to choose an available port selected by the operating +system. The port number chosen can be obtained with the +--print-address command line parameter and will be present in other +cases where the server reports its own address, such as when +DBUS_SESSION_BUS_ADDRESS is set. + +.PP +Example: tcp:host=localhost,port=0 + +.PP +tcp addresses also allow a bind=hostname option, which will override +the host option specifying what address to bind to, without changing +the address reported by the bus. The bind option can also take a +special name '*' to cause the bus to listen on all local address +(INADDR_ANY). The specified host should be a valid name of the local +machine or weird stuff will happen. + +.PP +Example: tcp:host=localhost,bind=*,port=0 + +.TP +.I "" + +.PP +Lists permitted authorization mechanisms. If this element doesn't +exist, then all known mechanisms are allowed. If there are multiple + elements, all the listed mechanisms are allowed. The order in +which mechanisms are listed is not meaningful. + +.PP +Example: EXTERNAL + +.PP +Example: DBUS_COOKIE_SHA1 + +.TP +.I "" + +.PP +Adds a directory to scan for .service files. Directories are +scanned starting with the last to appear in the config file +(the first .service file found that provides a particular +service will be used). + +.PP +Service files tell the bus how to automatically start a program. +They are primarily used with the per-user-session bus, +not the systemwide bus. + +.TP +.I "" + +.PP + is equivalent to specifying a series +of elements for each of the data directories in the "XDG +Base Directory Specification" with the subdirectory "dbus-1/services", +so for example "/usr/share/dbus-1/services" would be among the +directories searched. + +.PP +The "XDG Base Directory Specification" can be found at +http://freedesktop.org/wiki/Standards/basedir-spec if it hasn't moved, +otherwise try your favorite search engine. + +.PP +The option is only relevant to the +per-user-session bus daemon defined in +/src/build/dbus/etc/dbus-1/session.conf. Putting it in any other +configuration file would probably be nonsense. + +.TP +.I "" + +.PP + specifies the standard system-wide +activation directories that should be searched for service files. +This option defaults to /src/build/dbus/share/dbus-1/system-services. + +.PP +The option is only relevant to the +per-system bus daemon defined in +/src/build/dbus/etc/dbus-1/system.conf. Putting it in any other +configuration file would probably be nonsense. + +.TP +.I "" + +.PP + specifies the setuid helper that is used to launch +system daemons with an alternate user. Typically this should be +the dbus-daemon-launch-helper executable in located in libexec. + +.PP +The option is only relevant to the per-system bus daemon +defined in /src/build/dbus/etc/dbus-1/system.conf. Putting it in any other +configuration file would probably be nonsense. + +.TP +.I "" + +.PP + establishes a resource limit. For example: +.nf + 64 + 512 +.fi + +.PP +The name attribute is mandatory. +Available limit names are: +.nf + "max_incoming_bytes" : total size in bytes of messages + incoming from a single connection + "max_outgoing_bytes" : total size in bytes of messages + queued up for a single connection + "max_message_size" : max size of a single message in + bytes + "service_start_timeout" : milliseconds (thousandths) until + a started service has to connect + "auth_timeout" : milliseconds (thousandths) a + connection is given to + authenticate + "max_completed_connections" : max number of authenticated connections + "max_incomplete_connections" : max number of unauthenticated + connections + "max_connections_per_user" : max number of completed connections from + the same user + "max_pending_service_starts" : max number of service launches in + progress at the same time + "max_names_per_connection" : max number of names a single + connection can own + "max_match_rules_per_connection": max number of match rules for a single + connection + "max_replies_per_connection" : max number of pending method + replies per connection + (number of calls-in-progress) + "reply_timeout" : milliseconds (thousandths) + until a method call times out +.fi + +.PP +The max incoming/outgoing queue sizes allow a new message to be queued +if one byte remains below the max. So you can in fact exceed the max +by max_message_size. + +.PP +max_completed_connections divided by max_connections_per_user is the +number of users that can work together to denial-of-service all other users by using +up all connections on the systemwide bus. + +.PP +Limits are normally only of interest on the systemwide bus, not the user session +buses. + +.TP +.I "" + +.PP +The element defines a security policy to be applied to a particular +set of connections to the bus. A policy is made up of + and elements. Policies are normally used with the systemwide bus; +they are analogous to a firewall in that they allow expected traffic +and prevent unexpected traffic. + +.PP +Currently, the system bus has a default-deny policy for sending method calls +and owning bus names. Everything else, in particular reply messages, receive +checks, and signals has a default allow policy. + +.PP +In general, it is best to keep system services as small, targeted programs which +run in their own process and provide a single bus name. Then, all that is needed +is an rule for the "own" permission to let the process claim the bus +name, and a "send_destination" rule to allow traffic from some or all uids to +your service. + +.PP +The element has one of four attributes: +daemon.1.in +.nf + context="(default|mandatory)" + at_console="(true|false)" + user="username or userid" + group="group name or gid" +.fi + +.PP +Policies are applied to a connection as follows: +.nf + - all context="default" policies are applied + - all group="connection's user's group" policies are applied + in undefined order + - all user="connection's auth user" policies are applied + in undefined order + - all at_console="true" policies are applied + - all at_console="false" policies are applied + - all context="mandatory" policies are applied +.fi + +.PP +Policies applied later will override those applied earlier, +when the policies overlap. Multiple policies with the same +user/group/context are applied in the order they appear +in the config file. + +.TP +.I "" +.I "" + +.PP +A element appears below a element and prohibits some +action. The element makes an exception to previous +statements, and works just like but with the inverse meaning. + +.PP +The possible attributes of these elements are: +.nf + send_interface="interface_name" + send_member="method_or_signal_name" + send_error="error_name" + send_destination="name" + send_type="method_call" | "method_return" | "signal" | "error" + send_path="/path/name" + + receive_interface="interface_name" + receive_member="method_or_signal_name" + receive_error="error_name" + receive_sender="name" + receive_type="method_call" | "method_return" | "signal" | "error" + receive_path="/path/name" + + send_requested_reply="true" | "false" + receive_requested_reply="true" | "false" + + eavesdrop="true" | "false" + + own="name" + user="username" + group="groupname" +.fi + +.PP +Examples: +.nf + + + + + + + +.fi + +.PP +The element's attributes determine whether the deny "matches" a +particular action. If it matches, the action is denied (unless later +rules in the config file allow it). + +.PP +send_destination and receive_sender rules mean that messages may not be +sent to or received from the *owner* of the given name, not that +they may not be sent *to that name*. That is, if a connection +owns services A, B, C, and sending to A is denied, sending to B or C +will not work either. + +.PP +The other send_* and receive_* attributes are purely textual/by-value +matches against the given field in the message header. + +.PP +"Eavesdropping" occurs when an application receives a message that +was explicitly addressed to a name the application does not own, or +is a reply to such a message. Eavesdropping thus only applies to +messages that are addressed to services and replies to such messages +(i.e. it does not apply to signals). + +.PP +For , eavesdrop="true" indicates that the rule matches even +when eavesdropping. eavesdrop="false" is the default and means that +the rule only allows messages to go to their specified recipient. +For , eavesdrop="true" indicates that the rule matches +only when eavesdropping. eavesdrop="false" is the default for +also, but here it means that the rule applies always, even when +not eavesdropping. The eavesdrop attribute can only be combined with +send and receive rules (with send_* and receive_* attributes). + + +.PP +The [send|receive]_requested_reply attribute works similarly to the eavesdrop +attribute. It controls whether the or matches a reply +that is expected (corresponds to a previous method call message). +This attribute only makes sense for reply messages (errors and method +returns), and is ignored for other message types. + +.PP +For , [send|receive]_requested_reply="true" is the default and indicates that +only requested replies are allowed by the +rule. [send|receive]_requested_reply="false" means that the rule allows any reply +even if unexpected. + +.PP +For , [send|receive]_requested_reply="false" is the default but indicates that +the rule matches only when the reply was not +requested. [send|receive]_requested_reply="true" indicates that the rule applies +always, regardless of pending reply state. + +.PP +user and group denials mean that the given user or group may +not connect to the message bus. + +.PP +For "name", "username", "groupname", etc. +the character "*" can be substituted, meaning "any." Complex globs +like "foo.bar.*" aren't allowed for now because they'd be work to +implement and maybe encourage sloppy security anyway. + +.PP +It does not make sense to deny a user or group inside a +for a user or group; user/group denials can only be inside +context="default" or context="mandatory" policies. + +.PP +A single rule may specify combinations of attributes such as +send_destination and send_interface and send_type. In this case, the +denial applies only if both attributes match the message being denied. +e.g. would +deny messages with the given interface AND the given bus name. +To get an OR effect you specify multiple rules. + +.PP +You can't include both send_ and receive_ attributes on the same +rule, since "whether the message can be sent" and "whether it can be +received" are evaluated separately. + +.PP +Be careful with send_interface/receive_interface, because the +interface field in messages is optional. In particular, do NOT +specify ! This will cause +no-interface messages to be blocked for all services, which is +almost certainly not what you intended. Always use rules of +the form: + +.TP +.I "" + +.PP +The element contains settings related to Security Enhanced Linux. +More details below. + +.TP +.I "" + +.PP +An element appears below an element and +creates a mapping. Right now only one kind of association is possible: +.nf + +.fi + +.PP +This means that if a connection asks to own the name +"org.freedesktop.Foobar" then the source context will be the context +of the connection and the target context will be "foo_t" - see the +short discussion of SELinux below. + +.PP +Note, the context here is the target context when requesting a name, +NOT the context of the connection owning the name. + +.PP +There's currently no way to set a default for owning any name, if +we add this syntax it will look like: +.nf + +.fi +If you find a reason this is useful, let the developers know. +Right now the default will be the security context of the bus itself. + +.PP +If two elements specify the same name, the element +appearing later in the configuration file will be used. + +.SH SELinux + +.PP +See http://www.nsa.gov/selinux/ for full details on SELinux. Some useful excerpts: + +.IP "" 8 +Every subject (process) and object (e.g. file, socket, IPC object, +etc) in the system is assigned a collection of security attributes, +known as a security context. A security context contains all of the +security attributes associated with a particular subject or object +that are relevant to the security policy. + +.IP "" 8 +In order to better encapsulate security contexts and to provide +greater efficiency, the policy enforcement code of SELinux typically +handles security identifiers (SIDs) rather than security contexts. A +SID is an integer that is mapped by the security server to a security +context at runtime. + +.IP "" 8 +When a security decision is required, the policy enforcement code +passes a pair of SIDs (typically the SID of a subject and the SID of +an object, but sometimes a pair of subject SIDs or a pair of object +SIDs), and an object security class to the security server. The object +security class indicates the kind of object, e.g. a process, a regular +file, a directory, a TCP socket, etc. + +.IP "" 8 +Access decisions specify whether or not a permission is granted for a +given pair of SIDs and class. Each object class has a set of +associated permissions defined to control operations on objects with +that class. + +.PP +D-Bus performs SELinux security checks in two places. + +.PP +First, any time a message is routed from one connection to another +connection, the bus daemon will check permissions with the security context of +the first connection as source, security context of the second connection +as target, object class "dbus" and requested permission "send_msg". + +.PP +If a security context is not available for a connection +(impossible when using UNIX domain sockets), then the target +context used is the context of the bus daemon itself. +There is currently no way to change this default, because we're +assuming that only UNIX domain sockets will be used to +connect to the systemwide bus. If this changes, we'll +probably add a way to set the default connection context. + +.PP +Second, any time a connection asks to own a name, +the bus daemon will check permissions with the security +context of the connection as source, the security context specified +for the name in the config file as target, object +class "dbus" and requested permission "acquire_svc". + +.PP +The security context for a bus name is specified with the + element described earlier in this document. +If a name has no security context associated in the +configuration file, the security context of the bus daemon +itself will be used. + +.SH DEBUGGING + +.PP +If you're trying to figure out where your messages are going or why +you aren't getting messages, there are several things you can try. + +.PP +Remember that the system bus is heavily locked down and if you +haven't installed a security policy file to allow your message +through, it won't work. For the session bus, this is not a concern. + +.PP +The simplest way to figure out what's happening on the bus is to run +the \fIdbus-monitor\fP program, which comes with the D-Bus +package. You can also send test messages with \fIdbus-send\fP. These +programs have their own man pages. + +.PP +If you want to know what the daemon itself is doing, you might consider +running a separate copy of the daemon to test against. This will allow you +to put the daemon under a debugger, or run it with verbose output, without +messing up your real session and system daemons. + +.PP +To run a separate test copy of the daemon, for example you might open a terminal +and type: +.nf + DBUS_VERBOSE=1 dbus-daemon --session --print-address +.fi + +.PP +The test daemon address will be printed when the daemon starts. You will need +to copy-and-paste this address and use it as the value of the +DBUS_SESSION_BUS_ADDRESS environment variable when you launch the applications +you want to test. This will cause those applications to connect to your +test bus instead of the DBUS_SESSION_BUS_ADDRESS of your real session bus. + +.PP +DBUS_VERBOSE=1 will have NO EFFECT unless your copy of D-Bus +was compiled with verbose mode enabled. This is not recommended in +production builds due to performance impact. You may need to rebuild +D-Bus if your copy was not built with debugging in mind. (DBUS_VERBOSE +also affects the D-Bus library and thus applications using D-Bus; it may +be useful to see verbose output on both the client side and from the daemon.) + +.PP +If you want to get fancy, you can create a custom bus +configuration for your test bus (see the session.conf and system.conf +files that define the two default configurations for example). This +would allow you to specify a different directory for .service files, +for example. + + +.SH AUTHOR +See http://www.freedesktop.org/software/dbus/doc/AUTHORS + +.SH BUGS +Please send bug reports to the D-Bus mailing list or bug tracker, +see http://www.freedesktop.org/software/dbus/ diff --git a/bus/dbus-daemon.1.in b/bus/dbus-daemon.1.in new file mode 100644 index 00000000..8342600e --- /dev/null +++ b/bus/dbus-daemon.1.in @@ -0,0 +1,760 @@ +.\" +.\" dbus-daemon manual page. +.\" Copyright (C) 2003,2008 Red Hat, Inc. +.\" +.TH dbus-daemon 1 +.SH NAME +dbus-daemon \- Message bus daemon +.SH SYNOPSIS +.PP +.B dbus-daemon +dbus-daemon [\-\-version] [\-\-session] [\-\-system] [\-\-config-file=FILE] +[\-\-print-address[=DESCRIPTOR]] [\-\-print-pid[=DESCRIPTOR]] [\-\-fork] + +.SH DESCRIPTION + +\fIdbus-daemon\fP is the D-Bus message bus daemon. See +http://www.freedesktop.org/software/dbus/ for more information about +the big picture. D-Bus is first a library that provides one-to-one +communication between any two applications; \fIdbus-daemon\fP is an +application that uses this library to implement a message bus +daemon. Multiple programs connect to the message bus daemon and can +exchange messages with one another. + +.PP +There are two standard message bus instances: the systemwide message bus +(installed on many systems as the "messagebus" init service) and the +per-user-login-session message bus (started each time a user logs in). +\fIdbus-daemon\fP is used for both of these instances, but with +a different configuration file. + +.PP +The \-\-session option is equivalent to +"\-\-config-file=@EXPANDED_SYSCONFDIR@/dbus-1/session.conf" and the \-\-system +option is equivalent to +"\-\-config-file=@EXPANDED_SYSCONFDIR@/dbus-1/system.conf". By creating +additional configuration files and using the \-\-config-file option, +additional special-purpose message bus daemons could be created. + +.PP +The systemwide daemon is normally launched by an init script, +standardly called simply "messagebus". + +.PP +The systemwide daemon is largely used for broadcasting system events, +such as changes to the printer queue, or adding/removing devices. + +.PP +The per-session daemon is used for various interprocess communication +among desktop applications (however, it is not tied to X or the GUI +in any way). + +.PP +SIGHUP will cause the D-Bus daemon to PARTIALLY reload its +configuration file and to flush its user/group information caches. Some +configuration changes would require kicking all apps off the bus; so they will +only take effect if you restart the daemon. Policy changes should take effect +with SIGHUP. + +.SH OPTIONS +The following options are supported: +.TP +.I "--config-file=FILE" +Use the given configuration file. +.TP +.I "--fork" +Force the message bus to fork and become a daemon, even if +the configuration file does not specify that it should. +In most contexts the configuration file already gets this +right, though. +.TP +.I "--print-address[=DESCRIPTOR]" +Print the address of the message bus to standard output, or +to the given file descriptor. This is used by programs that +launch the message bus. +.TP +.I "--print-pid[=DESCRIPTOR]" +Print the process ID of the message bus to standard output, or +to the given file descriptor. This is used by programs that +launch the message bus. +.TP +.I "--session" +Use the standard configuration file for the per-login-session message +bus. +.TP +.I "--system" +Use the standard configuration file for the systemwide message bus. +.TP +.I "--version" +Print the version of the daemon. + +.SH CONFIGURATION FILE + +A message bus daemon has a configuration file that specializes it +for a particular application. For example, one configuration +file might set up the message bus to be a systemwide message bus, +while another might set it up to be a per-user-login-session bus. + +.PP +The configuration file also establishes resource limits, security +parameters, and so forth. + +.PP +The configuration file is not part of any interoperability +specification and its backward compatibility is not guaranteed; this +document is documentation, not specification. + +.PP +The standard systemwide and per-session message bus setups are +configured in the files "@EXPANDED_SYSCONFDIR@/dbus-1/system.conf" and +"@EXPANDED_SYSCONFDIR@/dbus-1/session.conf". These files normally + a system-local.conf or session-local.conf; you can put local +overrides in those files to avoid modifying the primary configuration +files. + +.PP +The configuration file is an XML document. It must have the following +doctype declaration: +.nf + + + +.fi + +.PP +The following elements may be present in the configuration file. + +.TP +.I "" + +.PP +Root element. + +.TP +.I "" + +.PP +The well-known type of the message bus. Currently known values are +"system" and "session"; if other values are set, they should be +either added to the D-Bus specification, or namespaced. The last + element "wins" (previous values are ignored). This element +only controls which message bus specific environment variables are +set in activated clients. Most of the policy that distinguishes a +session bus from the system bus is controlled from the other elements +in the configuration file. + +.PP +If the well-known type of the message bus is "session", then the +DBUS_STARTER_BUS_TYPE environment variable will be set to "session" +and the DBUS_SESSION_BUS_ADDRESS environment variable will be set +to the address of the session bus. Likewise, if the type of the +message bus is "system", then the DBUS_STARTER_BUS_TYPE environment +variable will be set to "system" and the DBUS_SESSION_BUS_ADDRESS +environment variable will be set to the address of the system bus +(which is normally well known anyway). + +.PP +Example: session + +.TP +.I "" + +.PP +Include a file filename.conf at this point. If the +filename is relative, it is located relative to the configuration file +doing the including. + +.PP + has an optional attribute "ignore_missing=(yes|no)" +which defaults to "no" if not provided. This attribute +controls whether it's a fatal error for the included file +to be absent. + +.TP +.I "" + +.PP +Include all files in foo.d at this +point. Files in the directory are included in undefined order. +Only files ending in ".conf" are included. + +.PP +This is intended to allow extension of the system bus by particular +packages. For example, if CUPS wants to be able to send out +notification of printer queue changes, it could install a file to +@EXPANDED_SYSCONFDIR@/dbus-1/system.d that allowed all apps to receive +this message and allowed the printer daemon user to send it. + +.TP +.I "" + +.PP +The user account the daemon should run as, as either a username or a +UID. If the daemon cannot change to this UID on startup, it will exit. +If this element is not present, the daemon will not change or care +about its UID. + +.PP +The last entry in the file "wins", the others are ignored. + +.PP +The user is changed after the bus has completed initialization. So +sockets etc. will be created before changing user, but no data will be +read from clients before changing user. This means that sockets +and PID files can be created in a location that requires root +privileges for writing. + +.TP +.I "" + +.PP +If present, the bus daemon becomes a real daemon (forks +into the background, etc.). This is generally used +rather than the \-\-fork command line option. + +.TP +.I "" + +.PP +If present, the bus daemon keeps its original umask when forking. +This may be useful to avoid affecting the behavior of child processes. + +.TP +.I "" + +.PP +Add an address that the bus should listen on. The +address is in the standard D-Bus format that contains +a transport name plus possible parameters/options. + +.PP +Example: unix:path=/tmp/foo + +.PP +Example: tcp:host=localhost,port=1234 + +.PP +If there are multiple elements, then the bus listens +on multiple addresses. The bus will pass its address to +started services or other interested parties with +the last address given in first. That is, +apps will try to connect to the last address first. + +.PP +tcp sockets can accept IPv4 addresses, IPv6 addresses or hostnames. +If a hostname resolves to multiple addresses, the server will bind +to all of them. The family=ipv4 or family=ipv6 options can be used +to force it to bind to a subset of addresses + +.PP +Example: tcp:host=localhost,port=0,family=ipv4 + +.PP +A special case is using a port number of zero (or omitting the port), +which means to choose an available port selected by the operating +system. The port number chosen can be obtained with the +--print-address command line parameter and will be present in other +cases where the server reports its own address, such as when +DBUS_SESSION_BUS_ADDRESS is set. + +.PP +Example: tcp:host=localhost,port=0 + +.PP +tcp addresses also allow a bind=hostname option, which will override +the host option specifying what address to bind to, without changing +the address reported by the bus. The bind option can also take a +special name '*' to cause the bus to listen on all local address +(INADDR_ANY). The specified host should be a valid name of the local +machine or weird stuff will happen. + +.PP +Example: tcp:host=localhost,bind=*,port=0 + +.TP +.I "" + +.PP +Lists permitted authorization mechanisms. If this element doesn't +exist, then all known mechanisms are allowed. If there are multiple + elements, all the listed mechanisms are allowed. The order in +which mechanisms are listed is not meaningful. + +.PP +Example: EXTERNAL + +.PP +Example: DBUS_COOKIE_SHA1 + +.TP +.I "" + +.PP +Adds a directory to scan for .service files. Directories are +scanned starting with the last to appear in the config file +(the first .service file found that provides a particular +service will be used). + +.PP +Service files tell the bus how to automatically start a program. +They are primarily used with the per-user-session bus, +not the systemwide bus. + +.TP +.I "" + +.PP + is equivalent to specifying a series +of elements for each of the data directories in the "XDG +Base Directory Specification" with the subdirectory "dbus-1/services", +so for example "/usr/share/dbus-1/services" would be among the +directories searched. + +.PP +The "XDG Base Directory Specification" can be found at +http://freedesktop.org/wiki/Standards/basedir-spec if it hasn't moved, +otherwise try your favorite search engine. + +.PP +The option is only relevant to the +per-user-session bus daemon defined in +@EXPANDED_SYSCONFDIR@/dbus-1/session.conf. Putting it in any other +configuration file would probably be nonsense. + +.TP +.I "" + +.PP + specifies the standard system-wide +activation directories that should be searched for service files. +This option defaults to @EXPANDED_DATADIR@/dbus-1/system-services. + +.PP +The option is only relevant to the +per-system bus daemon defined in +@EXPANDED_SYSCONFDIR@/dbus-1/system.conf. Putting it in any other +configuration file would probably be nonsense. + +.TP +.I "" + +.PP + specifies the setuid helper that is used to launch +system daemons with an alternate user. Typically this should be +the dbus-daemon-launch-helper executable in located in libexec. + +.PP +The option is only relevant to the per-system bus daemon +defined in @EXPANDED_SYSCONFDIR@/dbus-1/system.conf. Putting it in any other +configuration file would probably be nonsense. + +.TP +.I "" + +.PP + establishes a resource limit. For example: +.nf + 64 + 512 +.fi + +.PP +The name attribute is mandatory. +Available limit names are: +.nf + "max_incoming_bytes" : total size in bytes of messages + incoming from a single connection + "max_outgoing_bytes" : total size in bytes of messages + queued up for a single connection + "max_message_size" : max size of a single message in + bytes + "service_start_timeout" : milliseconds (thousandths) until + a started service has to connect + "auth_timeout" : milliseconds (thousandths) a + connection is given to + authenticate + "max_completed_connections" : max number of authenticated connections + "max_incomplete_connections" : max number of unauthenticated + connections + "max_connections_per_user" : max number of completed connections from + the same user + "max_pending_service_starts" : max number of service launches in + progress at the same time + "max_names_per_connection" : max number of names a single + connection can own + "max_match_rules_per_connection": max number of match rules for a single + connection + "max_replies_per_connection" : max number of pending method + replies per connection + (number of calls-in-progress) + "reply_timeout" : milliseconds (thousandths) + until a method call times out +.fi + +.PP +The max incoming/outgoing queue sizes allow a new message to be queued +if one byte remains below the max. So you can in fact exceed the max +by max_message_size. + +.PP +max_completed_connections divided by max_connections_per_user is the +number of users that can work together to denial-of-service all other users by using +up all connections on the systemwide bus. + +.PP +Limits are normally only of interest on the systemwide bus, not the user session +buses. + +.TP +.I "" + +.PP +The element defines a security policy to be applied to a particular +set of connections to the bus. A policy is made up of + and elements. Policies are normally used with the systemwide bus; +they are analogous to a firewall in that they allow expected traffic +and prevent unexpected traffic. + +.PP +Currently, the system bus has a default-deny policy for sending method calls +and owning bus names. Everything else, in particular reply messages, receive +checks, and signals has a default allow policy. + +.PP +In general, it is best to keep system services as small, targeted programs which +run in their own process and provide a single bus name. Then, all that is needed +is an rule for the "own" permission to let the process claim the bus +name, and a "send_destination" rule to allow traffic from some or all uids to +your service. + +.PP +The element has one of four attributes: +daemon.1.in +.nf + context="(default|mandatory)" + at_console="(true|false)" + user="username or userid" + group="group name or gid" +.fi + +.PP +Policies are applied to a connection as follows: +.nf + - all context="default" policies are applied + - all group="connection's user's group" policies are applied + in undefined order + - all user="connection's auth user" policies are applied + in undefined order + - all at_console="true" policies are applied + - all at_console="false" policies are applied + - all context="mandatory" policies are applied +.fi + +.PP +Policies applied later will override those applied earlier, +when the policies overlap. Multiple policies with the same +user/group/context are applied in the order they appear +in the config file. + +.TP +.I "" +.I "" + +.PP +A element appears below a element and prohibits some +action. The element makes an exception to previous +statements, and works just like but with the inverse meaning. + +.PP +The possible attributes of these elements are: +.nf + send_interface="interface_name" + send_member="method_or_signal_name" + send_error="error_name" + send_destination="name" + send_type="method_call" | "method_return" | "signal" | "error" + send_path="/path/name" + + receive_interface="interface_name" + receive_member="method_or_signal_name" + receive_error="error_name" + receive_sender="name" + receive_type="method_call" | "method_return" | "signal" | "error" + receive_path="/path/name" + + send_requested_reply="true" | "false" + receive_requested_reply="true" | "false" + + eavesdrop="true" | "false" + + own="name" + user="username" + group="groupname" +.fi + +.PP +Examples: +.nf + + + + + + + +.fi + +.PP +The element's attributes determine whether the deny "matches" a +particular action. If it matches, the action is denied (unless later +rules in the config file allow it). + +.PP +send_destination and receive_sender rules mean that messages may not be +sent to or received from the *owner* of the given name, not that +they may not be sent *to that name*. That is, if a connection +owns services A, B, C, and sending to A is denied, sending to B or C +will not work either. + +.PP +The other send_* and receive_* attributes are purely textual/by-value +matches against the given field in the message header. + +.PP +"Eavesdropping" occurs when an application receives a message that +was explicitly addressed to a name the application does not own, or +is a reply to such a message. Eavesdropping thus only applies to +messages that are addressed to services and replies to such messages +(i.e. it does not apply to signals). + +.PP +For , eavesdrop="true" indicates that the rule matches even +when eavesdropping. eavesdrop="false" is the default and means that +the rule only allows messages to go to their specified recipient. +For , eavesdrop="true" indicates that the rule matches +only when eavesdropping. eavesdrop="false" is the default for +also, but here it means that the rule applies always, even when +not eavesdropping. The eavesdrop attribute can only be combined with +send and receive rules (with send_* and receive_* attributes). + + +.PP +The [send|receive]_requested_reply attribute works similarly to the eavesdrop +attribute. It controls whether the or matches a reply +that is expected (corresponds to a previous method call message). +This attribute only makes sense for reply messages (errors and method +returns), and is ignored for other message types. + +.PP +For , [send|receive]_requested_reply="true" is the default and indicates that +only requested replies are allowed by the +rule. [send|receive]_requested_reply="false" means that the rule allows any reply +even if unexpected. + +.PP +For , [send|receive]_requested_reply="false" is the default but indicates that +the rule matches only when the reply was not +requested. [send|receive]_requested_reply="true" indicates that the rule applies +always, regardless of pending reply state. + +.PP +user and group denials mean that the given user or group may +not connect to the message bus. + +.PP +For "name", "username", "groupname", etc. +the character "*" can be substituted, meaning "any." Complex globs +like "foo.bar.*" aren't allowed for now because they'd be work to +implement and maybe encourage sloppy security anyway. + +.PP +It does not make sense to deny a user or group inside a +for a user or group; user/group denials can only be inside +context="default" or context="mandatory" policies. + +.PP +A single rule may specify combinations of attributes such as +send_destination and send_interface and send_type. In this case, the +denial applies only if both attributes match the message being denied. +e.g. would +deny messages with the given interface AND the given bus name. +To get an OR effect you specify multiple rules. + +.PP +You can't include both send_ and receive_ attributes on the same +rule, since "whether the message can be sent" and "whether it can be +received" are evaluated separately. + +.PP +Be careful with send_interface/receive_interface, because the +interface field in messages is optional. In particular, do NOT +specify ! This will cause +no-interface messages to be blocked for all services, which is +almost certainly not what you intended. Always use rules of +the form: + +.TP +.I "" + +.PP +The element contains settings related to Security Enhanced Linux. +More details below. + +.TP +.I "" + +.PP +An element appears below an element and +creates a mapping. Right now only one kind of association is possible: +.nf + +.fi + +.PP +This means that if a connection asks to own the name +"org.freedesktop.Foobar" then the source context will be the context +of the connection and the target context will be "foo_t" - see the +short discussion of SELinux below. + +.PP +Note, the context here is the target context when requesting a name, +NOT the context of the connection owning the name. + +.PP +There's currently no way to set a default for owning any name, if +we add this syntax it will look like: +.nf + +.fi +If you find a reason this is useful, let the developers know. +Right now the default will be the security context of the bus itself. + +.PP +If two elements specify the same name, the element +appearing later in the configuration file will be used. + +.SH SELinux + +.PP +See http://www.nsa.gov/selinux/ for full details on SELinux. Some useful excerpts: + +.IP "" 8 +Every subject (process) and object (e.g. file, socket, IPC object, +etc) in the system is assigned a collection of security attributes, +known as a security context. A security context contains all of the +security attributes associated with a particular subject or object +that are relevant to the security policy. + +.IP "" 8 +In order to better encapsulate security contexts and to provide +greater efficiency, the policy enforcement code of SELinux typically +handles security identifiers (SIDs) rather than security contexts. A +SID is an integer that is mapped by the security server to a security +context at runtime. + +.IP "" 8 +When a security decision is required, the policy enforcement code +passes a pair of SIDs (typically the SID of a subject and the SID of +an object, but sometimes a pair of subject SIDs or a pair of object +SIDs), and an object security class to the security server. The object +security class indicates the kind of object, e.g. a process, a regular +file, a directory, a TCP socket, etc. + +.IP "" 8 +Access decisions specify whether or not a permission is granted for a +given pair of SIDs and class. Each object class has a set of +associated permissions defined to control operations on objects with +that class. + +.PP +D-Bus performs SELinux security checks in two places. + +.PP +First, any time a message is routed from one connection to another +connection, the bus daemon will check permissions with the security context of +the first connection as source, security context of the second connection +as target, object class "dbus" and requested permission "send_msg". + +.PP +If a security context is not available for a connection +(impossible when using UNIX domain sockets), then the target +context used is the context of the bus daemon itself. +There is currently no way to change this default, because we're +assuming that only UNIX domain sockets will be used to +connect to the systemwide bus. If this changes, we'll +probably add a way to set the default connection context. + +.PP +Second, any time a connection asks to own a name, +the bus daemon will check permissions with the security +context of the connection as source, the security context specified +for the name in the config file as target, object +class "dbus" and requested permission "acquire_svc". + +.PP +The security context for a bus name is specified with the + element described earlier in this document. +If a name has no security context associated in the +configuration file, the security context of the bus daemon +itself will be used. + +.SH DEBUGGING + +.PP +If you're trying to figure out where your messages are going or why +you aren't getting messages, there are several things you can try. + +.PP +Remember that the system bus is heavily locked down and if you +haven't installed a security policy file to allow your message +through, it won't work. For the session bus, this is not a concern. + +.PP +The simplest way to figure out what's happening on the bus is to run +the \fIdbus-monitor\fP program, which comes with the D-Bus +package. You can also send test messages with \fIdbus-send\fP. These +programs have their own man pages. + +.PP +If you want to know what the daemon itself is doing, you might consider +running a separate copy of the daemon to test against. This will allow you +to put the daemon under a debugger, or run it with verbose output, without +messing up your real session and system daemons. + +.PP +To run a separate test copy of the daemon, for example you might open a terminal +and type: +.nf + DBUS_VERBOSE=1 dbus-daemon --session --print-address +.fi + +.PP +The test daemon address will be printed when the daemon starts. You will need +to copy-and-paste this address and use it as the value of the +DBUS_SESSION_BUS_ADDRESS environment variable when you launch the applications +you want to test. This will cause those applications to connect to your +test bus instead of the DBUS_SESSION_BUS_ADDRESS of your real session bus. + +.PP +DBUS_VERBOSE=1 will have NO EFFECT unless your copy of D-Bus +was compiled with verbose mode enabled. This is not recommended in +production builds due to performance impact. You may need to rebuild +D-Bus if your copy was not built with debugging in mind. (DBUS_VERBOSE +also affects the D-Bus library and thus applications using D-Bus; it may +be useful to see verbose output on both the client side and from the daemon.) + +.PP +If you want to get fancy, you can create a custom bus +configuration for your test bus (see the session.conf and system.conf +files that define the two default configurations for example). This +would allow you to specify a different directory for .service files, +for example. + + +.SH AUTHOR +See http://www.freedesktop.org/software/dbus/doc/AUTHORS + +.SH BUGS +Please send bug reports to the D-Bus mailing list or bug tracker, +see http://www.freedesktop.org/software/dbus/ diff --git a/bus/desktop-file.c b/bus/desktop-file.c new file mode 100644 index 00000000..754a83c3 --- /dev/null +++ b/bus/desktop-file.c @@ -0,0 +1,800 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* desktop-file.c .desktop file parser + * + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include +#include +#include "desktop-file.h" +#include "utils.h" + +typedef struct +{ + char *key; + char *value; +} BusDesktopFileLine; + +typedef struct +{ + char *section_name; + + int n_lines; + BusDesktopFileLine *lines; + int n_allocated_lines; +} BusDesktopFileSection; + +struct BusDesktopFile +{ + int n_sections; + BusDesktopFileSection *sections; + int n_allocated_sections; +}; + +/** + * Parser for service files. + */ +typedef struct +{ + DBusString data; /**< The data from the file */ + + BusDesktopFile *desktop_file; /**< The resulting object */ + int current_section; /**< The current section being parsed */ + + int pos; /**< Current position */ + int len; /**< Length */ + int line_num; /**< Current line number */ + +} BusDesktopFileParser; + +#define VALID_KEY_CHAR 1 +#define VALID_LOCALE_CHAR 2 +static unsigned char valid[256] = { + 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , + 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , + 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x3 , 0x2 , 0x0 , + 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , + 0x0 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , + 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x2 , + 0x0 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , + 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , + 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , + 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , + 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , + 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , + 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , + 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , + 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , + 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , +}; + +static void report_error (BusDesktopFileParser *parser, + char *message, + const char *error_name, + DBusError *error); + +static void +parser_free (BusDesktopFileParser *parser) +{ + bus_desktop_file_free (parser->desktop_file); + + _dbus_string_free (&parser->data); +} + +static void +bus_desktop_file_line_free (BusDesktopFileLine *line) +{ + dbus_free (line->key); + dbus_free (line->value); +} + +static void +bus_desktop_file_section_free (BusDesktopFileSection *section) +{ + int i; + + for (i = 0; i < section->n_lines; i++) + bus_desktop_file_line_free (§ion->lines[i]); + + dbus_free (section->lines); + dbus_free (section->section_name); +} + +void +bus_desktop_file_free (BusDesktopFile *desktop_file) +{ + int i; + + for (i = 0; i < desktop_file->n_sections; i++) + bus_desktop_file_section_free (&desktop_file->sections[i]); + dbus_free (desktop_file->sections); + + dbus_free (desktop_file); +} + +static dbus_bool_t +grow_lines_in_section (BusDesktopFileSection *section) +{ + BusDesktopFileLine *lines; + + int new_n_lines; + + if (section->n_allocated_lines == 0) + new_n_lines = 1; + else + new_n_lines = section->n_allocated_lines*2; + + lines = dbus_realloc (section->lines, + sizeof (BusDesktopFileLine) * new_n_lines); + + if (lines == NULL) + return FALSE; + + section->lines = lines; + section->n_allocated_lines = new_n_lines; + + return TRUE; +} + +static dbus_bool_t +grow_sections (BusDesktopFile *desktop_file) +{ + int new_n_sections; + BusDesktopFileSection *sections; + + if (desktop_file->n_allocated_sections == 0) + new_n_sections = 1; + else + new_n_sections = desktop_file->n_allocated_sections*2; + + sections = dbus_realloc (desktop_file->sections, + sizeof (BusDesktopFileSection) * new_n_sections); + if (sections == NULL) + return FALSE; + + desktop_file->sections = sections; + + desktop_file->n_allocated_sections = new_n_sections; + + return TRUE; +} + +static char * +unescape_string (BusDesktopFileParser *parser, + const DBusString *str, + int pos, + int end_pos, + DBusError *error) +{ + char *retval, *q; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* len + 1 is enough, because unescaping never makes the + * string longer + */ + retval = dbus_malloc (end_pos - pos + 1); + if (retval == NULL) + { + BUS_SET_OOM (error); + return NULL; + } + + q = retval; + + while (pos < end_pos) + { + if (_dbus_string_get_byte (str, pos) == 0) + { + /* Found an embedded null */ + dbus_free (retval); + report_error (parser, "Text to be unescaped contains embedded nul", + BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error); + return NULL; + } + + if (_dbus_string_get_byte (str, pos) == '\\') + { + pos ++; + + if (pos >= end_pos) + { + /* Escape at end of string */ + dbus_free (retval); + report_error (parser, "Text to be unescaped ended in \\", + BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error); + return NULL; + } + + switch (_dbus_string_get_byte (str, pos)) + { + case 's': + *q++ = ' '; + break; + case 't': + *q++ = '\t'; + break; + case 'n': + *q++ = '\n'; + break; + case 'r': + *q++ = '\r'; + break; + case '\\': + *q++ = '\\'; + break; + default: + /* Invalid escape code */ + dbus_free (retval); + report_error (parser, "Text to be unescaped had invalid escape sequence", + BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES, error); + return NULL; + } + pos++; + } + else + { + *q++ =_dbus_string_get_byte (str, pos); + + pos++; + } + } + + *q = 0; + + return retval; +} + +static BusDesktopFileSection* +new_section (BusDesktopFile *desktop_file, + const char *name) +{ + int n; + char *name_copy; + + if (desktop_file->n_allocated_sections == desktop_file->n_sections) + { + if (!grow_sections (desktop_file)) + return NULL; + } + + name_copy = _dbus_strdup (name); + if (name_copy == NULL) + return NULL; + + n = desktop_file->n_sections; + desktop_file->sections[n].section_name = name_copy; + + desktop_file->sections[n].n_lines = 0; + desktop_file->sections[n].lines = NULL; + desktop_file->sections[n].n_allocated_lines = 0; + + if (!grow_lines_in_section (&desktop_file->sections[n])) + { + dbus_free (desktop_file->sections[n].section_name); + desktop_file->sections[n].section_name = NULL; + return NULL; + } + + desktop_file->n_sections += 1; + + return &desktop_file->sections[n]; +} + +static BusDesktopFileSection* +open_section (BusDesktopFileParser *parser, + char *name) +{ + BusDesktopFileSection *section; + + section = new_section (parser->desktop_file, name); + if (section == NULL) + return NULL; + + parser->current_section = parser->desktop_file->n_sections - 1; + _dbus_assert (&parser->desktop_file->sections[parser->current_section] == section); + + return section; +} + +static BusDesktopFileLine * +new_line (BusDesktopFileParser *parser) +{ + BusDesktopFileSection *section; + BusDesktopFileLine *line; + + section = &parser->desktop_file->sections[parser->current_section]; + + if (section->n_allocated_lines == section->n_lines) + { + if (!grow_lines_in_section (section)) + return NULL; + } + + line = §ion->lines[section->n_lines++]; + + memset (line, 0, sizeof (BusDesktopFileLine)); + + return line; +} + +static dbus_bool_t +is_blank_line (BusDesktopFileParser *parser) +{ + int p; + char c; + + p = parser->pos; + + c = _dbus_string_get_byte (&parser->data, p); + + while (c && c != '\n') + { + if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f')) + return FALSE; + + p++; + c = _dbus_string_get_byte (&parser->data, p); + } + + return TRUE; +} + +static void +parse_comment_or_blank (BusDesktopFileParser *parser) +{ + int line_end, eol_len; + + if (!_dbus_string_find_eol (&parser->data, parser->pos, &line_end, &eol_len)) + line_end = parser->len; + + if (line_end == parser->len) + parser->pos = parser->len; + else + parser->pos = line_end + eol_len; + + parser->line_num += 1; +} + +static dbus_bool_t +is_valid_section_name (const char *name) +{ + /* 5. Group names may contain all ASCII characters except for control characters and '[' and ']'. */ + + while (*name) + { + if (!((*name >= 'A' && *name <= 'Z') || (*name >= 'a' || *name <= 'z') || + *name == '\n' || *name == '\t')) + return FALSE; + + name++; + } + + return TRUE; +} + +static dbus_bool_t +parse_section_start (BusDesktopFileParser *parser, DBusError *error) +{ + int line_end, eol_len; + char *section_name; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_find_eol (&parser->data, parser->pos, &line_end, &eol_len)) + line_end = parser->len; + + if (line_end - parser->pos <= 2 || + _dbus_string_get_byte (&parser->data, line_end - 1) != ']') + { + report_error (parser, "Invalid syntax for section header", BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX, error); + parser_free (parser); + return FALSE; + } + + section_name = unescape_string (parser, + &parser->data, parser->pos + 1, line_end - 1, + error); + + if (section_name == NULL) + { + parser_free (parser); + return FALSE; + } + + if (!is_valid_section_name (section_name)) + { + report_error (parser, "Invalid characters in section name", BUS_DESKTOP_PARSE_ERROR_INVALID_CHARS, error); + parser_free (parser); + dbus_free (section_name); + return FALSE; + } + + if (open_section (parser, section_name) == NULL) + { + dbus_free (section_name); + parser_free (parser); + BUS_SET_OOM (error); + return FALSE; + } + + if (line_end == parser->len) + parser->pos = parser->len; + else + parser->pos = line_end + eol_len; + + parser->line_num += 1; + + dbus_free (section_name); + + return TRUE; +} + +static dbus_bool_t +parse_key_value (BusDesktopFileParser *parser, DBusError *error) +{ + int line_end, eol_len; + int key_start, key_end; + int value_start; + int p; + char *value, *tmp; + DBusString key; + BusDesktopFileLine *line; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_find_eol (&parser->data, parser->pos, &line_end, &eol_len)) + line_end = parser->len; + + p = parser->pos; + key_start = p; + while (p < line_end && + (valid[_dbus_string_get_byte (&parser->data, p)] & VALID_KEY_CHAR)) + p++; + key_end = p; + + if (key_start == key_end) + { + report_error (parser, "Empty key name", BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX, error); + parser_free (parser); + return FALSE; + } + + /* We ignore locales for now */ + if (p < line_end && _dbus_string_get_byte (&parser->data, p) == '[') + { + if (line_end == parser->len) + parser->pos = parser->len; + else + parser->pos = line_end + eol_len; + + parser->line_num += 1; + + return TRUE; + } + + /* Skip space before '=' */ + while (p < line_end && _dbus_string_get_byte (&parser->data, p) == ' ') + p++; + + if (p < line_end && _dbus_string_get_byte (&parser->data, p) != '=') + { + report_error (parser, "Invalid characters in key name", BUS_DESKTOP_PARSE_ERROR_INVALID_CHARS, error); + parser_free (parser); + return FALSE; + } + + if (p == line_end) + { + report_error (parser, "No '=' in key/value pair", BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX, error); + parser_free (parser); + return FALSE; + } + + /* Skip the '=' */ + p++; + + /* Skip space after '=' */ + while (p < line_end && _dbus_string_get_byte (&parser->data, p) == ' ') + p++; + + value_start = p; + + value = unescape_string (parser, &parser->data, value_start, line_end, error); + if (value == NULL) + { + parser_free (parser); + return FALSE; + } + + line = new_line (parser); + if (line == NULL) + { + dbus_free (value); + parser_free (parser); + BUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_init (&key)) + { + dbus_free (value); + parser_free (parser); + BUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_copy_len (&parser->data, key_start, key_end - key_start, + &key, 0)) + { + _dbus_string_free (&key); + dbus_free (value); + parser_free (parser); + BUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_steal_data (&key, &tmp)) + { + _dbus_string_free (&key); + dbus_free (value); + parser_free (parser); + BUS_SET_OOM (error); + return FALSE; + } + + _dbus_string_free (&key); + + line->key = tmp; + line->value = value; + + if (line_end == parser->len) + parser->pos = parser->len; + else + parser->pos = line_end + eol_len; + + parser->line_num += 1; + + return TRUE; +} + +static void +report_error (BusDesktopFileParser *parser, + char *message, + const char *error_name, + DBusError *error) +{ + const char *section_name = NULL; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (parser->current_section != -1) + section_name = parser->desktop_file->sections[parser->current_section].section_name; + + if (section_name) + dbus_set_error (error, error_name, + "Error in section %s at line %d: %s\n", section_name, parser->line_num, message); + else + dbus_set_error (error, error_name, + "Error at line %d: %s\n", parser->line_num, message); +} + +#if 0 +static void +dump_desktop_file (BusDesktopFile *file) +{ + int i; + + for (i = 0; i < file->n_sections; i++) + { + int j; + + printf ("[%s]\n", file->sections[i].section_name); + + for (j = 0; j < file->sections[i].n_lines; j++) + { + printf ("%s=%s\n", file->sections[i].lines[j].key, + file->sections[i].lines[j].value); + } + } +} +#endif + +BusDesktopFile* +bus_desktop_file_load (DBusString *filename, + DBusError *error) +{ + DBusString str; + BusDesktopFileParser parser; + DBusStat sb; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* Clearly there's a race here, but it's just to make it unlikely + * that we do something silly, we still handle doing it below. + */ + if (!_dbus_stat (filename, &sb, error)) + return NULL; + + if (sb.size > _DBUS_ONE_KILOBYTE * 128) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Desktop file size (%ld bytes) is too large", (long) sb.size); + return NULL; + } + + if (!_dbus_string_init (&str)) + { + BUS_SET_OOM (error); + return NULL; + } + + if (!_dbus_file_get_contents (&str, filename, error)) + { + _dbus_string_free (&str); + return NULL; + } + + if (!_dbus_string_validate_utf8 (&str, 0, _dbus_string_get_length (&str))) + { + _dbus_string_free (&str); + dbus_set_error (error, DBUS_ERROR_FAILED, + "invalid UTF-8"); + return NULL; + } + + parser.desktop_file = dbus_new0 (BusDesktopFile, 1); + if (parser.desktop_file == NULL) + { + _dbus_string_free (&str); + BUS_SET_OOM (error); + return NULL; + } + + parser.data = str; + parser.line_num = 1; + parser.pos = 0; + parser.len = _dbus_string_get_length (&parser.data); + parser.current_section = -1; + + while (parser.pos < parser.len) + { + if (_dbus_string_get_byte (&parser.data, parser.pos) == '[') + { + if (!parse_section_start (&parser, error)) + { + return NULL; + } + } + else if (is_blank_line (&parser) || + _dbus_string_get_byte (&parser.data, parser.pos) == '#') + parse_comment_or_blank (&parser); + else + { + if (!parse_key_value (&parser, error)) + { + return NULL; + } + } + } + + _dbus_string_free (&parser.data); + + return parser.desktop_file; +} + +static BusDesktopFileSection * +lookup_section (BusDesktopFile *desktop_file, + const char *section_name) +{ + BusDesktopFileSection *section; + int i; + + if (section_name == NULL) + return NULL; + + for (i = 0; i < desktop_file->n_sections; i ++) + { + section = &desktop_file->sections[i]; + + if (strcmp (section->section_name, section_name) == 0) + return section; + } + + return NULL; +} + +static BusDesktopFileLine * +lookup_line (BusDesktopFile *desktop_file, + BusDesktopFileSection *section, + const char *keyname) +{ + BusDesktopFileLine *line; + int i; + + for (i = 0; i < section->n_lines; i++) + { + line = §ion->lines[i]; + + if (strcmp (line->key, keyname) == 0) + return line; + } + + return NULL; +} + +dbus_bool_t +bus_desktop_file_get_raw (BusDesktopFile *desktop_file, + const char *section_name, + const char *keyname, + const char **val) +{ + BusDesktopFileSection *section; + BusDesktopFileLine *line; + + *val = NULL; + + section = lookup_section (desktop_file, section_name); + + if (!section) + return FALSE; + + line = lookup_line (desktop_file, + section, + keyname); + + if (!line) + return FALSE; + + *val = line->value; + + return TRUE; +} + +dbus_bool_t +bus_desktop_file_get_string (BusDesktopFile *desktop_file, + const char *section, + const char *keyname, + char **val, + DBusError *error) +{ + const char *raw; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + *val = NULL; + + if (!bus_desktop_file_get_raw (desktop_file, section, keyname, &raw)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "No \"%s\" key in .service file\n", keyname); + return FALSE; + } + + *val = _dbus_strdup (raw); + + if (*val == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; +} diff --git a/bus/desktop-file.h b/bus/desktop-file.h new file mode 100644 index 00000000..7f43458a --- /dev/null +++ b/bus/desktop-file.h @@ -0,0 +1,56 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* desktop-file.h .desktop file parser + * + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef BUS_DESKTOP_FILE_H +#define BUS_DESKTOP_FILE_H + +#include +#include + +#define BUS_DESKTOP_PARSE_ERROR_INVALID_SYNTAX "org.freedesktop.DBus.DesktopParseError.InvalidSyntax" +#define BUS_DESKTOP_PARSE_ERROR_INVALID_ESCAPES "org.freedesktop.DBus.DesktopParseError.InvalidEscapes" +#define BUS_DESKTOP_PARSE_ERROR_INVALID_CHARS "org.freedesktop.DBus.DesktopParseError.InvalidChars" + +#define DBUS_SERVICE_SECTION "D-BUS Service" +#define DBUS_SERVICE_NAME "Name" +#define DBUS_SERVICE_EXEC "Exec" +#define DBUS_SERVICE_USER "User" +#define DBUS_SERVICE_GROUP "Group" + +typedef struct BusDesktopFile BusDesktopFile; + +BusDesktopFile *bus_desktop_file_load (DBusString *filename, + DBusError *error); +void bus_desktop_file_free (BusDesktopFile *file); + +dbus_bool_t bus_desktop_file_get_raw (BusDesktopFile *desktop_file, + const char *section_name, + const char *keyname, + const char **val); +dbus_bool_t bus_desktop_file_get_string (BusDesktopFile *desktop_file, + const char *section, + const char *keyname, + char **val, + DBusError *error); + + +#endif /* BUS_DESKTOP_FILE_H */ diff --git a/bus/dir-watch-default.c b/bus/dir-watch-default.c new file mode 100644 index 00000000..8e457eb6 --- /dev/null +++ b/bus/dir-watch-default.c @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dir-watch-default.c OS specific directory change notification for message bus + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#include +#include "dir-watch.h" + + +/* NoOp */ + +void +bus_watch_directory (const char *dir, BusContext *context) +{ +} + +void +bus_set_watched_dirs (BusContext *context, DBusList **directories) +{ +} diff --git a/bus/dir-watch-dnotify.c b/bus/dir-watch-dnotify.c new file mode 100644 index 00000000..b38d7d19 --- /dev/null +++ b/bus/dir-watch-dnotify.c @@ -0,0 +1,93 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dir-watch-dnotify.c OS specific directory change notification for message bus + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#define _GNU_SOURCE +#include +#include +#include +#ifdef HAVE_ERRNO_H +#include +#endif + +#include +#include "dir-watch.h" + +#define MAX_DIRS_TO_WATCH 128 + +/* use a static array to avoid handling OOM */ +static int fds[MAX_DIRS_TO_WATCH]; +static int num_fds = 0; + +void +bus_watch_directory (const char *dir, BusContext *context) +{ + int fd; + + _dbus_assert (dir != NULL); + + if (num_fds >= MAX_DIRS_TO_WATCH ) + { + _dbus_warn ("Cannot watch config directory '%s'. Already watching %d directories\n", dir, MAX_DIRS_TO_WATCH); + goto out; + } + + fd = open (dir, O_RDONLY); + if (fd < 0) + { + _dbus_warn ("Cannot open directory '%s'; error '%s'\n", dir, _dbus_strerror (errno)); + goto out; + } + + if (fcntl (fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_RENAME|DN_MODIFY) == -1) + { + _dbus_warn ("Cannot setup D_NOTIFY for '%s' error '%s'\n", dir, _dbus_strerror (errno)); + close (fd); + goto out; + } + + fds[num_fds++] = fd; + _dbus_verbose ("Added watch on config directory '%s'\n", dir); + + out: + ; +} + +void +bus_drop_all_directory_watches (void) +{ + int i; + + _dbus_verbose ("Dropping all watches on config directories\n"); + + for (i = 0; i < num_fds; i++) + { + if (close (fds[i]) != 0) + { + _dbus_verbose ("Error closing fd %d for config directory watch\n", fds[i]); + } + } + + num_fds = 0; +} diff --git a/bus/dir-watch-inotify.c b/bus/dir-watch-inotify.c new file mode 100644 index 00000000..094993bb --- /dev/null +++ b/bus/dir-watch-inotify.c @@ -0,0 +1,279 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dir-watch-inotify.c OS specific directory change notification for message bus + * + * Copyright (C) 2003 Red Hat, Inc. + * (c) 2006 Mandriva + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "dir-watch.h" + +#define MAX_DIRS_TO_WATCH 128 +#define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event)) +#define INOTIFY_BUF_LEN (1024 * (INOTIFY_EVENT_SIZE + 16)) + +/* use a static array to avoid handling OOM */ +static int wds[MAX_DIRS_TO_WATCH]; +static char *dirs[MAX_DIRS_TO_WATCH]; +static int num_wds = 0; +static int inotify_fd = -1; +static DBusWatch *watch = NULL; +static DBusLoop *loop = NULL; + +static dbus_bool_t +_inotify_watch_callback (DBusWatch *watch, unsigned int condition, void *data) +{ + return dbus_watch_handle (watch, condition); +} + +static dbus_bool_t +_handle_inotify_watch (DBusWatch *passed_watch, unsigned int flags, void *data) +{ + char buffer[INOTIFY_BUF_LEN]; + ssize_t ret = 0; + int i = 0; + pid_t pid; + dbus_bool_t have_change = FALSE; + + ret = read (inotify_fd, buffer, INOTIFY_BUF_LEN); + if (ret < 0) + _dbus_verbose ("Error reading inotify event: '%s'\n", _dbus_strerror(errno)); + else if (!ret) + _dbus_verbose ("Error reading inotify event: buffer too small\n"); + + while (i < ret) + { + struct inotify_event *ev; + pid = _dbus_getpid (); + + ev = (struct inotify_event *) &buffer[i]; + i += INOTIFY_EVENT_SIZE + ev->len; +#ifdef DBUS_ENABLE_VERBOSE_MODE + if (ev->len) + _dbus_verbose ("event name: '%s'\n", ev->name); + _dbus_verbose ("inotify event: wd=%d mask=%u cookie=%u len=%u\n", ev->wd, ev->mask, ev->cookie, ev->len); +#endif + _dbus_verbose ("Sending SIGHUP signal on reception of a inotify event\n"); + have_change = TRUE; + } + if (have_change) + (void) kill (pid, SIGHUP); + + return TRUE; +} + +#include + +static void +_set_watched_dirs_internal (DBusList **directories) +{ + int new_wds[MAX_DIRS_TO_WATCH]; + char *new_dirs[MAX_DIRS_TO_WATCH]; + DBusList *link; + int i, j, wd; + + for (i = 0; i < MAX_DIRS_TO_WATCH; i++) + { + new_wds[i] = -1; + new_dirs[i] = NULL; + } + + i = 0; + link = _dbus_list_get_first_link (directories); + while (link != NULL) + { + new_dirs[i++] = (char *)link->data; + link = _dbus_list_get_next_link (directories, link); + } + + /* Look for directories in both the old and new sets, if + * we find one, move its data into the new set. + */ + for (i = 0; new_dirs[i]; i++) + { + for (j = 0; j < num_wds; j++) + { + if (dirs[j] && strcmp (new_dirs[i], dirs[j]) == 0) + { + new_wds[i] = wds[j]; + new_dirs[i] = dirs[j]; + wds[j] = -1; + dirs[j] = NULL; + break; + } + } + } + + /* Any directories we find in "wds" with a nonzero fd must + * not be in the new set, so perform cleanup now. + */ + for (j = 0; j < num_wds; j++) + { + if (wds[j] != -1) + { + inotify_rm_watch (inotify_fd, wds[j]); + dbus_free (dirs[j]); + wds[j] = -1; + dirs[j] = NULL; + } + } + + for (i = 0; new_dirs[i]; i++) + { + if (new_wds[i] == -1) + { + /* FIXME - less lame error handling for failing to add a watch; we may need to sleep. */ + wd = inotify_add_watch (inotify_fd, new_dirs[i], IN_CLOSE_WRITE | IN_DELETE | IN_MOVED_TO | IN_MOVED_FROM); + if (wd < 0) + { + /* Not all service directories need to exist. */ + if (errno != ENOENT) + { + _dbus_warn ("Cannot setup inotify for '%s'; error '%s'\n", new_dirs[i], _dbus_strerror (errno)); + goto out; + } + else + { + new_wds[i] = -1; + new_dirs[i] = NULL; + continue; + } + } + new_wds[i] = wd; + new_dirs[i] = _dbus_strdup (new_dirs[i]); + if (!new_dirs[i]) + { + /* FIXME have less lame handling for OOM, we just silently fail to + * watch. (In reality though, the whole OOM handling in dbus is stupid + * but we won't go into that in this comment =) ) + */ + inotify_rm_watch (inotify_fd, wd); + new_wds[i] = -1; + } + } + } + + num_wds = i; + + for (i = 0; i < MAX_DIRS_TO_WATCH; i++) + { + wds[i] = new_wds[i]; + dirs[i] = new_dirs[i]; + } + + out:; +} + +#include +static void +_shutdown_inotify (void *data) +{ + DBusList *empty = NULL; + + if (inotify_fd == -1) + return; + + _set_watched_dirs_internal (&empty); + + close (inotify_fd); + inotify_fd = -1; + if (watch != NULL) + { + _dbus_loop_remove_watch (loop, watch, _inotify_watch_callback, NULL); + _dbus_watch_unref (watch); + _dbus_loop_unref (loop); + } + watch = NULL; + loop = NULL; +} + +static int +_init_inotify (BusContext *context) +{ + int ret = 0; + + if (inotify_fd == -1) + { +#ifdef HAVE_INOTIFY_INIT1 + inotify_fd = inotify_init1 (IN_CLOEXEC); + /* This ensures we still run on older Linux kernels. + * https://bugs.freedesktop.org/show_bug.cgi?id=23957 + */ + if (inotify_fd < 0) + inotify_fd = inotify_init (); +#else + inotify_fd = inotify_init (); +#endif + if (inotify_fd <= 0) + { + _dbus_warn ("Cannot initialize inotify\n"); + goto out; + } + loop = bus_context_get_loop (context); + _dbus_loop_ref (loop); + + watch = _dbus_watch_new (inotify_fd, DBUS_WATCH_READABLE, TRUE, + _handle_inotify_watch, NULL, NULL); + + if (watch == NULL) + { + _dbus_warn ("Unable to create inotify watch\n"); + goto out; + } + + if (!_dbus_loop_add_watch (loop, watch, _inotify_watch_callback, + NULL, NULL)) + { + _dbus_warn ("Unable to add reload watch to main loop"); + _dbus_watch_unref (watch); + watch = NULL; + goto out; + } + + _dbus_register_shutdown_func (_shutdown_inotify, NULL); + } + + ret = 1; + +out: + return ret; +} + +void +bus_set_watched_dirs (BusContext *context, DBusList **directories) +{ + if (!_init_inotify (context)) + return; + + _set_watched_dirs_internal (directories); +} diff --git a/bus/dir-watch-kqueue.c b/bus/dir-watch-kqueue.c new file mode 100644 index 00000000..4a01b748 --- /dev/null +++ b/bus/dir-watch-kqueue.c @@ -0,0 +1,255 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dir-watch-kqueue.c OS specific directory change notification for message bus + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "bus.h" +#include + +#include +#include +#include "dir-watch.h" + +#define MAX_DIRS_TO_WATCH 128 + +static int kq = -1; +static int fds[MAX_DIRS_TO_WATCH]; +static char *dirs[MAX_DIRS_TO_WATCH]; +static int num_fds = 0; +static DBusWatch *watch = NULL; +static DBusLoop *loop = NULL; + +static dbus_bool_t +_kqueue_watch_callback (DBusWatch *watch, unsigned int condition, void *data) +{ + return dbus_watch_handle (watch, condition); +} + +static dbus_bool_t +_handle_kqueue_watch (DBusWatch *watch, unsigned int flags, void *data) +{ + struct kevent ev; + struct timespec nullts = { 0, 0 }; + int res; + pid_t pid; + + res = kevent (kq, NULL, 0, &ev, 1, &nullts); + + /* Sleep for half a second to avoid a race when files are install(1)'d + * to system.d. */ + usleep(500000); + + if (res > 0) + { + pid = getpid (); + _dbus_verbose ("Sending SIGHUP signal on reception of a kevent\n"); + (void) kill (pid, SIGHUP); + } + else if (res < 0 && errno == EBADF) + { + kq = -1; + if (watch != NULL) + { + _dbus_loop_remove_watch (loop, watch, _kqueue_watch_callback, NULL); + _dbus_watch_unref (watch); + watch = NULL; + } + pid = getpid (); + _dbus_verbose ("Sending SIGHUP signal since kqueue has been closed\n"); + (void) kill (pid, SIGHUP); + } + + return TRUE; +} + +static int +_init_kqueue (BusContext *context) +{ + int ret = 0; + + if (kq < 0) + { + + kq = kqueue (); + if (kq < 0) + { + _dbus_warn ("Cannot create kqueue; error '%s'\n", _dbus_strerror (errno)); + goto out; + } + + loop = bus_context_get_loop (context); + + watch = _dbus_watch_new (kq, DBUS_WATCH_READABLE, TRUE, + _handle_kqueue_watch, NULL, NULL); + + if (watch == NULL) + { + _dbus_warn ("Unable to create kqueue watch\n"); + close (kq); + kq = -1; + goto out; + } + + if (!_dbus_loop_add_watch (loop, watch, _kqueue_watch_callback, + NULL, NULL)) + { + _dbus_warn ("Unable to add reload watch to main loop"); + close (kq); + kq = -1; + _dbus_watch_unref (watch); + watch = NULL; + goto out; + } + } + + ret = 1; + +out: + return ret; +} + +void +bus_set_watched_dirs (BusContext *context, DBusList **directories) +{ + int new_fds[MAX_DIRS_TO_WATCH]; + char *new_dirs[MAX_DIRS_TO_WATCH]; + DBusList *link; + int i, j, f, fd; + struct kevent ev; + + if (!_init_kqueue (context)) + goto out; + + for (i = 0; i < MAX_DIRS_TO_WATCH; i++) + { + new_fds[i] = -1; + new_dirs[i] = NULL; + } + + i = 0; + link = _dbus_list_get_first_link (directories); + while (link != NULL) + { + new_dirs[i++] = (char *)link->data; + link = _dbus_list_get_next_link (directories, link); + } + + /* Look for directories in both the old and new sets, if + * we find one, move its data into the new set. + */ + for (i = 0; new_dirs[i]; i++) + { + for (j = 0; i < num_fds; j++) + { + if (dirs[j] && strcmp (new_dirs[i], dirs[j]) == 0) + { + new_fds[i] = fds[j]; + new_dirs[i] = dirs[j]; + fds[j] = -1; + dirs[j] = NULL; + break; + } + } + } + + /* Any directory we find in "fds" with a nonzero fd must + * not be in the new set, so perform cleanup now. + */ + for (j = 0; j < num_fds; j++) + { + if (fds[j] != -1) + { + close (fds[j]); + dbus_free (dirs[j]); + fds[j] = -1; + dirs[j] = NULL; + } + } + + for (i = 0; new_dirs[i]; i++) + { + if (new_fds[i] == -1) + { + /* FIXME - less lame error handling for failing to add a watch; + * we may need to sleep. + */ + fd = open (new_dirs[i], O_RDONLY); + if (fd < 0) + { + if (errno != ENOENT) + { + _dbus_warn ("Cannot open directory '%s'; error '%s'\n", new_dirs[i], _dbus_strerror (errno)); + goto out; + } + else + { + new_fds[i] = -1; + new_dirs[i] = NULL; + continue; + } + } + + EV_SET (&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, + NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_RENAME, 0, 0); + if (kevent (kq, &ev, 1, NULL, 0, NULL) == -1) + { + _dbus_warn ("Cannot setup a kevent for '%s'; error '%s'\n", new_dirs[i], _dbus_strerror (errno)); + close (fd); + goto out; + } + + new_fds[i] = fd; + new_dirs[i] = _dbus_strdup (new_dirs[i]); + if (!new_dirs[i]) + { + /* FIXME have less lame handling for OOM, we just silently fail to + * watch. (In reality though, the whole OOM handling in dbus is + * stupid but we won't go into that in this comment =) ) + */ + close (fd); + new_fds[i] = -1; + } + } + } + + num_fds = i; + + for (i = 0; i < MAX_DIRS_TO_WATCH; i++) + { + fds[i] = new_fds[i]; + dirs[i] = new_dirs[i]; + } + + out: + ; +} diff --git a/bus/dir-watch.h b/bus/dir-watch.h new file mode 100644 index 00000000..b44529e5 --- /dev/null +++ b/bus/dir-watch.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dir-watch.h Watch directories + * + * Copyright (C) 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "bus.h" + +#ifndef DIR_WATCH_H +#define DIR_WATCH_H + +/** + * Update the set of directories to monitor for changes. The + * operating-system-specific implementation of this function should + * avoid creating a window where a directory in both the + * old and new set isn't monitored. + * + * @param context The bus context + * @param dirs List of strings which are directory paths + */ +void bus_set_watched_dirs (BusContext *context, DBusList **dirs); + +#endif /* DIR_WATCH_H */ diff --git a/bus/dispatch.c b/bus/dispatch.c new file mode 100644 index 00000000..ca55177b --- /dev/null +++ b/bus/dispatch.c @@ -0,0 +1,4725 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dispatch.c Message dispatcher + * + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + * Copyright (C) 2004 Imendio HB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dispatch.h" +#include "connection.h" +#include "driver.h" +#include "services.h" +#include "activation.h" +#include "utils.h" +#include "bus.h" +#include "signals.h" +#include "test.h" +#include +#include + +static dbus_bool_t +send_one_message (DBusConnection *connection, + BusContext *context, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusMessage *message, + BusTransaction *transaction, + DBusError *error) +{ + if (!bus_context_check_security_policy (context, transaction, + sender, + addressed_recipient, + connection, + message, + NULL)) + return TRUE; /* silently don't send it */ + + if (!bus_transaction_send (transaction, + connection, + message)) + { + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; +} + +dbus_bool_t +bus_dispatch_matches (BusTransaction *transaction, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusMessage *message, + DBusError *error) +{ + DBusError tmp_error; + BusConnections *connections; + DBusList *recipients; + BusMatchmaker *matchmaker; + DBusList *link; + BusContext *context; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* sender and recipient can both be NULL for the bus driver, + * or for signals with no particular recipient + */ + + _dbus_assert (sender == NULL || bus_connection_is_active (sender)); + _dbus_assert (dbus_message_get_sender (message) != NULL); + + context = bus_transaction_get_context (transaction); + + /* First, send the message to the addressed_recipient, if there is one. */ + if (addressed_recipient != NULL) + { + if (!bus_context_check_security_policy (context, transaction, + sender, addressed_recipient, + addressed_recipient, + message, error)) + return FALSE; + + /* Dispatch the message */ + if (!bus_transaction_send (transaction, addressed_recipient, message)) + { + BUS_SET_OOM (error); + return FALSE; + } + } + + /* Now dispatch to others who look interested in this message */ + connections = bus_transaction_get_connections (transaction); + dbus_error_init (&tmp_error); + matchmaker = bus_context_get_matchmaker (context); + + recipients = NULL; + if (!bus_matchmaker_get_recipients (matchmaker, connections, + sender, addressed_recipient, message, + &recipients)) + { + BUS_SET_OOM (error); + return FALSE; + } + + link = _dbus_list_get_first_link (&recipients); + while (link != NULL) + { + DBusConnection *dest; + + dest = link->data; + + if (!send_one_message (dest, context, sender, addressed_recipient, + message, transaction, &tmp_error)) + break; + + link = _dbus_list_get_next_link (&recipients, link); + } + + _dbus_list_clear (&recipients); + + if (dbus_error_is_set (&tmp_error)) + { + dbus_move_error (&tmp_error, error); + return FALSE; + } + else + return TRUE; +} + +static DBusHandlerResult +bus_dispatch (DBusConnection *connection, + DBusMessage *message) +{ + const char *sender, *service_name; + DBusError error; + BusTransaction *transaction; + BusContext *context; + DBusHandlerResult result; + DBusConnection *addressed_recipient; + + result = DBUS_HANDLER_RESULT_HANDLED; + + transaction = NULL; + addressed_recipient = NULL; + dbus_error_init (&error); + + context = bus_connection_get_context (connection); + _dbus_assert (context != NULL); + + /* If we can't even allocate an OOM error, we just go to sleep + * until we can. + */ + while (!bus_connection_preallocate_oom_error (connection)) + _dbus_wait_for_memory (); + + /* Ref connection in case we disconnect it at some point in here */ + dbus_connection_ref (connection); + + service_name = dbus_message_get_destination (message); + +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + const char *interface_name, *member_name, *error_name; + + interface_name = dbus_message_get_interface (message); + member_name = dbus_message_get_member (message); + error_name = dbus_message_get_error_name (message); + + _dbus_verbose ("DISPATCH: %s %s %s to %s\n", + interface_name ? interface_name : "(no interface)", + member_name ? member_name : "(no member)", + error_name ? error_name : "(no error name)", + service_name ? service_name : "peer"); + } +#endif /* DBUS_ENABLE_VERBOSE_MODE */ + + /* If service_name is NULL, if it's a signal we send it to all + * connections with a match rule. If it's not a signal, there + * are some special cases here but mostly we just bail out. + */ + if (service_name == NULL) + { + if (dbus_message_is_signal (message, + DBUS_INTERFACE_LOCAL, + "Disconnected")) + { + bus_connection_disconnected (connection); + goto out; + } + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL) + { + /* DBusConnection also handles some of these automatically, we leave + * it to do so. + */ + result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto out; + } + } + + /* Create our transaction */ + transaction = bus_transaction_new (context); + if (transaction == NULL) + { + BUS_SET_OOM (&error); + goto out; + } + + /* Assign a sender to the message */ + if (bus_connection_is_active (connection)) + { + sender = bus_connection_get_name (connection); + _dbus_assert (sender != NULL); + + if (!dbus_message_set_sender (message, sender)) + { + BUS_SET_OOM (&error); + goto out; + } + + /* We need to refetch the service name here, because + * dbus_message_set_sender can cause the header to be + * reallocated, and thus the service_name pointer will become + * invalid. + */ + service_name = dbus_message_get_destination (message); + } + + if (service_name && + strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */ + { + if (!bus_context_check_security_policy (context, transaction, + connection, NULL, NULL, message, &error)) + { + _dbus_verbose ("Security policy rejected message\n"); + goto out; + } + + _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS); + if (!bus_driver_handle_message (connection, transaction, message, &error)) + goto out; + } + else if (!bus_connection_is_active (connection)) /* clients must talk to bus driver first */ + { + _dbus_verbose ("Received message from non-registered client. Disconnecting.\n"); + dbus_connection_close (connection); + goto out; + } + else if (service_name != NULL) /* route to named service */ + { + DBusString service_string; + BusService *service; + BusRegistry *registry; + + _dbus_assert (service_name != NULL); + + registry = bus_connection_get_registry (connection); + + _dbus_string_init_const (&service_string, service_name); + service = bus_registry_lookup (registry, &service_string); + + if (service == NULL && dbus_message_get_auto_start (message)) + { + BusActivation *activation; + /* We can't do the security policy check here, since the addressed + * recipient service doesn't exist yet. We do it before sending the + * message after the service has been created. + */ + activation = bus_connection_get_activation (connection); + + if (!bus_activation_activate_service (activation, connection, transaction, TRUE, + message, service_name, &error)) + { + _DBUS_ASSERT_ERROR_IS_SET (&error); + _dbus_verbose ("bus_activation_activate_service() failed: %s\n", error.name); + goto out; + } + + goto out; + } + else if (service == NULL) + { + dbus_set_error (&error, + DBUS_ERROR_NAME_HAS_NO_OWNER, + "Name \"%s\" does not exist", + service_name); + goto out; + } + else + { + addressed_recipient = bus_service_get_primary_owners_connection (service); + _dbus_assert (addressed_recipient != NULL); + } + } + + /* Now send the message to its destination (or not, if + * addressed_recipient == NULL), and match it against other connections' + * match rules. + */ + if (!bus_dispatch_matches (transaction, connection, addressed_recipient, message, &error)) + goto out; + + out: + if (dbus_error_is_set (&error)) + { + if (!dbus_connection_get_is_connected (connection)) + { + /* If we disconnected it, we won't bother to send it any error + * messages. + */ + _dbus_verbose ("Not sending error to connection we disconnected\n"); + } + else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + bus_connection_send_oom_error (connection, message); + + /* cancel transaction due to OOM */ + if (transaction != NULL) + { + bus_transaction_cancel_and_free (transaction); + transaction = NULL; + } + } + else + { + /* Try to send the real error, if no mem to do that, send + * the OOM error + */ + _dbus_assert (transaction != NULL); + if (!bus_transaction_send_error_reply (transaction, connection, + &error, message)) + { + bus_connection_send_oom_error (connection, message); + + /* cancel transaction due to OOM */ + if (transaction != NULL) + { + bus_transaction_cancel_and_free (transaction); + transaction = NULL; + } + } + } + + + dbus_error_free (&error); + } + + if (transaction != NULL) + { + bus_transaction_execute_and_free (transaction); + } + + dbus_connection_unref (connection); + + return result; +} + +static DBusHandlerResult +bus_dispatch_message_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + return bus_dispatch (connection, message); +} + +dbus_bool_t +bus_dispatch_add_connection (DBusConnection *connection) +{ + if (!dbus_connection_add_filter (connection, + bus_dispatch_message_filter, + NULL, NULL)) + return FALSE; + + return TRUE; +} + +void +bus_dispatch_remove_connection (DBusConnection *connection) +{ + /* Here we tell the bus driver that we want to get off. */ + bus_driver_remove_connection (connection); + + dbus_connection_remove_filter (connection, + bus_dispatch_message_filter, + NULL); +} + +#ifdef DBUS_BUILD_TESTS + +#include + +/* This is used to know whether we need to block in order to finish + * sending a message, or whether the initial dbus_connection_send() + * already flushed the queue. + */ +#define SEND_PENDING(connection) (dbus_connection_has_messages_to_send (connection)) + +typedef dbus_bool_t (* Check1Func) (BusContext *context); +typedef dbus_bool_t (* Check2Func) (BusContext *context, + DBusConnection *connection); + +static dbus_bool_t check_no_leftovers (BusContext *context); + +static void +block_connection_until_message_from_bus (BusContext *context, + DBusConnection *connection, + const char *what_is_expected) +{ + _dbus_verbose ("expecting: %s\n", what_is_expected); + + while (dbus_connection_get_dispatch_status (connection) == + DBUS_DISPATCH_COMPLETE && + dbus_connection_get_is_connected (connection)) + { + bus_test_run_bus_loop (context, TRUE); + bus_test_run_clients_loop (FALSE); + } +} + +static void +spin_connection_until_authenticated (BusContext *context, + DBusConnection *connection) +{ + _dbus_verbose ("Spinning to auth connection %p\n", connection); + while (!dbus_connection_get_is_authenticated (connection) && + dbus_connection_get_is_connected (connection)) + { + bus_test_run_bus_loop (context, FALSE); + bus_test_run_clients_loop (FALSE); + } + _dbus_verbose (" ... done spinning to auth connection %p\n", connection); +} + +/* compensate for fact that pop_message() can return #NULL due to OOM */ +static DBusMessage* +pop_message_waiting_for_memory (DBusConnection *connection) +{ + while (dbus_connection_get_dispatch_status (connection) == + DBUS_DISPATCH_NEED_MEMORY) + _dbus_wait_for_memory (); + + return dbus_connection_pop_message (connection); +} + +static DBusMessage* +borrow_message_waiting_for_memory (DBusConnection *connection) +{ + while (dbus_connection_get_dispatch_status (connection) == + DBUS_DISPATCH_NEED_MEMORY) + _dbus_wait_for_memory (); + + return dbus_connection_borrow_message (connection); +} + +static void +warn_unexpected_real (DBusConnection *connection, + DBusMessage *message, + const char *expected, + const char *function, + int line) +{ + if (message) + _dbus_warn ("%s:%d received message interface \"%s\" member \"%s\" error name \"%s\" on %p, expecting %s\n", + function, line, + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + connection, + expected); + else + _dbus_warn ("%s:%d received no message on %p, expecting %s\n", + function, line, connection, expected); +} + +#define warn_unexpected(connection, message, expected) \ + warn_unexpected_real (connection, message, expected, _DBUS_FUNCTION_NAME, __LINE__) + +static void +verbose_message_received (DBusConnection *connection, + DBusMessage *message) +{ + _dbus_verbose ("Received message interface \"%s\" member \"%s\" error name \"%s\" on %p\n", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : "(unset)", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : "(unset)", + dbus_message_get_error_name (message) ? + dbus_message_get_error_name (message) : "(unset)", + connection); +} + +typedef enum +{ + SERVICE_CREATED, + OWNER_CHANGED, + SERVICE_DELETED +} ServiceInfoKind; + +typedef struct +{ + ServiceInfoKind expected_kind; + const char *expected_service_name; + dbus_bool_t failed; + DBusConnection *skip_connection; +} CheckServiceOwnerChangedData; + +static dbus_bool_t +check_service_owner_changed_foreach (DBusConnection *connection, + void *data) +{ + CheckServiceOwnerChangedData *d = data; + DBusMessage *message; + DBusError error; + const char *service_name, *old_owner, *new_owner; + + if (d->expected_kind == SERVICE_CREATED + && connection == d->skip_connection) + return TRUE; + + dbus_error_init (&error); + d->failed = TRUE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a message on %p, expecting %s\n", + connection, "NameOwnerChanged"); + goto out; + } + else if (!dbus_message_is_signal (message, + DBUS_INTERFACE_DBUS, + "NameOwnerChanged")) + { + warn_unexpected (connection, message, "NameOwnerChanged"); + + goto out; + } + else + { + reget_service_info_data: + service_name = NULL; + old_owner = NULL; + new_owner = NULL; + + dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &service_name, + DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &new_owner, + DBUS_TYPE_INVALID); + + if (dbus_error_is_set (&error)) + { + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + dbus_error_free (&error); + _dbus_wait_for_memory (); + goto reget_service_info_data; + } + else + { + _dbus_warn ("Did not get the expected arguments\n"); + goto out; + } + } + + if ((d->expected_kind == SERVICE_CREATED && ( old_owner[0] || !new_owner[0])) + || (d->expected_kind == OWNER_CHANGED && (!old_owner[0] || !new_owner[0])) + || (d->expected_kind == SERVICE_DELETED && (!old_owner[0] || new_owner[0]))) + { + _dbus_warn ("inconsistent NameOwnerChanged arguments\n"); + goto out; + } + + if (strcmp (service_name, d->expected_service_name) != 0) + { + _dbus_warn ("expected info on service %s, got info on %s\n", + d->expected_service_name, + service_name); + goto out; + } + + if (*service_name == ':' && new_owner[0] + && strcmp (service_name, new_owner) != 0) + { + _dbus_warn ("inconsistent ServiceOwnedChanged message (\"%s\" [ %s -> %s ])\n", + service_name, old_owner, new_owner); + goto out; + } + } + + d->failed = FALSE; + + out: + dbus_error_free (&error); + + if (message) + dbus_message_unref (message); + + return !d->failed; +} + + +static void +kill_client_connection (BusContext *context, + DBusConnection *connection) +{ + char *base_service; + const char *s; + CheckServiceOwnerChangedData socd; + + _dbus_verbose ("killing connection %p\n", connection); + + s = dbus_bus_get_unique_name (connection); + _dbus_assert (s != NULL); + + while ((base_service = _dbus_strdup (s)) == NULL) + _dbus_wait_for_memory (); + + dbus_connection_ref (connection); + + /* kick in the disconnect handler that unrefs the connection */ + dbus_connection_close (connection); + + bus_test_run_everything (context); + + _dbus_assert (bus_test_client_listed (connection)); + + /* Run disconnect handler in test.c */ + if (bus_connection_dispatch_one_message (connection)) + _dbus_assert_not_reached ("something received on connection being killed other than the disconnect"); + + _dbus_assert (!dbus_connection_get_is_connected (connection)); + dbus_connection_unref (connection); + connection = NULL; + _dbus_assert (!bus_test_client_listed (connection)); + + socd.expected_kind = SERVICE_DELETED; + socd.expected_service_name = base_service; + socd.failed = FALSE; + socd.skip_connection = NULL; + + bus_test_clients_foreach (check_service_owner_changed_foreach, + &socd); + + dbus_free (base_service); + + if (socd.failed) + _dbus_assert_not_reached ("didn't get the expected NameOwnerChanged (deletion) messages"); + + if (!check_no_leftovers (context)) + _dbus_assert_not_reached ("stuff left in message queues after disconnecting a client"); +} + +static void +kill_client_connection_unchecked (DBusConnection *connection) +{ + /* This kills the connection without expecting it to affect + * the rest of the bus. + */ + _dbus_verbose ("Unchecked kill of connection %p\n", connection); + + dbus_connection_ref (connection); + dbus_connection_close (connection); + /* dispatching disconnect handler will unref once */ + if (bus_connection_dispatch_one_message (connection)) + _dbus_assert_not_reached ("message other than disconnect dispatched after failure to register"); + + _dbus_assert (!bus_test_client_listed (connection)); + dbus_connection_unref (connection); +} + +typedef struct +{ + dbus_bool_t failed; +} CheckNoMessagesData; + +static dbus_bool_t +check_no_messages_foreach (DBusConnection *connection, + void *data) +{ + CheckNoMessagesData *d = data; + DBusMessage *message; + + message = pop_message_waiting_for_memory (connection); + if (message != NULL) + { + warn_unexpected (connection, message, "no messages"); + + d->failed = TRUE; + } + + if (message) + dbus_message_unref (message); + return !d->failed; +} + +static dbus_bool_t +check_no_leftovers (BusContext *context) +{ + CheckNoMessagesData nmd; + + nmd.failed = FALSE; + bus_test_clients_foreach (check_no_messages_foreach, + &nmd); + + if (nmd.failed) + { + _dbus_verbose ("%s: leftover message found\n", + _DBUS_FUNCTION_NAME); + return FALSE; + } + else + return TRUE; +} + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_hello_message (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + DBusMessage *name_message; + dbus_uint32_t serial; + dbus_bool_t retval; + DBusError error; + const char *name; + const char *acquired; + + retval = FALSE; + dbus_error_init (&error); + name = NULL; + acquired = NULL; + message = NULL; + name_message = NULL; + + _dbus_verbose ("check_hello_message for %p\n", connection); + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "Hello"); + + if (message == NULL) + return TRUE; + + dbus_connection_ref (connection); /* because we may get disconnected */ + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + dbus_connection_unref (connection); + return TRUE; + } + + _dbus_assert (dbus_message_has_signature (message, "")); + + dbus_message_unref (message); + message = NULL; + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected (presumably auth failed)\n"); + + dbus_connection_unref (connection); + + return TRUE; + } + + /* send our message */ + bus_test_run_clients_loop (SEND_PENDING (connection)); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected (presumably auth failed)\n"); + + dbus_connection_unref (connection); + + return TRUE; + } + + block_connection_until_message_from_bus (context, connection, "reply to Hello"); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected (presumably auth failed)\n"); + + dbus_connection_unref (connection); + + return TRUE; + } + + dbus_connection_unref (connection); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "Hello", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + CheckServiceOwnerChangedData socd; + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) + { + ; /* good, expected */ + } + else + { + warn_unexpected (connection, message, "method return for Hello"); + + goto out; + } + + retry_get_hello_name: + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) + { + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + _dbus_verbose ("no memory to get service name arg from hello\n"); + dbus_error_free (&error); + _dbus_wait_for_memory (); + goto retry_get_hello_name; + } + else + { + _dbus_assert (dbus_error_is_set (&error)); + _dbus_warn ("Did not get the expected single string argument to hello\n"); + goto out; + } + } + + _dbus_verbose ("Got hello name: %s\n", name); + + while (!dbus_bus_set_unique_name (connection, name)) + _dbus_wait_for_memory (); + + socd.expected_kind = SERVICE_CREATED; + socd.expected_service_name = name; + socd.failed = FALSE; + socd.skip_connection = connection; /* we haven't done AddMatch so won't get it ourselves */ + bus_test_clients_foreach (check_service_owner_changed_foreach, + &socd); + + if (socd.failed) + goto out; + + name_message = message; + /* Client should also have gotten ServiceAcquired */ + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Expecting %s, got nothing\n", + "NameAcquired"); + goto out; + } + if (! dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, + "NameAcquired")) + { + _dbus_warn ("Expecting %s, got smthg else\n", + "NameAcquired"); + goto out; + } + + retry_get_acquired_name: + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &acquired, + DBUS_TYPE_INVALID)) + { + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + _dbus_verbose ("no memory to get service name arg from acquired\n"); + dbus_error_free (&error); + _dbus_wait_for_memory (); + goto retry_get_acquired_name; + } + else + { + _dbus_assert (dbus_error_is_set (&error)); + _dbus_warn ("Did not get the expected single string argument to ServiceAcquired\n"); + goto out; + } + } + + _dbus_verbose ("Got acquired name: %s\n", acquired); + + if (strcmp (acquired, name) != 0) + { + _dbus_warn ("Acquired name is %s but expected %s\n", + acquired, name); + goto out; + } + acquired = NULL; + } + + if (!check_no_leftovers (context)) + goto out; + + retval = TRUE; + + out: + _dbus_verbose ("ending %s retval = %d\n", _DBUS_FUNCTION_NAME, retval); + + dbus_error_free (&error); + + if (message) + dbus_message_unref (message); + + if (name_message) + dbus_message_unref (name_message); + + return retval; +} + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_double_hello_message (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + DBusError error; + + retval = FALSE; + dbus_error_init (&error); + message = NULL; + + _dbus_verbose ("check_double_hello_message for %p\n", connection); + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "Hello"); + + if (message == NULL) + return TRUE; + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + /* send our message */ + bus_test_run_clients_loop (SEND_PENDING (connection)); + + dbus_connection_ref (connection); /* because we may get disconnected */ + block_connection_until_message_from_bus (context, connection, "reply to Hello"); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + + dbus_connection_unref (connection); + + return TRUE; + } + + dbus_connection_unref (connection); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "Hello", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) + { + warn_unexpected (connection, message, "method return for Hello"); + goto out; + } + + if (!check_no_leftovers (context)) + goto out; + + retval = TRUE; + + out: + dbus_error_free (&error); + + if (message) + dbus_message_unref (message); + + return retval; +} + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_get_connection_unix_user (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + DBusError error; + const char *base_service_name; + dbus_uint32_t uid; + + retval = FALSE; + dbus_error_init (&error); + message = NULL; + + _dbus_verbose ("check_get_connection_unix_user for %p\n", connection); + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetConnectionUnixUser"); + + if (message == NULL) + return TRUE; + + base_service_name = dbus_bus_get_unique_name (connection); + + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &base_service_name, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + /* send our message */ + bus_test_run_clients_loop (SEND_PENDING (connection)); + + dbus_message_unref (message); + message = NULL; + + dbus_connection_ref (connection); /* because we may get disconnected */ + block_connection_until_message_from_bus (context, connection, "reply to GetConnectionUnixUser"); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + + dbus_connection_unref (connection); + + return TRUE; + } + + dbus_connection_unref (connection); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "GetConnectionUnixUser", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (dbus_message_is_error (message, DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) + { + ; /* good, expected */ + } + else + { + warn_unexpected (connection, message, + "method_return for GetConnectionUnixUser"); + + goto out; + } + + retry_get_property: + + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_UINT32, &uid, + DBUS_TYPE_INVALID)) + { + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + _dbus_verbose ("no memory to get uid by GetConnectionUnixUser\n"); + dbus_error_free (&error); + _dbus_wait_for_memory (); + goto retry_get_property; + } + else + { + _dbus_assert (dbus_error_is_set (&error)); + _dbus_warn ("Did not get the expected DBUS_TYPE_UINT32 from GetConnectionUnixUser\n"); + goto out; + } + } + } + + if (!check_no_leftovers (context)) + goto out; + + retval = TRUE; + + out: + dbus_error_free (&error); + + if (message) + dbus_message_unref (message); + + return retval; +} + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_get_connection_unix_process_id (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + DBusError error; + const char *base_service_name; + dbus_uint32_t pid; + + retval = FALSE; + dbus_error_init (&error); + message = NULL; + + _dbus_verbose ("check_get_connection_unix_process_id for %p\n", connection); + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetConnectionUnixProcessID"); + + if (message == NULL) + return TRUE; + + base_service_name = dbus_bus_get_unique_name (connection); + + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &base_service_name, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + /* send our message */ + bus_test_run_clients_loop (SEND_PENDING (connection)); + + dbus_message_unref (message); + message = NULL; + + dbus_connection_ref (connection); /* because we may get disconnected */ + block_connection_until_message_from_bus (context, connection, "reply to GetConnectionUnixProcessID"); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + + dbus_connection_unref (connection); + + return TRUE; + } + + dbus_connection_unref (connection); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "GetConnectionUnixProcessID", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (dbus_message_is_error (message, DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } +#ifdef DBUS_WIN + else if (dbus_message_is_error (message, DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN)) + { + /* We are expecting this error, since we know in the test suite we aren't + * talking to a client running on UNIX + */ + _dbus_verbose ("Windows correctly does not support GetConnectionUnixProcessID\n"); + } +#endif + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { +#ifdef DBUS_WIN + warn_unexpected (connection, message, "GetConnectionUnixProcessID to fail on Windows"); + goto out; +#else + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) + { + ; /* good, expected */ + } + else + { + warn_unexpected (connection, message, + "method_return for GetConnectionUnixProcessID"); + + goto out; + } + + retry_get_property: + + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_UINT32, &pid, + DBUS_TYPE_INVALID)) + { + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + _dbus_verbose ("no memory to get pid by GetConnectionUnixProcessID\n"); + dbus_error_free (&error); + _dbus_wait_for_memory (); + goto retry_get_property; + } + else + { + _dbus_assert (dbus_error_is_set (&error)); + _dbus_warn ("Did not get the expected DBUS_TYPE_UINT32 from GetConnectionUnixProcessID\n"); + goto out; + } + } + else + { + /* test if returned pid is the same as our own pid + * + * @todo It would probably be good to restructure the tests + * in a way so our parent is the bus that we're testing + * cause then we can test that the pid returned matches + * getppid() + */ + if (pid != (dbus_uint32_t) _dbus_getpid ()) + { + _dbus_assert (dbus_error_is_set (&error)); + _dbus_warn ("Result from GetConnectionUnixProcessID is not our own pid\n"); + goto out; + } + } +#endif /* !DBUS_WIN */ + } + + if (!check_no_leftovers (context)) + goto out; + + retval = TRUE; + + out: + dbus_error_free (&error); + + if (message) + dbus_message_unref (message); + + return retval; +} + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_add_match_all (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_bool_t retval; + dbus_uint32_t serial; + DBusError error; + const char *empty = ""; + + retval = FALSE; + dbus_error_init (&error); + message = NULL; + + _dbus_verbose ("check_add_match_all for %p\n", connection); + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "AddMatch"); + + if (message == NULL) + return TRUE; + + /* empty string match rule matches everything */ + if (!dbus_message_append_args (message, DBUS_TYPE_STRING, &empty, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + dbus_connection_ref (connection); /* because we may get disconnected */ + + /* send our message */ + bus_test_run_clients_loop (SEND_PENDING (connection)); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + + dbus_connection_unref (connection); + + return TRUE; + } + + block_connection_until_message_from_bus (context, connection, "reply to AddMatch"); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + + dbus_connection_unref (connection); + + return TRUE; + } + + dbus_connection_unref (connection); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "AddMatch", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) + { + ; /* good, expected */ + _dbus_assert (dbus_message_get_reply_serial (message) == serial); + } + else + { + warn_unexpected (connection, message, "method return for AddMatch"); + + goto out; + } + } + + if (!check_no_leftovers (context)) + goto out; + + retval = TRUE; + + out: + dbus_error_free (&error); + + if (message) + dbus_message_unref (message); + + return retval; +} + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_hello_connection (BusContext *context) +{ + DBusConnection *connection; + DBusError error; + + dbus_error_init (&error); + + connection = dbus_connection_open_private ("debug-pipe:name=test-server", &error); + if (connection == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (&error); + dbus_error_free (&error); + return TRUE; + } + + if (!bus_setup_debug_client (connection)) + { + dbus_connection_close (connection); + dbus_connection_unref (connection); + return TRUE; + } + + spin_connection_until_authenticated (context, connection); + + if (!check_hello_message (context, connection)) + return FALSE; + + if (dbus_bus_get_unique_name (connection) == NULL) + { + /* We didn't successfully register, so we can't + * do the usual kill_client_connection() checks + */ + kill_client_connection_unchecked (connection); + } + else + { + if (!check_add_match_all (context, connection)) + return FALSE; + + kill_client_connection (context, connection); + } + + return TRUE; +} + +#define NONEXISTENT_SERVICE_NAME "test.this.service.does.not.exist.ewuoiurjdfxcvn" + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_nonexistent_service_no_auto_start (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + const char *nonexistent = NONEXISTENT_SERVICE_NAME; + dbus_uint32_t flags; + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "StartServiceByName"); + + if (message == NULL) + return TRUE; + + dbus_message_set_auto_start (message, FALSE); + + flags = 0; + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &nonexistent, + DBUS_TYPE_UINT32, &flags, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + block_connection_until_message_from_bus (context, connection, "reply to ActivateService on nonexistent"); + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "StartServiceByName", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_SERVICE_UNKNOWN)) + { + ; /* good, this is expected also */ + } + else + { + warn_unexpected (connection, message, "not this error"); + goto out; + } + } + else + { + _dbus_warn ("Did not expect to successfully activate %s\n", + NONEXISTENT_SERVICE_NAME); + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_nonexistent_service_auto_start (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + + message = dbus_message_new_method_call (NONEXISTENT_SERVICE_NAME, + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Echo"); + + if (message == NULL) + return TRUE; + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + block_connection_until_message_from_bus (context, connection, "reply to Echo"); + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "Echo message (auto activation)", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_SERVICE_UNKNOWN)) + { + ; /* good, this is expected also */ + } + else + { + warn_unexpected (connection, message, "not this error"); + goto out; + } + } + else + { + _dbus_warn ("Did not expect to successfully activate %s\n", + NONEXISTENT_SERVICE_NAME); + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} + +static dbus_bool_t +check_base_service_activated (BusContext *context, + DBusConnection *connection, + DBusMessage *initial_message, + const char **base_service_p) +{ + DBusMessage *message; + dbus_bool_t retval; + DBusError error; + const char *base_service, *base_service_from_bus, *old_owner; + + retval = FALSE; + + dbus_error_init (&error); + base_service = NULL; + old_owner = NULL; + base_service_from_bus = NULL; + + message = initial_message; + dbus_message_ref (message); + + if (dbus_message_is_signal (message, + DBUS_INTERFACE_DBUS, + "NameOwnerChanged")) + { + CheckServiceOwnerChangedData socd; + + reget_service_name_arg: + base_service = NULL; + old_owner = NULL; + base_service_from_bus = NULL; + + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &base_service, + DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &base_service_from_bus, + DBUS_TYPE_INVALID)) + { + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + dbus_error_free (&error); + _dbus_wait_for_memory (); + goto reget_service_name_arg; + } + else + { + _dbus_warn ("Message %s doesn't have a service name: %s\n", + "NameOwnerChanged (creation)", + error.message); + goto out; + } + } + + if (*base_service != ':') + { + _dbus_warn ("Expected base service activation, got \"%s\" instead\n", + base_service); + goto out; + } + + if (strcmp (base_service, base_service_from_bus) != 0) + { + _dbus_warn ("Expected base service activation, got \"%s\" instead with owner \"%s\"\n", + base_service, base_service_from_bus); + goto out; + } + + if (old_owner[0]) + { + _dbus_warn ("Received an old_owner argument during base service activation, \"%s\"\n", + old_owner); + goto out; + } + + socd.expected_kind = SERVICE_CREATED; + socd.expected_service_name = base_service; + socd.failed = FALSE; + socd.skip_connection = connection; + bus_test_clients_foreach (check_service_owner_changed_foreach, + &socd); + + if (socd.failed) + goto out; + } + else + { + warn_unexpected (connection, message, "NameOwnerChanged (creation) for base service"); + + goto out; + } + + if (base_service_p) + *base_service_p = base_service; + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + dbus_error_free (&error); + + return retval; +} + +static dbus_bool_t +check_service_activated (BusContext *context, + DBusConnection *connection, + const char *activated_name, + const char *base_service_name, + DBusMessage *initial_message) +{ + DBusMessage *message; + dbus_bool_t retval; + DBusError error; + dbus_uint32_t activation_result; + + retval = FALSE; + + dbus_error_init (&error); + + message = initial_message; + dbus_message_ref (message); + + if (dbus_message_is_signal (message, + DBUS_INTERFACE_DBUS, + "NameOwnerChanged")) + { + CheckServiceOwnerChangedData socd; + const char *service_name, *base_service_from_bus, *old_owner; + + reget_service_name_arg: + service_name = NULL; + old_owner = NULL; + base_service_from_bus = NULL; + + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &service_name, + DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &base_service_from_bus, + DBUS_TYPE_INVALID)) + { + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + dbus_error_free (&error); + _dbus_wait_for_memory (); + goto reget_service_name_arg; + } + else + { + _dbus_warn ("Message %s doesn't have a service name: %s\n", + "NameOwnerChanged (creation)", + error.message); + goto out; + } + } + + if (strcmp (service_name, activated_name) != 0) + { + _dbus_warn ("Expected to see service %s created, saw %s instead\n", + activated_name, service_name); + goto out; + } + + if (strcmp (base_service_name, base_service_from_bus) != 0) + { + _dbus_warn ("NameOwnerChanged reports wrong base service: %s owner, expected %s instead\n", + base_service_from_bus, base_service_name); + goto out; + } + + if (old_owner[0]) + { + _dbus_warn ("expected a %s, got a %s\n", + "NameOwnerChanged (creation)", + "NameOwnerChanged (change)"); + goto out; + } + + socd.expected_kind = SERVICE_CREATED; + socd.skip_connection = connection; + socd.failed = FALSE; + socd.expected_service_name = service_name; + bus_test_clients_foreach (check_service_owner_changed_foreach, + &socd); + + if (socd.failed) + goto out; + + dbus_message_unref (message); + service_name = NULL; + old_owner = NULL; + base_service_from_bus = NULL; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Expected a reply to %s, got nothing\n", + "StartServiceByName"); + goto out; + } + } + else + { + warn_unexpected (connection, message, "NameOwnerChanged for the activated name"); + + goto out; + } + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN) + { + warn_unexpected (connection, message, "reply to StartServiceByName"); + + goto out; + } + + activation_result = 0; + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_UINT32, &activation_result, + DBUS_TYPE_INVALID)) + { + if (!dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + _dbus_warn ("Did not have activation result first argument to %s: %s\n", + "StartServiceByName", error.message); + goto out; + } + + dbus_error_free (&error); + } + else + { + if (activation_result == DBUS_START_REPLY_SUCCESS) + ; /* Good */ + else if (activation_result == DBUS_START_REPLY_ALREADY_RUNNING) + ; /* Good also */ + else + { + _dbus_warn ("Activation result was %u, no good.\n", + activation_result); + goto out; + } + } + + dbus_message_unref (message); + message = NULL; + + if (!check_no_leftovers (context)) + { + _dbus_warn ("Messages were left over after verifying existent activation results\n"); + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + dbus_error_free (&error); + + return retval; +} + +static dbus_bool_t +check_service_auto_activated (BusContext *context, + DBusConnection *connection, + const char *activated_name, + const char *base_service_name, + DBusMessage *initial_message) +{ + DBusMessage *message; + dbus_bool_t retval; + DBusError error; + + retval = FALSE; + + dbus_error_init (&error); + + message = initial_message; + dbus_message_ref (message); + + if (dbus_message_is_signal (message, + DBUS_INTERFACE_DBUS, + "NameOwnerChanged")) + { + const char *service_name; + CheckServiceOwnerChangedData socd; + + reget_service_name_arg: + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &service_name, + DBUS_TYPE_INVALID)) + { + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + dbus_error_free (&error); + _dbus_wait_for_memory (); + goto reget_service_name_arg; + } + else + { + _dbus_warn ("Message %s doesn't have a service name: %s\n", + "NameOwnerChanged", + error.message); + dbus_error_free (&error); + goto out; + } + } + + if (strcmp (service_name, activated_name) != 0) + { + _dbus_warn ("Expected to see service %s created, saw %s instead\n", + activated_name, service_name); + goto out; + } + + socd.expected_kind = SERVICE_CREATED; + socd.expected_service_name = service_name; + socd.failed = FALSE; + socd.skip_connection = connection; + bus_test_clients_foreach (check_service_owner_changed_foreach, + &socd); + + if (socd.failed) + goto out; + + /* Note that this differs from regular activation in that we don't get a + * reply to ActivateService here. + */ + + dbus_message_unref (message); + message = NULL; + service_name = NULL; + } + else + { + warn_unexpected (connection, message, "NameOwnerChanged for the activated name"); + + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} + +static dbus_bool_t +check_service_deactivated (BusContext *context, + DBusConnection *connection, + const char *activated_name, + const char *base_service) +{ + dbus_bool_t retval; + CheckServiceOwnerChangedData socd; + + retval = FALSE; + + /* Now we are expecting ServiceOwnerChanged (deletion) messages for the base + * service and the activated_name. The base service + * notification is required to come last. + */ + socd.expected_kind = SERVICE_DELETED; + socd.expected_service_name = activated_name; + socd.failed = FALSE; + socd.skip_connection = NULL; + bus_test_clients_foreach (check_service_owner_changed_foreach, + &socd); + + if (socd.failed) + goto out; + + socd.expected_kind = SERVICE_DELETED; + socd.expected_service_name = base_service; + socd.failed = FALSE; + socd.skip_connection = NULL; + bus_test_clients_foreach (check_service_owner_changed_foreach, + &socd); + + if (socd.failed) + goto out; + + retval = TRUE; + + out: + return retval; +} + +static dbus_bool_t +check_send_exit_to_service (BusContext *context, + DBusConnection *connection, + const char *service_name, + const char *base_service) +{ + dbus_bool_t got_error; + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + + _dbus_verbose ("Sending exit message to the test service\n"); + + retval = FALSE; + + /* Kill off the test service by sending it a quit message */ + message = dbus_message_new_method_call (service_name, + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Exit"); + + if (message == NULL) + { + /* Do this again; we still need the service to exit... */ + if (!check_send_exit_to_service (context, connection, + service_name, base_service)) + goto out; + + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + + /* Do this again; we still need the service to exit... */ + if (!check_send_exit_to_service (context, connection, + service_name, base_service)) + goto out; + + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + /* send message */ + bus_test_run_clients_loop (SEND_PENDING (connection)); + + /* read it in and write it out to test service */ + bus_test_run_bus_loop (context, FALSE); + + /* see if we got an error during message bus dispatching */ + bus_test_run_clients_loop (FALSE); + message = borrow_message_waiting_for_memory (connection); + got_error = message != NULL && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR; + if (message) + { + dbus_connection_return_message (connection, message); + message = NULL; + } + + if (!got_error) + { + /* If no error, wait for the test service to exit */ + block_connection_until_message_from_bus (context, connection, "test service to exit"); + + bus_test_run_everything (context); + } + + if (got_error) + { + message = pop_message_waiting_for_memory (connection); + _dbus_assert (message != NULL); + + if (dbus_message_get_reply_serial (message) != serial) + { + warn_unexpected (connection, message, + "error with the correct reply serial"); + goto out; + } + + if (!dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + warn_unexpected (connection, message, + "a no memory error from asking test service to exit"); + goto out; + } + + _dbus_verbose ("Got error %s when asking test service to exit\n", + dbus_message_get_error_name (message)); + + /* Do this again; we still need the service to exit... */ + if (!check_send_exit_to_service (context, connection, + service_name, base_service)) + goto out; + } + else + { + if (!check_service_deactivated (context, connection, + service_name, base_service)) + goto out; + + /* Should now have a NoReply error from the Exit() method + * call; it should have come after all the deactivation + * stuff. + */ + message = pop_message_waiting_for_memory (connection); + + if (message == NULL) + { + warn_unexpected (connection, NULL, + "reply to Exit() method call"); + goto out; + } + if (!dbus_message_is_error (message, + DBUS_ERROR_NO_REPLY)) + { + warn_unexpected (connection, message, + "NoReply error from Exit() method call"); + goto out; + } + + if (dbus_message_get_reply_serial (message) != serial) + { + warn_unexpected (connection, message, + "error with the correct reply serial"); + goto out; + } + + _dbus_verbose ("Got error %s after test service exited\n", + dbus_message_get_error_name (message)); + + if (!check_no_leftovers (context)) + { + _dbus_warn ("Messages were left over after %s\n", + _DBUS_FUNCTION_NAME); + goto out; + } + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} + +static dbus_bool_t +check_got_error (BusContext *context, + DBusConnection *connection, + const char *first_error_name, + ...) +{ + DBusMessage *message; + dbus_bool_t retval; + va_list ap; + dbus_bool_t error_found; + const char *error_name; + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not get an expected error\n"); + goto out; + } + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) + { + warn_unexpected (connection, message, "an error"); + + goto out; + } + + error_found = FALSE; + + va_start (ap, first_error_name); + error_name = first_error_name; + while (error_name != NULL) + { + if (dbus_message_is_error (message, error_name)) + { + error_found = TRUE; + break; + } + error_name = va_arg (ap, char*); + } + va_end (ap); + + if (!error_found) + { + _dbus_warn ("Expected error %s or other, got %s instead\n", + first_error_name, + dbus_message_get_error_name (message)); + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} + +typedef enum +{ + GOT_SERVICE_CREATED, + GOT_SERVICE_DELETED, + GOT_ERROR, + GOT_SOMETHING_ELSE +} GotServiceInfo; + +static GotServiceInfo +check_got_service_info (DBusMessage *message) +{ + GotServiceInfo message_kind; + + if (dbus_message_is_signal (message, + DBUS_INTERFACE_DBUS, + "NameOwnerChanged")) + { + DBusError error; + const char *service_name, *old_owner, *new_owner; + dbus_error_init (&error); + + reget_service_info_data: + service_name = NULL; + old_owner = NULL; + new_owner = NULL; + + dbus_message_get_args (message, &error, + DBUS_TYPE_STRING, &service_name, + DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &new_owner, + DBUS_TYPE_INVALID); + if (dbus_error_is_set (&error)) + { + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + dbus_error_free (&error); + goto reget_service_info_data; + } + else + { + _dbus_warn ("unexpected arguments for NameOwnerChanged message\n"); + message_kind = GOT_SOMETHING_ELSE; + } + } + else if (!old_owner[0]) + message_kind = GOT_SERVICE_CREATED; + else if (!new_owner[0]) + message_kind = GOT_SERVICE_DELETED; + else + message_kind = GOT_SOMETHING_ELSE; + + dbus_error_free (&error); + } + else if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + message_kind = GOT_ERROR; + else + message_kind = GOT_SOMETHING_ELSE; + + return message_kind; +} + +#define EXISTENT_SERVICE_NAME "org.freedesktop.DBus.TestSuiteEchoService" + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_existent_service_no_auto_start (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + DBusMessage *base_service_message; + const char *base_service; + dbus_uint32_t serial; + dbus_bool_t retval; + const char *existent = EXISTENT_SERVICE_NAME; + dbus_uint32_t flags; + + base_service_message = NULL; + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "StartServiceByName"); + + if (message == NULL) + return TRUE; + + dbus_message_set_auto_start (message, FALSE); + + flags = 0; + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &existent, + DBUS_TYPE_UINT32, &flags, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + + /* now wait for the message bus to hear back from the activated + * service. + */ + block_connection_until_message_from_bus (context, connection, "activated service to connect"); + + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive any messages after %s %d on %p\n", + "StartServiceByName", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + _dbus_verbose (" (after sending %s)\n", "StartServiceByName"); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_SPAWN_CHILD_EXITED) || + dbus_message_is_error (message, + DBUS_ERROR_SPAWN_CHILD_SIGNALED) || + dbus_message_is_error (message, + DBUS_ERROR_SPAWN_EXEC_FAILED)) + { + ; /* good, this is expected also */ + } + else + { + _dbus_warn ("Did not expect error %s\n", + dbus_message_get_error_name (message)); + goto out; + } + } + else + { + GotServiceInfo message_kind; + + if (!check_base_service_activated (context, connection, + message, &base_service)) + goto out; + + base_service_message = message; + message = NULL; + + /* We may need to block here for the test service to exit or finish up */ + block_connection_until_message_from_bus (context, connection, "test service to exit or finish up"); + + message = dbus_connection_borrow_message (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive any messages after base service creation notification\n"); + goto out; + } + + message_kind = check_got_service_info (message); + + dbus_connection_return_message (connection, message); + message = NULL; + + switch (message_kind) + { + case GOT_SOMETHING_ELSE: + _dbus_warn ("Unexpected message after ActivateService " + "(should be an error or a service announcement"); + goto out; + + case GOT_ERROR: + if (!check_got_error (context, connection, + DBUS_ERROR_SPAWN_CHILD_EXITED, + DBUS_ERROR_NO_MEMORY, + NULL)) + goto out; + /* A service deleted should be coming along now after this error. + * We can also get the error *after* the service deleted. + */ + + /* fall through */ + + case GOT_SERVICE_DELETED: + { + /* The service started up and got a base address, but then + * failed to register under EXISTENT_SERVICE_NAME + */ + CheckServiceOwnerChangedData socd; + + socd.expected_kind = SERVICE_DELETED; + socd.expected_service_name = base_service; + socd.failed = FALSE; + socd.skip_connection = NULL; + + bus_test_clients_foreach (check_service_owner_changed_foreach, + &socd); + + if (socd.failed) + goto out; + + /* Now we should get an error about the service exiting + * if we didn't get it before. + */ + if (message_kind != GOT_ERROR) + { + block_connection_until_message_from_bus (context, connection, "error about service exiting"); + + /* and process everything again */ + bus_test_run_everything (context); + + if (!check_got_error (context, connection, + DBUS_ERROR_SPAWN_CHILD_EXITED, + DBUS_ERROR_NO_MEMORY, + NULL)) + goto out; + } + break; + } + + case GOT_SERVICE_CREATED: + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Failed to pop message we just put back! " + "should have been a NameOwnerChanged (creation)\n"); + goto out; + } + + if (!check_service_activated (context, connection, EXISTENT_SERVICE_NAME, + base_service, message)) + goto out; + + dbus_message_unref (message); + message = NULL; + + if (!check_no_leftovers (context)) + { + _dbus_warn ("Messages were left over after successful activation\n"); + goto out; + } + + if (!check_send_exit_to_service (context, connection, + EXISTENT_SERVICE_NAME, base_service)) + goto out; + + break; + } + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + if (base_service_message) + dbus_message_unref (base_service_message); + + return retval; +} + +#ifndef DBUS_WIN_FIXME +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_segfault_service_no_auto_start (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + const char *segv_service; + dbus_uint32_t flags; + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "StartServiceByName"); + + if (message == NULL) + return TRUE; + + dbus_message_set_auto_start (message, FALSE); + + segv_service = "org.freedesktop.DBus.TestSuiteSegfaultService"; + flags = 0; + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &segv_service, + DBUS_TYPE_UINT32, &flags, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + block_connection_until_message_from_bus (context, connection, "reply to activating segfault service"); + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "StartServiceByName", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_FAILED)) + { + const char *servicehelper; + servicehelper = bus_context_get_servicehelper (context); + /* make sure this only happens with the launch helper */ + _dbus_assert (servicehelper != NULL); + } + else if (dbus_message_is_error (message, + DBUS_ERROR_SPAWN_CHILD_SIGNALED)) + { + ; /* good, this is expected also */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + _dbus_warn ("Did not expect to successfully activate segfault service\n"); + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} + + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_segfault_service_auto_start (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + + message = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteSegfaultService", + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Echo"); + + if (message == NULL) + return TRUE; + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + block_connection_until_message_from_bus (context, connection, "reply to Echo on segfault service"); + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "Echo message (auto activation)", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_SPAWN_CHILD_SIGNALED)) + { + ; /* good, this is expected also */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + _dbus_warn ("Did not expect to successfully activate segfault service\n"); + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} +#endif + +#define TEST_ECHO_MESSAGE "Test echo message" +#define TEST_RUN_HELLO_FROM_SELF_MESSAGE "Test sending message to self" + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_existent_hello_from_self (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + const char *text; + + message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME, + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "RunHelloFromSelf"); + + if (message == NULL) + return TRUE; + + text = TEST_RUN_HELLO_FROM_SELF_MESSAGE; + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + + /* Note: if this test is run in OOM mode, it will block when the bus + * doesn't send a reply due to OOM. + */ + block_connection_until_message_from_bus (context, connection, "reply from running hello from self"); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Failed to pop message! Should have been reply from RunHelloFromSelf message\n"); + return FALSE; + } + + if (dbus_message_get_reply_serial (message) != serial) + { + _dbus_warn ("Wrong reply serial\n"); + dbus_message_unref (message); + return FALSE; + } + + dbus_message_unref (message); + message = NULL; + + return TRUE; +} + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_existent_ping (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME, + "/org/freedesktop/TestSuite", + "org.freedesktop.DBus.Peer", + "Ping"); + + if (message == NULL) + return TRUE; + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + + /* Note: if this test is run in OOM mode, it will block when the bus + * doesn't send a reply due to OOM. + */ + block_connection_until_message_from_bus (context, connection, "reply from running Ping"); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Failed to pop message! Should have been reply from Ping message\n"); + return FALSE; + } + + if (dbus_message_get_reply_serial (message) != serial) + { + _dbus_warn ("Wrong reply serial\n"); + dbus_message_unref (message); + return FALSE; + } + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN) + { + _dbus_warn ("Unexpected message return during Ping\n"); + dbus_message_unref (message); + return FALSE; + } + + dbus_message_unref (message); + message = NULL; + + return TRUE; +} + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_existent_get_machine_id (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + const char *machine_id; + + message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME, + "/org/freedesktop/TestSuite", + "org.freedesktop.DBus.Peer", + "GetMachineId"); + + if (message == NULL) + return TRUE; + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + + /* Note: if this test is run in OOM mode, it will block when the bus + * doesn't send a reply due to OOM. + */ + block_connection_until_message_from_bus (context, connection, "reply from running GetMachineId"); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Failed to pop message! Should have been reply from GetMachineId message\n"); + return FALSE; + } + + if (dbus_message_get_reply_serial (message) != serial) + { + _dbus_warn ("Wrong reply serial\n"); + dbus_message_unref (message); + return FALSE; + } + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN) + { + _dbus_warn ("Unexpected message return during GetMachineId\n"); + dbus_message_unref (message); + return FALSE; + } + + machine_id = NULL; + if (!dbus_message_get_args (message, NULL, DBUS_TYPE_STRING, &machine_id, DBUS_TYPE_INVALID)) + { + _dbus_warn ("Did not get a machine ID in reply to GetMachineId\n"); + dbus_message_unref (message); + return FALSE; + } + + if (machine_id == NULL || strlen (machine_id) != 32) + { + _dbus_warn ("Machine id looks bogus: '%s'\n", machine_id ? machine_id : "null"); + dbus_message_unref (message); + return FALSE; + } + + /* We can't check that the machine id is correct because during make check it is + * just made up for each process separately + */ + + dbus_message_unref (message); + message = NULL; + + return TRUE; +} + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_existent_service_auto_start (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + DBusMessage *base_service_message; + dbus_uint32_t serial; + dbus_bool_t retval; + const char *base_service; + const char *text; + + base_service_message = NULL; + + message = dbus_message_new_method_call (EXISTENT_SERVICE_NAME, + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Echo"); + + if (message == NULL) + return TRUE; + + text = TEST_ECHO_MESSAGE; + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + + /* now wait for the message bus to hear back from the activated + * service. + */ + block_connection_until_message_from_bus (context, connection, "reply to Echo on existent service"); + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive any messages after auto start %d on %p\n", + serial, connection); + goto out; + } + + verbose_message_received (connection, message); + _dbus_verbose (" (after sending %s)\n", "auto start"); + + /* we should get zero or two ServiceOwnerChanged signals */ + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL) + { + GotServiceInfo message_kind; + + if (!check_base_service_activated (context, connection, + message, &base_service)) + goto out; + + base_service_message = message; + message = NULL; + + /* We may need to block here for the test service to exit or finish up */ + block_connection_until_message_from_bus (context, connection, "service to exit"); + + /* Should get a service creation notification for the activated + * service name, or a service deletion on the base service name + */ + message = dbus_connection_borrow_message (connection); + if (message == NULL) + { + _dbus_warn ("No message after auto activation " + "(should be a service announcement)\n"); + dbus_connection_return_message (connection, message); + message = NULL; + goto out; + } + + message_kind = check_got_service_info (message); + + dbus_connection_return_message (connection, message); + message = NULL; + + switch (message_kind) + { + case GOT_SERVICE_CREATED: + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Failed to pop message we just put back! " + "should have been a NameOwnerChanged (creation)\n"); + goto out; + } + + /* Check that ServiceOwnerChanged (creation) was correctly received */ + if (!check_service_auto_activated (context, connection, EXISTENT_SERVICE_NAME, + base_service, message)) + goto out; + + dbus_message_unref (message); + message = NULL; + + break; + + case GOT_SERVICE_DELETED: + { + /* The service started up and got a base address, but then + * failed to register under EXISTENT_SERVICE_NAME + */ + CheckServiceOwnerChangedData socd; + + socd.expected_kind = SERVICE_DELETED; + socd.expected_service_name = base_service; + socd.failed = FALSE; + socd.skip_connection = NULL; + bus_test_clients_foreach (check_service_owner_changed_foreach, + &socd); + + if (socd.failed) + goto out; + + break; + } + + case GOT_ERROR: + case GOT_SOMETHING_ELSE: + _dbus_warn ("Unexpected message after auto activation\n"); + goto out; + } + } + + /* OK, now we've dealt with ServiceOwnerChanged signals, now should + * come the method reply (or error) from the initial method call + */ + + /* Note: if this test is run in OOM mode, it will block when the bus + * doesn't send a reply due to OOM. + */ + block_connection_until_message_from_bus (context, connection, "reply from echo message after auto-activation"); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Failed to pop message! Should have been reply from echo message\n"); + goto out; + } + + if (dbus_message_get_reply_serial (message) != serial) + { + _dbus_warn ("Wrong reply serial\n"); + goto out; + } + + dbus_message_unref (message); + message = NULL; + + if (!check_existent_ping (context, connection)) + goto out; + + if (!check_existent_get_machine_id (context, connection)) + goto out; + + if (!check_existent_hello_from_self (context, connection)) + goto out; + + if (!check_send_exit_to_service (context, connection, + EXISTENT_SERVICE_NAME, + base_service)) + goto out; + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + if (base_service_message) + dbus_message_unref (base_service_message); + + return retval; +} + +#define SERVICE_FILE_MISSING_NAME "org.freedesktop.DBus.TestSuiteEchoServiceDotServiceFileDoesNotExist" + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_launch_service_file_missing (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + + message = dbus_message_new_method_call (SERVICE_FILE_MISSING_NAME, + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Echo"); + + if (message == NULL) + return TRUE; + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + block_connection_until_message_from_bus (context, connection, "reply to service file missing should fail to auto-start"); + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "Echo message (auto activation)", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_SERVICE_UNKNOWN)) + { + _dbus_verbose("got service unknown\n"); + ; /* good, this is expected (only valid when using launch helper) */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + _dbus_warn ("Did not expect to successfully auto-start missing service\n"); + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} + +#define SERVICE_USER_MISSING_NAME "org.freedesktop.DBus.TestSuiteNoUser" + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_launch_service_user_missing (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + + message = dbus_message_new_method_call (SERVICE_USER_MISSING_NAME, + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Echo"); + + if (message == NULL) + return TRUE; + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + block_connection_until_message_from_bus (context, connection, + "reply to service which should fail to auto-start (missing User)"); + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_warn ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "Echo message (auto activation)", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_SPAWN_FILE_INVALID)) + { + _dbus_verbose("got service file invalid\n"); + ; /* good, this is expected (only valid when using launch helper) */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + _dbus_warn ("Did not expect to successfully auto-start missing service\n"); + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} + +#define SERVICE_EXEC_MISSING_NAME "org.freedesktop.DBus.TestSuiteNoExec" + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_launch_service_exec_missing (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + + message = dbus_message_new_method_call (SERVICE_EXEC_MISSING_NAME, + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Echo"); + + if (message == NULL) + return TRUE; + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + block_connection_until_message_from_bus (context, connection, + "reply to service which should fail to auto-start (missing Exec)"); + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_warn ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "Echo message (auto activation)", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_SERVICE_UNKNOWN)) + { + _dbus_verbose("could not activate as invalid service file was not added\n"); + ; /* good, this is expected as we shouldn't have been added to + * the activation list with a missing Exec key */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_SPAWN_FILE_INVALID)) + { + _dbus_verbose("got service file invalid\n"); + ; /* good, this is allowed, and is the message passed back from the + * launch helper */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + _dbus_warn ("Did not expect to successfully auto-start missing service\n"); + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} + +#define SERVICE_SERVICE_MISSING_NAME "org.freedesktop.DBus.TestSuiteNoService" + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_launch_service_service_missing (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + + message = dbus_message_new_method_call (SERVICE_SERVICE_MISSING_NAME, + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Echo"); + + if (message == NULL) + return TRUE; + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + block_connection_until_message_from_bus (context, connection, + "reply to service which should fail to auto-start (missing Service)"); + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_warn ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "Echo message (auto activation)", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_SERVICE_UNKNOWN)) + { + _dbus_verbose("could not activate as invalid service file was not added\n"); + ; /* good, this is expected as we shouldn't have been added to + * the activation list with a missing Exec key */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_SPAWN_FILE_INVALID)) + { + _dbus_verbose("got service file invalid\n"); + ; /* good, this is allowed, and is the message passed back from the + * launch helper */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + _dbus_warn ("Did not expect to successfully auto-start missing service\n"); + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} + +#define SHELL_FAIL_SERVICE_NAME "org.freedesktop.DBus.TestSuiteShellEchoServiceFail" + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_shell_fail_service_auto_start (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + + message = dbus_message_new_method_call (SHELL_FAIL_SERVICE_NAME, + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Echo"); + + if (message == NULL) + return TRUE; + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + block_connection_until_message_from_bus (context, connection, "reply to shell Echo on service which should fail to auto-start"); + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + "Echo message (auto activation)", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_INVALID_ARGS)) + { + _dbus_verbose("got invalid args\n"); + ; /* good, this is expected also */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + _dbus_warn ("Did not expect to successfully auto-start shell fail service\n"); + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} + +#define SHELL_SUCCESS_SERVICE_NAME "org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess" + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_shell_service_success_auto_start (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + DBusMessage *base_service_message; + dbus_uint32_t serial; + dbus_bool_t retval; + const char *base_service; + const char *argv[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + + base_service_message = NULL; + + message = dbus_message_new_method_call (SHELL_SUCCESS_SERVICE_NAME, + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Echo"); + + if (message == NULL) + return TRUE; + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + + /* now wait for the message bus to hear back from the activated + * service. + */ + block_connection_until_message_from_bus (context, connection, "reply to Echo on shell success service"); + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive any messages after auto start %d on %p\n", + serial, connection); + goto out; + } + + verbose_message_received (connection, message); + _dbus_verbose (" (after sending %s)\n", "auto start"); + + /* we should get zero or two ServiceOwnerChanged signals */ + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL) + { + GotServiceInfo message_kind; + + if (!check_base_service_activated (context, connection, + message, &base_service)) + goto out; + + base_service_message = message; + message = NULL; + + /* We may need to block here for the test service to exit or finish up */ + block_connection_until_message_from_bus (context, connection, "service to exit"); + + /* Should get a service creation notification for the activated + * service name, or a service deletion on the base service name + */ + message = dbus_connection_borrow_message (connection); + if (message == NULL) + { + _dbus_warn ("No message after auto activation " + "(should be a service announcement)\n"); + dbus_connection_return_message (connection, message); + message = NULL; + goto out; + } + + message_kind = check_got_service_info (message); + + dbus_connection_return_message (connection, message); + message = NULL; + + switch (message_kind) + { + case GOT_SERVICE_CREATED: + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Failed to pop message we just put back! " + "should have been a NameOwnerChanged (creation)\n"); + goto out; + } + + /* Check that ServiceOwnerChanged (creation) was correctly received */ + if (!check_service_auto_activated (context, connection, SHELL_SUCCESS_SERVICE_NAME, + base_service, message)) + goto out; + + dbus_message_unref (message); + message = NULL; + + break; + + case GOT_SERVICE_DELETED: + { + /* The service started up and got a base address, but then + * failed to register under SHELL_SUCCESS_SERVICE_NAME + */ + CheckServiceOwnerChangedData socd; + + socd.expected_kind = SERVICE_DELETED; + socd.expected_service_name = base_service; + socd.failed = FALSE; + socd.skip_connection = NULL; + bus_test_clients_foreach (check_service_owner_changed_foreach, + &socd); + + if (socd.failed) + goto out; + + break; + } + + case GOT_ERROR: + case GOT_SOMETHING_ELSE: + _dbus_warn ("Unexpected message after auto activation\n"); + goto out; + } + } + + /* OK, now we've dealt with ServiceOwnerChanged signals, now should + * come the method reply (or error) from the initial method call + */ + + /* Note: if this test is run in OOM mode, it will block when the bus + * doesn't send a reply due to OOM. + */ + block_connection_until_message_from_bus (context, connection, "reply from echo message after auto-activation"); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Failed to pop message! Should have been reply from echo message\n"); + goto out; + } + + if (dbus_message_get_reply_serial (message) != serial) + { + _dbus_warn ("Wrong reply serial\n"); + goto out; + } + + if (!dbus_message_get_args (message, NULL, + DBUS_TYPE_STRING, &argv[0], + DBUS_TYPE_STRING, &argv[1], + DBUS_TYPE_STRING, &argv[2], + DBUS_TYPE_STRING, &argv[3], + DBUS_TYPE_STRING, &argv[4], + DBUS_TYPE_STRING, &argv[5], + DBUS_TYPE_STRING, &argv[6], + DBUS_TYPE_INVALID)) + { + _dbus_warn ("Error getting arguments from return\n"); + goto out; + } + + /* don't worry about arg[0] as it may be different + depending on the path to the tests + */ + if (strcmp("-test", argv[1]) != 0) + { + _dbus_warn ("Unexpected argv[1] in shell success service test (expected: %s, got: %s)\n", + "-test", argv[1]); + goto out; + } + + if (strcmp("that", argv[2]) != 0) + { + _dbus_warn ("Unexpected argv[2] in shell success service test (expected: %s, got: %s)\n", + "that", argv[2]); + goto out; + } + + if (strcmp("we get", argv[3]) != 0) + { + _dbus_warn ("Unexpected argv[3] in shell success service test (expected: %s, got: %s)\n", + "we get", argv[3]); + goto out; + } + + if (strcmp("back", argv[4]) != 0) + { + _dbus_warn ("Unexpected argv[4] in shell success service test (expected: %s, got: %s)\n", + "back", argv[4]); + goto out; + } + + if (strcmp("--what", argv[5]) != 0) + { + _dbus_warn ("Unexpected argv[5] in shell success service test (expected: %s, got: %s)\n", + "--what", argv[5]); + goto out; + } + + if (strcmp("we put in", argv[6]) != 0) + { + _dbus_warn ("Unexpected argv[6] in shell success service test (expected: %s, got: %s)\n", + "we put in", argv[6]); + goto out; + } + + dbus_message_unref (message); + message = NULL; + + if (!check_send_exit_to_service (context, connection, + SHELL_SUCCESS_SERVICE_NAME, + base_service)) + goto out; + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + if (base_service_message) + dbus_message_unref (base_service_message); + + return retval; +} + +typedef struct +{ + Check1Func func; + BusContext *context; +} Check1Data; + +static dbus_bool_t +check_oom_check1_func (void *data) +{ + Check1Data *d = data; + + if (! (* d->func) (d->context)) + return FALSE; + + if (!check_no_leftovers (d->context)) + { + _dbus_warn ("Messages were left over, should be covered by test suite\n"); + return FALSE; + } + + return TRUE; +} + +static void +check1_try_iterations (BusContext *context, + const char *description, + Check1Func func) +{ + Check1Data d; + + d.func = func; + d.context = context; + + if (!_dbus_test_oom_handling (description, check_oom_check1_func, + &d)) + _dbus_assert_not_reached ("test failed"); +} + +static dbus_bool_t +check_get_services (BusContext *context, + DBusConnection *connection, + const char *method, + char ***services, + int *len) +{ + DBusMessage *message; + dbus_uint32_t serial; + dbus_bool_t retval; + DBusError error; + char **srvs; + int l; + + retval = FALSE; + dbus_error_init (&error); + message = NULL; + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + method); + + if (message == NULL) + return TRUE; + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + /* send our message */ + bus_test_run_clients_loop (SEND_PENDING (connection)); + + dbus_message_unref (message); + message = NULL; + + dbus_connection_ref (connection); /* because we may get disconnected */ + block_connection_until_message_from_bus (context, connection, "reply to ListActivatableNames/ListNames"); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + + dbus_connection_unref (connection); + + return TRUE; + } + + dbus_connection_unref (connection); + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + method, serial, connection); + goto out; + } + + verbose_message_received (connection, message); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (dbus_message_is_error (message, DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else + { + warn_unexpected (connection, message, "not this error"); + + goto out; + } + } + else + { + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) + { + ; /* good, expected */ + } + else + { + warn_unexpected (connection, message, + "method_return for ListActivatableNames/ListNames"); + + goto out; + } + + retry_get_property: + + if (!dbus_message_get_args (message, &error, + DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING, + &srvs, &l, + DBUS_TYPE_INVALID)) + { + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + _dbus_verbose ("no memory to list services by %s\n", method); + dbus_error_free (&error); + _dbus_wait_for_memory (); + goto retry_get_property; + } + else + { + _dbus_assert (dbus_error_is_set (&error)); + _dbus_warn ("Did not get the expected DBUS_TYPE_ARRAY from %s\n", method); + goto out; + } + } else { + *services = srvs; + *len = l; + } + } + + if (!check_no_leftovers (context)) + goto out; + + retval = TRUE; + + out: + dbus_error_free (&error); + + if (message) + dbus_message_unref (message); + + return retval; +} + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_list_services (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + DBusMessage *base_service_message; + const char *base_service; + dbus_uint32_t serial; + dbus_bool_t retval; + const char *existent = EXISTENT_SERVICE_NAME; + dbus_uint32_t flags; + char **services; + int len; + + _dbus_verbose ("check_list_services for %p\n", connection); + + if (!check_get_services (context, connection, "ListActivatableNames", &services, &len)) + { + return TRUE; + } + + if (!_dbus_string_array_contains ((const char **)services, existent)) + { + _dbus_warn ("Did not get the expected %s from ListActivatableNames\n", existent); + return FALSE; + } + + dbus_free_string_array (services); + + base_service_message = NULL; + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "StartServiceByName"); + + if (message == NULL) + return TRUE; + + dbus_message_set_auto_start (message, FALSE); + + flags = 0; + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &existent, + DBUS_TYPE_UINT32, &flags, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + + /* now wait for the message bus to hear back from the activated + * service. + */ + block_connection_until_message_from_bus (context, connection, "activated service to connect"); + + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected: %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + return TRUE; + } + + retval = FALSE; + + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive any messages after %s %d on %p\n", + "StartServiceByName", serial, connection); + goto out; + } + + verbose_message_received (connection, message); + _dbus_verbose (" (after sending %s)\n", "StartServiceByName"); + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_is_error (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else if (dbus_message_is_error (message, + DBUS_ERROR_SPAWN_CHILD_EXITED) || + dbus_message_is_error (message, + DBUS_ERROR_SPAWN_CHILD_SIGNALED) || + dbus_message_is_error (message, + DBUS_ERROR_SPAWN_EXEC_FAILED)) + { + ; /* good, this is expected also */ + } + else + { + _dbus_warn ("Did not expect error %s\n", + dbus_message_get_error_name (message)); + goto out; + } + } + else + { + GotServiceInfo message_kind; + + if (!check_base_service_activated (context, connection, + message, &base_service)) + goto out; + + base_service_message = message; + message = NULL; + + /* We may need to block here for the test service to exit or finish up */ + block_connection_until_message_from_bus (context, connection, "test service to exit or finish up"); + + message = dbus_connection_borrow_message (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive any messages after base service creation notification\n"); + goto out; + } + + message_kind = check_got_service_info (message); + + dbus_connection_return_message (connection, message); + message = NULL; + + switch (message_kind) + { + case GOT_SOMETHING_ELSE: + case GOT_ERROR: + case GOT_SERVICE_DELETED: + _dbus_warn ("Unexpected message after ActivateService " + "(should be an error or a service announcement)\n"); + goto out; + + case GOT_SERVICE_CREATED: + message = pop_message_waiting_for_memory (connection); + if (message == NULL) + { + _dbus_warn ("Failed to pop message we just put back! " + "should have been a NameOwnerChanged (creation)\n"); + goto out; + } + + if (!check_service_activated (context, connection, EXISTENT_SERVICE_NAME, + base_service, message)) + goto out; + + dbus_message_unref (message); + message = NULL; + + if (!check_no_leftovers (context)) + { + _dbus_warn ("Messages were left over after successful activation\n"); + goto out; + } + + break; + } + } + + if (!check_get_services (context, connection, "ListNames", &services, &len)) + { + return TRUE; + } + + if (!_dbus_string_array_contains ((const char **)services, existent)) + { + _dbus_warn ("Did not get the expected %s from ListNames\n", existent); + goto out; + } + + dbus_free_string_array (services); + + if (!check_send_exit_to_service (context, connection, + EXISTENT_SERVICE_NAME, base_service)) + goto out; + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + if (base_service_message) + dbus_message_unref (base_service_message); + + return retval; +} + +typedef struct +{ + Check2Func func; + BusContext *context; + DBusConnection *connection; +} Check2Data; + +static dbus_bool_t +check_oom_check2_func (void *data) +{ + Check2Data *d = data; + + if (! (* d->func) (d->context, d->connection)) + return FALSE; + + if (!check_no_leftovers (d->context)) + { + _dbus_warn ("Messages were left over, should be covered by test suite\n"); + return FALSE; + } + + return TRUE; +} + +static void +check2_try_iterations (BusContext *context, + DBusConnection *connection, + const char *description, + Check2Func func) +{ + Check2Data d; + + d.func = func; + d.context = context; + d.connection = connection; + + if (!_dbus_test_oom_handling (description, check_oom_check2_func, + &d)) + { + _dbus_warn ("%s failed during oom\n", description); + _dbus_assert_not_reached ("test failed"); + } +} + +static dbus_bool_t +setenv_TEST_LAUNCH_HELPER_CONFIG(const DBusString *test_data_dir, + const char *filename) +{ + DBusString full; + DBusString file; + + if (!_dbus_string_init (&full)) + return FALSE; + + if (!_dbus_string_copy (test_data_dir, 0, &full, 0)) + { + _dbus_string_free (&full); + return FALSE; + } + + _dbus_string_init_const (&file, filename); + + if (!_dbus_concat_dir_and_file (&full, &file)) + { + _dbus_string_free (&full); + return FALSE; + } + + _dbus_verbose ("Setting TEST_LAUNCH_HELPER_CONFIG to '%s'\n", + _dbus_string_get_const_data (&full)); + + _dbus_setenv ("TEST_LAUNCH_HELPER_CONFIG", _dbus_string_get_const_data (&full)); + + _dbus_string_free (&full); + + return TRUE; +} + +static dbus_bool_t +bus_dispatch_test_conf (const DBusString *test_data_dir, + const char *filename, + dbus_bool_t use_launcher) +{ + BusContext *context; + DBusConnection *foo; + DBusConnection *bar; + DBusConnection *baz; + DBusError error; + + /* save the config name for the activation helper */ + if (!setenv_TEST_LAUNCH_HELPER_CONFIG (test_data_dir, filename)) + _dbus_assert_not_reached ("no memory setting TEST_LAUNCH_HELPER_CONFIG"); + + dbus_error_init (&error); + + context = bus_context_new_test (test_data_dir, filename); + if (context == NULL) + return FALSE; + + foo = dbus_connection_open_private ("debug-pipe:name=test-server", &error); + if (foo == NULL) + _dbus_assert_not_reached ("could not alloc connection"); + + if (!bus_setup_debug_client (foo)) + _dbus_assert_not_reached ("could not set up connection"); + + spin_connection_until_authenticated (context, foo); + + if (!check_hello_message (context, foo)) + _dbus_assert_not_reached ("hello message failed"); + + if (!check_double_hello_message (context, foo)) + _dbus_assert_not_reached ("double hello message failed"); + + if (!check_add_match_all (context, foo)) + _dbus_assert_not_reached ("AddMatch message failed"); + + bar = dbus_connection_open_private ("debug-pipe:name=test-server", &error); + if (bar == NULL) + _dbus_assert_not_reached ("could not alloc connection"); + + if (!bus_setup_debug_client (bar)) + _dbus_assert_not_reached ("could not set up connection"); + + spin_connection_until_authenticated (context, bar); + + if (!check_hello_message (context, bar)) + _dbus_assert_not_reached ("hello message failed"); + + if (!check_add_match_all (context, bar)) + _dbus_assert_not_reached ("AddMatch message failed"); + + baz = dbus_connection_open_private ("debug-pipe:name=test-server", &error); + if (baz == NULL) + _dbus_assert_not_reached ("could not alloc connection"); + + if (!bus_setup_debug_client (baz)) + _dbus_assert_not_reached ("could not set up connection"); + + spin_connection_until_authenticated (context, baz); + + if (!check_hello_message (context, baz)) + _dbus_assert_not_reached ("hello message failed"); + + if (!check_add_match_all (context, baz)) + _dbus_assert_not_reached ("AddMatch message failed"); + + if (!check_get_connection_unix_user (context, baz)) + _dbus_assert_not_reached ("GetConnectionUnixUser message failed"); + + if (!check_get_connection_unix_process_id (context, baz)) + _dbus_assert_not_reached ("GetConnectionUnixProcessID message failed"); + + if (!check_list_services (context, baz)) + _dbus_assert_not_reached ("ListActivatableNames message failed"); + + if (!check_no_leftovers (context)) + { + _dbus_warn ("Messages were left over after setting up initial connections\n"); + _dbus_assert_not_reached ("initial connection setup failed"); + } + + check1_try_iterations (context, "create_and_hello", + check_hello_connection); + + check2_try_iterations (context, foo, "nonexistent_service_no_auto_start", + check_nonexistent_service_no_auto_start); + +#ifdef DBUS_WIN_FIXME + _dbus_warn("TODO: dispatch.c segfault_service_no_auto_start test\n"); +#else + check2_try_iterations (context, foo, "segfault_service_no_auto_start", + check_segfault_service_no_auto_start); +#endif + + check2_try_iterations (context, foo, "existent_service_no_auto_start", + check_existent_service_no_auto_start); + + check2_try_iterations (context, foo, "nonexistent_service_auto_start", + check_nonexistent_service_auto_start); + + +#ifdef DBUS_WIN_FIXME + _dbus_warn("TODO: dispatch.c segfault_service_auto_start test\n"); +#else + /* only do the segfault test if we are not using the launcher */ + check2_try_iterations (context, foo, "segfault_service_auto_start", + check_segfault_service_auto_start); +#endif + + /* only do the shell fail test if we are not using the launcher */ + check2_try_iterations (context, foo, "shell_fail_service_auto_start", + check_shell_fail_service_auto_start); + + /* specific to launcher */ + if (use_launcher) + if (!check_launch_service_file_missing (context, foo)) + _dbus_assert_not_reached ("did not get service file not found error"); + +#if 0 + /* Note: need to resolve some issues with the testing code in order to run + * this in oom (handle that we sometimes don't get replies back from the bus + * when oom happens, without blocking the test). + */ + check2_try_iterations (context, foo, "existent_service_auto_auto_start", + check_existent_service_auto_start); +#endif + + if (!check_existent_service_auto_start (context, foo)) + _dbus_assert_not_reached ("existent service auto start failed"); + + if (!check_shell_service_success_auto_start (context, foo)) + _dbus_assert_not_reached ("shell success service auto start failed"); + + _dbus_verbose ("Disconnecting foo, bar, and baz\n"); + + kill_client_connection_unchecked (foo); + kill_client_connection_unchecked (bar); + kill_client_connection_unchecked (baz); + + bus_context_unref (context); + + return TRUE; +} + +static dbus_bool_t +bus_dispatch_test_conf_fail (const DBusString *test_data_dir, + const char *filename) +{ + BusContext *context; + DBusConnection *foo; + DBusError error; + + /* save the config name for the activation helper */ + if (!setenv_TEST_LAUNCH_HELPER_CONFIG (test_data_dir, filename)) + _dbus_assert_not_reached ("no memory setting TEST_LAUNCH_HELPER_CONFIG"); + + dbus_error_init (&error); + + context = bus_context_new_test (test_data_dir, filename); + if (context == NULL) + return FALSE; + + foo = dbus_connection_open_private ("debug-pipe:name=test-server", &error); + if (foo == NULL) + _dbus_assert_not_reached ("could not alloc connection"); + + if (!bus_setup_debug_client (foo)) + _dbus_assert_not_reached ("could not set up connection"); + + spin_connection_until_authenticated (context, foo); + + if (!check_hello_message (context, foo)) + _dbus_assert_not_reached ("hello message failed"); + + if (!check_double_hello_message (context, foo)) + _dbus_assert_not_reached ("double hello message failed"); + + if (!check_add_match_all (context, foo)) + _dbus_assert_not_reached ("AddMatch message failed"); + + /* this only tests the activation.c user check */ + if (!check_launch_service_user_missing (context, foo)) + _dbus_assert_not_reached ("user missing did not trigger error"); + + /* this only tests the desktop.c exec check */ + if (!check_launch_service_exec_missing (context, foo)) + _dbus_assert_not_reached ("exec missing did not trigger error"); + + /* this only tests the desktop.c service check */ + if (!check_launch_service_service_missing (context, foo)) + _dbus_assert_not_reached ("service missing did not trigger error"); + + _dbus_verbose ("Disconnecting foo\n"); + + kill_client_connection_unchecked (foo); + + bus_context_unref (context); + + return TRUE; +} + +dbus_bool_t +bus_dispatch_test (const DBusString *test_data_dir) +{ + /* run normal activation tests */ + _dbus_verbose ("Normal activation tests\n"); + if (!bus_dispatch_test_conf (test_data_dir, + "valid-config-files/debug-allow-all.conf", FALSE)) + return FALSE; + + /* run launch-helper activation tests */ + _dbus_verbose ("Launch helper activation tests\n"); + if (!bus_dispatch_test_conf (test_data_dir, + "valid-config-files-system/debug-allow-all-pass.conf", TRUE)) + return FALSE; + + /* run select launch-helper activation tests on broken service files */ + if (!bus_dispatch_test_conf_fail (test_data_dir, + "valid-config-files-system/debug-allow-all-fail.conf")) + return FALSE; + + return TRUE; +} + +dbus_bool_t +bus_dispatch_sha1_test (const DBusString *test_data_dir) +{ + BusContext *context; + DBusConnection *foo; + DBusError error; + + dbus_error_init (&error); + + /* Test SHA1 authentication */ + _dbus_verbose ("Testing SHA1 context\n"); + + context = bus_context_new_test (test_data_dir, + "valid-config-files/debug-allow-all-sha1.conf"); + if (context == NULL) + return FALSE; + + foo = dbus_connection_open_private ("debug-pipe:name=test-server", &error); + if (foo == NULL) + _dbus_assert_not_reached ("could not alloc connection"); + + if (!bus_setup_debug_client (foo)) + _dbus_assert_not_reached ("could not set up connection"); + + spin_connection_until_authenticated (context, foo); + + if (!check_hello_message (context, foo)) + _dbus_assert_not_reached ("hello message failed"); + + if (!check_add_match_all (context, foo)) + _dbus_assert_not_reached ("addmatch message failed"); + + if (!check_no_leftovers (context)) + { + _dbus_warn ("Messages were left over after setting up initial SHA-1 connection\n"); + _dbus_assert_not_reached ("initial connection setup failed"); + } + + check1_try_iterations (context, "create_and_hello_sha1", + check_hello_connection); + + kill_client_connection_unchecked (foo); + + bus_context_unref (context); + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/bus/dispatch.h b/bus/dispatch.h new file mode 100644 index 00000000..fb5ba7a5 --- /dev/null +++ b/bus/dispatch.h @@ -0,0 +1,38 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dispatch.h Message dispatcher + * + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_DISPATCH_H +#define BUS_DISPATCH_H + +#include +#include "connection.h" + +dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection); +void bus_dispatch_remove_connection (DBusConnection *connection); +dbus_bool_t bus_dispatch_matches (BusTransaction *transaction, + DBusConnection *sender, + DBusConnection *recipient, + DBusMessage *message, + DBusError *error); + +#endif /* BUS_DISPATCH_H */ diff --git a/bus/driver.c b/bus/driver.c new file mode 100644 index 00000000..5e8a7a26 --- /dev/null +++ b/bus/driver.c @@ -0,0 +1,2022 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* driver.c Bus client (driver) + * + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "activation.h" +#include "connection.h" +#include "driver.h" +#include "dispatch.h" +#include "services.h" +#include "selinux.h" +#include "signals.h" +#include "utils.h" +#include +#include +#include +#include +#include + +static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection, + DBusMessage *hello_message, + BusTransaction *transaction, + DBusError *error); + +dbus_bool_t +bus_driver_send_service_owner_changed (const char *service_name, + const char *old_owner, + const char *new_owner, + BusTransaction *transaction, + DBusError *error) +{ + DBusMessage *message; + dbus_bool_t retval; + const char *null_service; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + null_service = ""; + _dbus_verbose ("sending name owner changed: %s [%s -> %s]\n", + service_name, + old_owner ? old_owner : null_service, + new_owner ? new_owner : null_service); + + message = dbus_message_new_signal (DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "NameOwnerChanged"); + + if (message == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS)) + goto oom; + + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &service_name, + DBUS_TYPE_STRING, old_owner ? &old_owner : &null_service, + DBUS_TYPE_STRING, new_owner ? &new_owner : &null_service, + DBUS_TYPE_INVALID)) + goto oom; + + _dbus_assert (dbus_message_has_signature (message, "sss")); + + retval = bus_dispatch_matches (transaction, NULL, NULL, message, error); + dbus_message_unref (message); + + return retval; + + oom: + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; +} + +dbus_bool_t +bus_driver_send_service_lost (DBusConnection *connection, + const char *service_name, + BusTransaction *transaction, + DBusError *error) +{ + DBusMessage *message; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + message = dbus_message_new_signal (DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "NameLost"); + + if (message == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) || + !dbus_message_append_args (message, + DBUS_TYPE_STRING, &service_name, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_transaction_send_from_driver (transaction, connection, message)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } + else + { + dbus_message_unref (message); + return TRUE; + } +} + +dbus_bool_t +bus_driver_send_service_acquired (DBusConnection *connection, + const char *service_name, + BusTransaction *transaction, + DBusError *error) +{ + DBusMessage *message; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + message = dbus_message_new_signal (DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "NameAcquired"); + + if (message == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) || + !dbus_message_append_args (message, + DBUS_TYPE_STRING, &service_name, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_transaction_send_from_driver (transaction, connection, message)) + { + dbus_message_unref (message); + BUS_SET_OOM (error); + return FALSE; + } + else + { + dbus_message_unref (message); + return TRUE; + } +} + +static dbus_bool_t +create_unique_client_name (BusRegistry *registry, + DBusString *str) +{ + /* We never want to use the same unique client name twice, because + * we want to guarantee that if you send a message to a given unique + * name, you always get the same application. So we use two numbers + * for INT_MAX * INT_MAX combinations, should be pretty safe against + * wraparound. + */ + /* FIXME these should be in BusRegistry rather than static vars */ + static int next_major_number = 0; + static int next_minor_number = 0; + int len; + + len = _dbus_string_get_length (str); + + while (TRUE) + { + /* start out with 1-0, go to 1-1, 1-2, 1-3, + * up to 1-MAXINT, then 2-0, 2-1, etc. + */ + if (next_minor_number <= 0) + { + next_major_number += 1; + next_minor_number = 0; + if (next_major_number <= 0) + _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added"); + } + + _dbus_assert (next_major_number > 0); + _dbus_assert (next_minor_number >= 0); + + /* appname:MAJOR-MINOR */ + + if (!_dbus_string_append (str, ":")) + return FALSE; + + if (!_dbus_string_append_int (str, next_major_number)) + return FALSE; + + if (!_dbus_string_append (str, ".")) + return FALSE; + + if (!_dbus_string_append_int (str, next_minor_number)) + return FALSE; + + next_minor_number += 1; + + /* Check if a client with the name exists */ + if (bus_registry_lookup (registry, str) == NULL) + break; + + /* drop the number again, try the next one. */ + _dbus_string_set_length (str, len); + } + + return TRUE; +} + +static dbus_bool_t +bus_driver_handle_hello (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusString unique_name; + BusService *service; + dbus_bool_t retval; + BusRegistry *registry; + BusConnections *connections; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (bus_connection_is_active (connection)) + { + /* We already handled an Hello message for this connection. */ + dbus_set_error (error, DBUS_ERROR_FAILED, + "Already handled an Hello message"); + return FALSE; + } + + /* Note that when these limits are exceeded we don't disconnect the + * connection; we just sort of leave it hanging there until it times + * out or disconnects itself or is dropped due to the max number of + * incomplete connections. It's even OK if the connection wants to + * retry the hello message, we support that. + */ + connections = bus_connection_get_connections (connection); + if (!bus_connections_check_limits (connections, connection, + error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return FALSE; + } + + if (!_dbus_string_init (&unique_name)) + { + BUS_SET_OOM (error); + return FALSE; + } + + retval = FALSE; + + registry = bus_connection_get_registry (connection); + + if (!create_unique_client_name (registry, &unique_name)) + { + BUS_SET_OOM (error); + goto out_0; + } + + if (!bus_connection_complete (connection, &unique_name, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto out_0; + } + + if (!dbus_message_set_sender (message, + bus_connection_get_name (connection))) + { + BUS_SET_OOM (error); + goto out_0; + } + + if (!bus_driver_send_welcome_message (connection, message, transaction, error)) + goto out_0; + + /* Create the service */ + service = bus_registry_ensure (registry, + &unique_name, connection, 0, transaction, error); + if (service == NULL) + goto out_0; + + _dbus_assert (bus_connection_is_active (connection)); + retval = TRUE; + + out_0: + _dbus_string_free (&unique_name); + return retval; +} + +static dbus_bool_t +bus_driver_send_welcome_message (DBusConnection *connection, + DBusMessage *hello_message, + BusTransaction *transaction, + DBusError *error) +{ + DBusMessage *welcome; + const char *name; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + name = bus_connection_get_name (connection); + _dbus_assert (name != NULL); + + welcome = dbus_message_new_method_return (hello_message); + if (welcome == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!dbus_message_append_args (welcome, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (welcome); + BUS_SET_OOM (error); + return FALSE; + } + + _dbus_assert (dbus_message_has_signature (welcome, DBUS_TYPE_STRING_AS_STRING)); + + if (!bus_transaction_send_from_driver (transaction, connection, welcome)) + { + dbus_message_unref (welcome); + BUS_SET_OOM (error); + return FALSE; + } + else + { + dbus_message_unref (welcome); + return TRUE; + } +} + +static dbus_bool_t +bus_driver_handle_list_services (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusMessage *reply; + int len; + char **services; + BusRegistry *registry; + int i; + DBusMessageIter iter; + DBusMessageIter sub; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + registry = bus_connection_get_registry (connection); + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_registry_list_services (registry, &services, &len)) + { + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + + dbus_message_iter_init_append (reply, &iter); + + if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, + &sub)) + { + dbus_free_string_array (services); + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + + { + /* Include the bus driver in the list */ + const char *v_STRING = DBUS_SERVICE_DBUS; + if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, + &v_STRING)) + { + dbus_free_string_array (services); + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + } + + i = 0; + while (i < len) + { + if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, + &services[i])) + { + dbus_free_string_array (services); + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + ++i; + } + + dbus_free_string_array (services); + + if (!dbus_message_iter_close_container (&iter, &sub)) + { + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + { + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + else + { + dbus_message_unref (reply); + return TRUE; + } +} + +static dbus_bool_t +bus_driver_handle_list_activatable_services (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusMessage *reply; + int len; + char **services; + BusActivation *activation; + int i; + DBusMessageIter iter; + DBusMessageIter sub; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + activation = bus_connection_get_activation (connection); + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_activation_list_services (activation, &services, &len)) + { + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + + dbus_message_iter_init_append (reply, &iter); + + if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, + &sub)) + { + dbus_free_string_array (services); + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + + { + /* Include the bus driver in the list */ + const char *v_STRING = DBUS_SERVICE_DBUS; + if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, + &v_STRING)) + { + dbus_free_string_array (services); + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + } + + i = 0; + while (i < len) + { + if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, + &services[i])) + { + dbus_free_string_array (services); + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + ++i; + } + + dbus_free_string_array (services); + + if (!dbus_message_iter_close_container (&iter, &sub)) + { + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + { + dbus_message_unref (reply); + BUS_SET_OOM (error); + return FALSE; + } + else + { + dbus_message_unref (reply); + return TRUE; + } +} + +static dbus_bool_t +bus_driver_handle_acquire_service (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusMessage *reply; + DBusString service_name; + const char *name; + dbus_uint32_t service_reply; + dbus_uint32_t flags; + dbus_bool_t retval; + BusRegistry *registry; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + registry = bus_connection_get_registry (connection); + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_UINT32, &flags, + DBUS_TYPE_INVALID)) + return FALSE; + + _dbus_verbose ("Trying to own name %s with flags 0x%x\n", name, flags); + + retval = FALSE; + reply = NULL; + + _dbus_string_init_const (&service_name, name); + + if (!bus_registry_acquire_service (registry, connection, + &service_name, flags, + &service_reply, transaction, + error)) + goto out; + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + { + BUS_SET_OOM (error); + goto out; + } + + if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, &service_reply, DBUS_TYPE_INVALID)) + { + BUS_SET_OOM (error); + goto out; + } + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + { + BUS_SET_OOM (error); + goto out; + } + + retval = TRUE; + + out: + if (reply) + dbus_message_unref (reply); + return retval; +} + +static dbus_bool_t +bus_driver_handle_release_service (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusMessage *reply; + DBusString service_name; + const char *name; + dbus_uint32_t service_reply; + dbus_bool_t retval; + BusRegistry *registry; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + registry = bus_connection_get_registry (connection); + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) + return FALSE; + + _dbus_verbose ("Trying to release name %s\n", name); + + retval = FALSE; + reply = NULL; + + _dbus_string_init_const (&service_name, name); + + if (!bus_registry_release_service (registry, connection, + &service_name, &service_reply, + transaction, error)) + goto out; + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + { + BUS_SET_OOM (error); + goto out; + } + + if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, &service_reply, DBUS_TYPE_INVALID)) + { + BUS_SET_OOM (error); + goto out; + } + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + { + BUS_SET_OOM (error); + goto out; + } + + retval = TRUE; + + out: + if (reply) + dbus_message_unref (reply); + return retval; +} + +static dbus_bool_t +bus_driver_handle_service_exists (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusMessage *reply; + DBusString service_name; + BusService *service; + dbus_bool_t service_exists; + const char *name; + dbus_bool_t retval; + BusRegistry *registry; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + registry = bus_connection_get_registry (connection); + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) + return FALSE; + + retval = FALSE; + + if (strcmp (name, DBUS_SERVICE_DBUS) == 0) + { + service_exists = TRUE; + } + else + { + _dbus_string_init_const (&service_name, name); + service = bus_registry_lookup (registry, &service_name); + service_exists = service != NULL; + } + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + { + BUS_SET_OOM (error); + goto out; + } + + if (!dbus_message_append_args (reply, + DBUS_TYPE_BOOLEAN, &service_exists, + 0)) + { + BUS_SET_OOM (error); + goto out; + } + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + { + BUS_SET_OOM (error); + goto out; + } + + retval = TRUE; + + out: + if (reply) + dbus_message_unref (reply); + + return retval; +} + +static dbus_bool_t +bus_driver_handle_activate_service (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + dbus_uint32_t flags; + const char *name; + dbus_bool_t retval; + BusActivation *activation; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + activation = bus_connection_get_activation (connection); + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_UINT32, &flags, + DBUS_TYPE_INVALID)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_verbose ("No memory to get arguments to StartServiceByName\n"); + return FALSE; + } + + retval = FALSE; + + if (!bus_activation_activate_service (activation, connection, transaction, FALSE, + message, name, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_verbose ("bus_activation_activate_service() failed\n"); + goto out; + } + + retval = TRUE; + + out: + return retval; +} + +static dbus_bool_t +send_ack_reply (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusMessage *reply; + + if (dbus_message_get_no_reply (message)) + return TRUE; + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_transaction_send_from_driver (transaction, connection, reply)) + { + BUS_SET_OOM (error); + dbus_message_unref (reply); + return FALSE; + } + + dbus_message_unref (reply); + + return TRUE; +} + +static dbus_bool_t +bus_driver_handle_update_activation_environment (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + dbus_bool_t retval; + BusActivation *activation; + DBusMessageIter iter; + DBusMessageIter dict_iter; + DBusMessageIter dict_entry_iter; + int msg_type; + int array_type; + int key_type; + DBusList *keys, *key_link; + DBusList *values, *value_link; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + activation = bus_connection_get_activation (connection); + + dbus_message_iter_init (message, &iter); + + /* The message signature has already been checked for us, + * so let's just assert it's right. + */ + msg_type = dbus_message_iter_get_arg_type (&iter); + + _dbus_assert (msg_type == DBUS_TYPE_ARRAY); + + dbus_message_iter_recurse (&iter, &dict_iter); + + retval = FALSE; + + /* Then loop through the sent dictionary, add the location of + * the environment keys and values to lists. The result will + * be in reverse order, so we don't have to constantly search + * for the end of the list in a loop. + */ + keys = NULL; + values = NULL; + while ((array_type = dbus_message_iter_get_arg_type (&dict_iter)) == DBUS_TYPE_DICT_ENTRY) + { + dbus_message_iter_recurse (&dict_iter, &dict_entry_iter); + + while ((key_type = dbus_message_iter_get_arg_type (&dict_entry_iter)) == DBUS_TYPE_STRING) + { + char *key; + char *value; + int value_type; + + dbus_message_iter_get_basic (&dict_entry_iter, &key); + dbus_message_iter_next (&dict_entry_iter); + + value_type = dbus_message_iter_get_arg_type (&dict_entry_iter); + + if (value_type != DBUS_TYPE_STRING) + break; + + dbus_message_iter_get_basic (&dict_entry_iter, &value); + + if (!_dbus_list_append (&keys, key)) + { + BUS_SET_OOM (error); + break; + } + + if (!_dbus_list_append (&values, value)) + { + BUS_SET_OOM (error); + break; + } + + dbus_message_iter_next (&dict_entry_iter); + } + + if (key_type != DBUS_TYPE_INVALID) + break; + + dbus_message_iter_next (&dict_iter); + } + + if (array_type != DBUS_TYPE_INVALID) + goto out; + + _dbus_assert (_dbus_list_get_length (&keys) == _dbus_list_get_length (&values)); + + key_link = keys; + value_link = values; + while (key_link != NULL) + { + const char *key; + const char *value; + + key = key_link->data; + value = value_link->data; + + if (!bus_activation_set_environment_variable (activation, + key, value, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_verbose ("bus_activation_set_environment_variable() failed\n"); + break; + } + key_link = _dbus_list_get_next_link (&keys, key_link); + value_link = _dbus_list_get_next_link (&values, value_link); + } + + /* FIXME: We can fail early having set only some of the environment variables, + * (because of OOM failure). It's sort of hard to fix and it doesn't really + * matter, so we're punting for now. + */ + if (key_link != NULL) + goto out; + + if (!send_ack_reply (connection, transaction, + message, error)) + goto out; + + retval = TRUE; + + out: + _dbus_list_clear (&keys); + _dbus_list_clear (&values); + return retval; +} + +static dbus_bool_t +bus_driver_handle_add_match (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + BusMatchRule *rule; + const char *text; + DBusString str; + BusMatchmaker *matchmaker; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + text = NULL; + rule = NULL; + + if (bus_connection_get_n_match_rules (connection) >= + bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction))) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "Connection \"%s\" is not allowed to add more match rules " + "(increase limits in configuration file if required)", + bus_connection_is_active (connection) ? + bus_connection_get_name (connection) : + "(inactive)"); + goto failed; + } + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) + { + _dbus_verbose ("No memory to get arguments to AddMatch\n"); + goto failed; + } + + _dbus_string_init_const (&str, text); + + rule = bus_match_rule_parse (connection, &str, error); + if (rule == NULL) + goto failed; + + matchmaker = bus_connection_get_matchmaker (connection); + + if (!bus_matchmaker_add_rule (matchmaker, rule)) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!send_ack_reply (connection, transaction, + message, error)) + { + bus_matchmaker_remove_rule (matchmaker, rule); + goto failed; + } + + bus_match_rule_unref (rule); + + return TRUE; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (rule) + bus_match_rule_unref (rule); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_remove_match (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + BusMatchRule *rule; + const char *text; + DBusString str; + BusMatchmaker *matchmaker; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + text = NULL; + rule = NULL; + + if (!dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) + { + _dbus_verbose ("No memory to get arguments to RemoveMatch\n"); + goto failed; + } + + _dbus_string_init_const (&str, text); + + rule = bus_match_rule_parse (connection, &str, error); + if (rule == NULL) + goto failed; + + /* Send the ack before we remove the rule, since the ack is undone + * on transaction cancel, but rule removal isn't. + */ + if (!send_ack_reply (connection, transaction, + message, error)) + goto failed; + + matchmaker = bus_connection_get_matchmaker (connection); + + if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error)) + goto failed; + + bus_match_rule_unref (rule); + + return TRUE; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (rule) + bus_match_rule_unref (rule); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_get_service_owner (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + const char *text; + const char *base_name; + DBusString str; + BusRegistry *registry; + BusService *service; + DBusMessage *reply; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + registry = bus_connection_get_registry (connection); + + text = NULL; + reply = NULL; + + if (! dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) + goto failed; + + _dbus_string_init_const (&str, text); + service = bus_registry_lookup (registry, &str); + if (service == NULL && + _dbus_string_equal_c_str (&str, DBUS_SERVICE_DBUS)) + { + /* ORG_FREEDESKTOP_DBUS owns itself */ + base_name = DBUS_SERVICE_DBUS; + } + else if (service == NULL) + { + dbus_set_error (error, + DBUS_ERROR_NAME_HAS_NO_OWNER, + "Could not get owner of name '%s': no such name", text); + goto failed; + } + else + { + base_name = bus_connection_get_name (bus_service_get_primary_owners_connection (service)); + if (base_name == NULL) + { + /* FIXME - how is this error possible? */ + dbus_set_error (error, + DBUS_ERROR_FAILED, + "Could not determine unique name for '%s'", text); + goto failed; + } + _dbus_assert (*base_name == ':'); + } + + _dbus_assert (base_name != NULL); + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + goto oom; + + if (! dbus_message_append_args (reply, + DBUS_TYPE_STRING, &base_name, + DBUS_TYPE_INVALID)) + goto oom; + + if (! bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + dbus_message_unref (reply); + + return TRUE; + + oom: + BUS_SET_OOM (error); + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (reply) + dbus_message_unref (reply); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_list_queued_owners (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + const char *text; + DBusList *base_names; + DBusList *link; + DBusString str; + BusRegistry *registry; + BusService *service; + DBusMessage *reply; + DBusMessageIter iter, array_iter; + char *dbus_service_name = DBUS_SERVICE_DBUS; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + registry = bus_connection_get_registry (connection); + + base_names = NULL; + text = NULL; + reply = NULL; + + if (! dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &text, + DBUS_TYPE_INVALID)) + goto failed; + + _dbus_string_init_const (&str, text); + service = bus_registry_lookup (registry, &str); + if (service == NULL && + _dbus_string_equal_c_str (&str, DBUS_SERVICE_DBUS)) + { + /* ORG_FREEDESKTOP_DBUS owns itself */ + if (! _dbus_list_append (&base_names, dbus_service_name)) + goto oom; + } + else if (service == NULL) + { + dbus_set_error (error, + DBUS_ERROR_NAME_HAS_NO_OWNER, + "Could not get owners of name '%s': no such name", text); + goto failed; + } + else + { + if (!bus_service_list_queued_owners (service, + &base_names, + error)) + goto failed; + } + + _dbus_assert (base_names != NULL); + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + goto oom; + + dbus_message_iter_init_append (reply, &iter); + if (!dbus_message_iter_open_container (&iter, + DBUS_TYPE_ARRAY, + DBUS_TYPE_STRING_AS_STRING, + &array_iter)) + goto oom; + + link = _dbus_list_get_first_link (&base_names); + while (link != NULL) + { + char *uname; + + _dbus_assert (link->data != NULL); + uname = (char *)link->data; + + if (!dbus_message_iter_append_basic (&array_iter, + DBUS_TYPE_STRING, + &uname)) + goto oom; + + link = _dbus_list_get_next_link (&base_names, link); + } + + if (! dbus_message_iter_close_container (&iter, &array_iter)) + goto oom; + + + if (! bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + dbus_message_unref (reply); + + return TRUE; + + oom: + BUS_SET_OOM (error); + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (reply) + dbus_message_unref (reply); + + if (base_names) + _dbus_list_clear (&base_names); + + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_get_connection_unix_user (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + const char *service; + DBusString str; + BusRegistry *registry; + BusService *serv; + DBusConnection *conn; + DBusMessage *reply; + unsigned long uid; + dbus_uint32_t uid32; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + registry = bus_connection_get_registry (connection); + + service = NULL; + reply = NULL; + + if (! dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &service, + DBUS_TYPE_INVALID)) + goto failed; + + _dbus_verbose ("asked for UID of connection %s\n", service); + + _dbus_string_init_const (&str, service); + serv = bus_registry_lookup (registry, &str); + if (serv == NULL) + { + dbus_set_error (error, + DBUS_ERROR_NAME_HAS_NO_OWNER, + "Could not get UID of name '%s': no such name", service); + goto failed; + } + + conn = bus_service_get_primary_owners_connection (serv); + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + goto oom; + + if (!dbus_connection_get_unix_user (conn, &uid)) + { + dbus_set_error (error, + DBUS_ERROR_FAILED, + "Could not determine UID for '%s'", service); + goto failed; + } + + uid32 = uid; + if (! dbus_message_append_args (reply, + DBUS_TYPE_UINT32, &uid32, + DBUS_TYPE_INVALID)) + goto oom; + + if (! bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + dbus_message_unref (reply); + + return TRUE; + + oom: + BUS_SET_OOM (error); + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (reply) + dbus_message_unref (reply); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + const char *service; + DBusString str; + BusRegistry *registry; + BusService *serv; + DBusConnection *conn; + DBusMessage *reply; + unsigned long pid; + dbus_uint32_t pid32; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + registry = bus_connection_get_registry (connection); + + service = NULL; + reply = NULL; + + if (! dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &service, + DBUS_TYPE_INVALID)) + goto failed; + + _dbus_verbose ("asked for PID of connection %s\n", service); + + _dbus_string_init_const (&str, service); + serv = bus_registry_lookup (registry, &str); + if (serv == NULL) + { + dbus_set_error (error, + DBUS_ERROR_NAME_HAS_NO_OWNER, + "Could not get PID of name '%s': no such name", service); + goto failed; + } + + conn = bus_service_get_primary_owners_connection (serv); + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + goto oom; + + if (!dbus_connection_get_unix_process_id (conn, &pid)) + { + dbus_set_error (error, + DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, + "Could not determine PID for '%s'", service); + goto failed; + } + + pid32 = pid; + if (! dbus_message_append_args (reply, + DBUS_TYPE_UINT32, &pid32, + DBUS_TYPE_INVALID)) + goto oom; + + if (! bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + dbus_message_unref (reply); + + return TRUE; + + oom: + BUS_SET_OOM (error); + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (reply) + dbus_message_unref (reply); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + const char *service; + DBusString str; + BusRegistry *registry; + BusService *serv; + DBusConnection *conn; + DBusMessage *reply; + void *data = NULL; + dbus_uint32_t data_size; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + registry = bus_connection_get_registry (connection); + + service = NULL; + reply = NULL; + + if (! dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &service, + DBUS_TYPE_INVALID)) + goto failed; + + _dbus_verbose ("asked for audit session data for connection %s\n", service); + + _dbus_string_init_const (&str, service); + serv = bus_registry_lookup (registry, &str); + if (serv == NULL) + { + dbus_set_error (error, + DBUS_ERROR_NAME_HAS_NO_OWNER, + "Could not get audit session data for name '%s': no such name", service); + goto failed; + } + + conn = bus_service_get_primary_owners_connection (serv); + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + goto oom; + + if (!dbus_connection_get_adt_audit_session_data (conn, &data, &data_size) || data == NULL) + { + dbus_set_error (error, + DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN, + "Could not determine audit session data for '%s'", service); + goto failed; + } + + if (! dbus_message_append_args (reply, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data, data_size, + DBUS_TYPE_INVALID)) + goto oom; + + if (! bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + dbus_message_unref (reply); + + return TRUE; + + oom: + BUS_SET_OOM (error); + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (reply) + dbus_message_unref (reply); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_get_connection_selinux_security_context (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + const char *service; + DBusString str; + BusRegistry *registry; + BusService *serv; + DBusConnection *conn; + DBusMessage *reply; + BusSELinuxID *context; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + registry = bus_connection_get_registry (connection); + + service = NULL; + reply = NULL; + + if (! dbus_message_get_args (message, error, + DBUS_TYPE_STRING, &service, + DBUS_TYPE_INVALID)) + goto failed; + + _dbus_verbose ("asked for security context of connection %s\n", service); + + _dbus_string_init_const (&str, service); + serv = bus_registry_lookup (registry, &str); + if (serv == NULL) + { + dbus_set_error (error, + DBUS_ERROR_NAME_HAS_NO_OWNER, + "Could not get security context of name '%s': no such name", service); + goto failed; + } + + conn = bus_service_get_primary_owners_connection (serv); + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + goto oom; + + context = bus_connection_get_selinux_id (conn); + if (!context) + { + dbus_set_error (error, + DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN, + "Could not determine security context for '%s'", service); + goto failed; + } + + if (! bus_selinux_append_context (reply, context, error)) + goto failed; + + if (! bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + dbus_message_unref (reply); + + return TRUE; + + oom: + BUS_SET_OOM (error); + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (reply) + dbus_message_unref (reply); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_reload_config (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + BusContext *context; + DBusMessage *reply; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + reply = NULL; + + context = bus_connection_get_context (connection); + if (!bus_context_reload_config (context, error)) + goto failed; + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + goto oom; + + if (! bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + dbus_message_unref (reply); + return TRUE; + + oom: + BUS_SET_OOM (error); + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (reply) + dbus_message_unref (reply); + return FALSE; +} + +static dbus_bool_t +bus_driver_handle_get_id (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + BusContext *context; + DBusMessage *reply; + DBusString uuid; + const char *v_STRING; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&uuid)) + { + BUS_SET_OOM (error); + return FALSE; + } + + reply = NULL; + + context = bus_connection_get_context (connection); + if (!bus_context_get_id (context, &uuid)) + goto oom; + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + goto oom; + + v_STRING = _dbus_string_get_const_data (&uuid); + if (!dbus_message_append_args (reply, + DBUS_TYPE_STRING, &v_STRING, + DBUS_TYPE_INVALID)) + goto oom; + + _dbus_assert (dbus_message_has_signature (reply, "s")); + + if (! bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + _dbus_string_free (&uuid); + dbus_message_unref (reply); + return TRUE; + + oom: + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + BUS_SET_OOM (error); + + if (reply) + dbus_message_unref (reply); + _dbus_string_free (&uuid); + return FALSE; +} + +/* For speed it might be useful to sort this in order of + * frequency of use (but doesn't matter with only a few items + * anyhow) + */ +static struct +{ + const char *name; + const char *in_args; + const char *out_args; + dbus_bool_t (* handler) (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error); +} message_handlers[] = { + { "Hello", + "", + DBUS_TYPE_STRING_AS_STRING, + bus_driver_handle_hello }, + { "RequestName", + DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING, + DBUS_TYPE_UINT32_AS_STRING, + bus_driver_handle_acquire_service }, + { "ReleaseName", + DBUS_TYPE_STRING_AS_STRING, + DBUS_TYPE_UINT32_AS_STRING, + bus_driver_handle_release_service }, + { "StartServiceByName", + DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING, + DBUS_TYPE_UINT32_AS_STRING, + bus_driver_handle_activate_service }, + { "UpdateActivationEnvironment", + DBUS_TYPE_ARRAY_AS_STRING DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + "", + bus_driver_handle_update_activation_environment }, + { "NameHasOwner", + DBUS_TYPE_STRING_AS_STRING, + DBUS_TYPE_BOOLEAN_AS_STRING, + bus_driver_handle_service_exists }, + { "ListNames", + "", + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, + bus_driver_handle_list_services }, + { "ListActivatableNames", + "", + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, + bus_driver_handle_list_activatable_services }, + { "AddMatch", + DBUS_TYPE_STRING_AS_STRING, + "", + bus_driver_handle_add_match }, + { "RemoveMatch", + DBUS_TYPE_STRING_AS_STRING, + "", + bus_driver_handle_remove_match }, + { "GetNameOwner", + DBUS_TYPE_STRING_AS_STRING, + DBUS_TYPE_STRING_AS_STRING, + bus_driver_handle_get_service_owner }, + { "ListQueuedOwners", + DBUS_TYPE_STRING_AS_STRING, + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING, + bus_driver_handle_list_queued_owners }, + { "GetConnectionUnixUser", + DBUS_TYPE_STRING_AS_STRING, + DBUS_TYPE_UINT32_AS_STRING, + bus_driver_handle_get_connection_unix_user }, + { "GetConnectionUnixProcessID", + DBUS_TYPE_STRING_AS_STRING, + DBUS_TYPE_UINT32_AS_STRING, + bus_driver_handle_get_connection_unix_process_id }, + { "GetAdtAuditSessionData", + DBUS_TYPE_STRING_AS_STRING, + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, + bus_driver_handle_get_adt_audit_session_data }, + { "GetConnectionSELinuxSecurityContext", + DBUS_TYPE_STRING_AS_STRING, + DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, + bus_driver_handle_get_connection_selinux_security_context }, + { "ReloadConfig", + "", + "", + bus_driver_handle_reload_config }, + { "GetId", + "", + DBUS_TYPE_STRING_AS_STRING, + bus_driver_handle_get_id } +}; + +static dbus_bool_t +write_args_for_direction (DBusString *xml, + const char *signature, + dbus_bool_t in) +{ + DBusTypeReader typereader; + DBusString sigstr; + int current_type; + + _dbus_string_init_const (&sigstr, signature); + _dbus_type_reader_init_types_only (&typereader, &sigstr, 0); + + while ((current_type = _dbus_type_reader_get_current_type (&typereader)) != DBUS_TYPE_INVALID) + { + const DBusString *subsig; + int start, len; + + _dbus_type_reader_get_signature (&typereader, &subsig, &start, &len); + if (!_dbus_string_append_printf (xml, " \n")) + goto oom; + + _dbus_type_reader_next (&typereader); + } + return TRUE; + oom: + return FALSE; +} + +dbus_bool_t +bus_driver_generate_introspect_string (DBusString *xml) +{ + int i; + + if (!_dbus_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE)) + return FALSE; + if (!_dbus_string_append (xml, "\n")) + return FALSE; + if (!_dbus_string_append_printf (xml, " \n", DBUS_INTERFACE_INTROSPECTABLE)) + return FALSE; + if (!_dbus_string_append (xml, " \n")) + return FALSE; + if (!_dbus_string_append_printf (xml, " \n", DBUS_TYPE_STRING_AS_STRING)) + return FALSE; + if (!_dbus_string_append (xml, " \n")) + return FALSE; + if (!_dbus_string_append (xml, " \n")) + return FALSE; + + if (!_dbus_string_append_printf (xml, " \n", + DBUS_INTERFACE_DBUS)) + return FALSE; + + i = 0; + while (i < _DBUS_N_ELEMENTS (message_handlers)) + { + + if (!_dbus_string_append_printf (xml, " \n", + message_handlers[i].name)) + return FALSE; + + if (!write_args_for_direction (xml, message_handlers[i].in_args, TRUE)) + return FALSE; + + if (!write_args_for_direction (xml, message_handlers[i].out_args, FALSE)) + return FALSE; + + if (!_dbus_string_append (xml, " \n")) + return FALSE; + + ++i; + } + + if (!_dbus_string_append_printf (xml, " \n")) + return FALSE; + + if (!_dbus_string_append_printf (xml, " \n")) + return FALSE; + + if (!_dbus_string_append_printf (xml, " \n")) + return FALSE; + + if (!_dbus_string_append_printf (xml, " \n")) + return FALSE; + + if (!_dbus_string_append_printf (xml, " \n")) + return FALSE; + + + + if (!_dbus_string_append_printf (xml, " \n")) + return FALSE; + + if (!_dbus_string_append_printf (xml, " \n")) + return FALSE; + + if (!_dbus_string_append_printf (xml, " \n")) + return FALSE; + + + + if (!_dbus_string_append_printf (xml, " \n")) + return FALSE; + + if (!_dbus_string_append_printf (xml, " \n")) + return FALSE; + + if (!_dbus_string_append_printf (xml, " \n")) + return FALSE; + + if (!_dbus_string_append (xml, " \n")) + return FALSE; + + if (!_dbus_string_append (xml, "\n")) + return FALSE; + + return TRUE; +} + +static dbus_bool_t +bus_driver_handle_introspect (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + DBusString xml; + DBusMessage *reply; + const char *v_STRING; + + _dbus_verbose ("Introspect() on bus driver\n"); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + reply = NULL; + + if (! dbus_message_get_args (message, error, + DBUS_TYPE_INVALID)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return FALSE; + } + + if (!_dbus_string_init (&xml)) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!bus_driver_generate_introspect_string (&xml)) + goto oom; + + v_STRING = _dbus_string_get_const_data (&xml); + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + goto oom; + + if (! dbus_message_append_args (reply, + DBUS_TYPE_STRING, &v_STRING, + DBUS_TYPE_INVALID)) + goto oom; + + if (! bus_transaction_send_from_driver (transaction, connection, reply)) + goto oom; + + dbus_message_unref (reply); + _dbus_string_free (&xml); + + return TRUE; + + oom: + BUS_SET_OOM (error); + + if (reply) + dbus_message_unref (reply); + + _dbus_string_free (&xml); + + return FALSE; +} + +dbus_bool_t +bus_driver_handle_message (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error) +{ + const char *name, *sender, *interface; + int i; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL) + { + _dbus_verbose ("Driver got a non-method-call message, ignoring\n"); + return TRUE; /* we just ignore this */ + } + + if (dbus_message_is_method_call (message, + DBUS_INTERFACE_INTROSPECTABLE, + "Introspect")) + return bus_driver_handle_introspect (connection, transaction, message, error); + + interface = dbus_message_get_interface (message); + if (interface == NULL) + interface = DBUS_INTERFACE_DBUS; + + _dbus_assert (dbus_message_get_member (message) != NULL); + + name = dbus_message_get_member (message); + sender = dbus_message_get_sender (message); + + if (strcmp (interface, + DBUS_INTERFACE_DBUS) != 0) + { + _dbus_verbose ("Driver got message to unknown interface \"%s\"\n", + interface); + goto unknown; + } + + _dbus_verbose ("Driver got a method call: %s\n", + dbus_message_get_member (message)); + + /* security checks should have kept this from getting here */ + _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0); + + i = 0; + while (i < _DBUS_N_ELEMENTS (message_handlers)) + { + if (strcmp (message_handlers[i].name, name) == 0) + { + _dbus_verbose ("Found driver handler for %s\n", name); + + if (!dbus_message_has_signature (message, message_handlers[i].in_args)) + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + _dbus_verbose ("Call to %s has wrong args (%s, expected %s)\n", + name, dbus_message_get_signature (message), + message_handlers[i].in_args); + + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Call to %s has wrong args (%s, expected %s)\n", + name, dbus_message_get_signature (message), + message_handlers[i].in_args); + _DBUS_ASSERT_ERROR_IS_SET (error); + return FALSE; + } + + if ((* message_handlers[i].handler) (connection, transaction, message, error)) + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + _dbus_verbose ("Driver handler succeeded\n"); + return TRUE; + } + else + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_verbose ("Driver handler returned failure\n"); + return FALSE; + } + } + + ++i; + } + + unknown: + _dbus_verbose ("No driver handler for message \"%s\"\n", + name); + + dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD, + "%s does not understand message %s", + DBUS_SERVICE_DBUS, name); + + return FALSE; +} + +void +bus_driver_remove_connection (DBusConnection *connection) +{ + /* FIXME 1.0 Does nothing for now, should unregister the connection + * with the bus driver. + */ +} diff --git a/bus/driver.h b/bus/driver.h new file mode 100644 index 00000000..713b2764 --- /dev/null +++ b/bus/driver.h @@ -0,0 +1,52 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* driver.h Bus client (driver) + * + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_DRIVER_H +#define BUS_DRIVER_H + +#include +#include "connection.h" + +void bus_driver_remove_connection (DBusConnection *connection); +dbus_bool_t bus_driver_handle_message (DBusConnection *connection, + BusTransaction *transaction, + DBusMessage *message, + DBusError *error); +dbus_bool_t bus_driver_send_service_lost (DBusConnection *connection, + const char *service_name, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_driver_send_service_acquired (DBusConnection *connection, + const char *service_name, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_driver_send_service_owner_changed (const char *service_name, + const char *old_owner, + const char *new_owner, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_driver_generate_introspect_string (DBusString *xml); + + + +#endif /* BUS_DRIVER_H */ diff --git a/bus/expirelist.c b/bus/expirelist.c new file mode 100644 index 00000000..58e1f6d1 --- /dev/null +++ b/bus/expirelist.c @@ -0,0 +1,412 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* expirelist.c List of items that expire + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "expirelist.h" +#include "test.h" +#include +#include +#include + +struct BusExpireList +{ + DBusList *items; /**< List of BusExpireItem */ + DBusTimeout *timeout; + DBusLoop *loop; + BusExpireFunc expire_func; + void *data; + int expire_after; /**< Expire after milliseconds (thousandths) */ +}; + +static dbus_bool_t expire_timeout_handler (void *data); + +static void +call_timeout_callback (DBusTimeout *timeout, + void *data) +{ + /* can return FALSE on OOM but we just let it fire again later */ + dbus_timeout_handle (timeout); +} + +BusExpireList* +bus_expire_list_new (DBusLoop *loop, + int expire_after, + BusExpireFunc expire_func, + void *data) +{ + BusExpireList *list; + + list = dbus_new0 (BusExpireList, 1); + if (list == NULL) + return NULL; + + list->expire_func = expire_func; + list->data = data; + list->loop = loop; + list->expire_after = expire_after; + + list->timeout = _dbus_timeout_new (100, /* irrelevant */ + expire_timeout_handler, + list, NULL); + if (list->timeout == NULL) + goto failed; + + _dbus_timeout_set_enabled (list->timeout, FALSE); + + if (!_dbus_loop_add_timeout (list->loop, + list->timeout, + call_timeout_callback, NULL, NULL)) + goto failed; + + return list; + + failed: + if (list->timeout) + _dbus_timeout_unref (list->timeout); + + dbus_free (list); + + return NULL; +} + +void +bus_expire_list_free (BusExpireList *list) +{ + _dbus_assert (list->items == NULL); + + _dbus_loop_remove_timeout (list->loop, list->timeout, + call_timeout_callback, NULL); + + _dbus_timeout_unref (list->timeout); + + dbus_free (list); +} + +void +bus_expire_timeout_set_interval (DBusTimeout *timeout, + int next_interval) +{ + if (next_interval >= 0) + { + _dbus_timeout_set_interval (timeout, + next_interval); + _dbus_timeout_set_enabled (timeout, TRUE); + + _dbus_verbose ("Enabled an expire timeout with interval %d\n", + next_interval); + } + else if (dbus_timeout_get_enabled (timeout)) + { + _dbus_timeout_set_enabled (timeout, FALSE); + + _dbus_verbose ("Disabled an expire timeout\n"); + } + else + _dbus_verbose ("No need to disable this expire timeout\n"); +} + +void +bus_expire_list_recheck_immediately (BusExpireList *list) +{ + _dbus_verbose ("setting interval on expire list to 0 for immediate recheck\n"); + + bus_expire_timeout_set_interval (list->timeout, 0); +} + +static int +do_expiration_with_current_time (BusExpireList *list, + long tv_sec, + long tv_usec) +{ + DBusList *link; + int next_interval, min_wait_time, items_to_expire; + + next_interval = -1; + min_wait_time = 3600 * 1000; /* this is reset anyway if used */ + items_to_expire = 0; + + link = _dbus_list_get_first_link (&list->items); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&list->items, link); + double elapsed; + BusExpireItem *item; + + item = link->data; + + elapsed = ELAPSED_MILLISECONDS_SINCE (item->added_tv_sec, + item->added_tv_usec, + tv_sec, tv_usec); + + if (((item->added_tv_sec == 0) && (item->added_tv_usec == 0)) || + ((list->expire_after > 0) && (elapsed >= (double) list->expire_after))) + { + _dbus_verbose ("Expiring an item %p\n", item); + + /* If the expire function fails, we just end up expiring + * this item next time we walk through the list. This would + * be an indeterminate time normally, so we set up the + * next_interval to be "shortly" (just enough to avoid + * a busy loop) + */ + if (!(* list->expire_func) (list, link, list->data)) + { + next_interval = _dbus_get_oom_wait (); + break; + } + } + else if (list->expire_after > 0) + { + double to_wait; + + items_to_expire = 1; + to_wait = (double) list->expire_after - elapsed; + if (min_wait_time > to_wait) + min_wait_time = to_wait; + } + + link = next; + } + + if (next_interval < 0 && items_to_expire) + next_interval = min_wait_time; + + return next_interval; +} + +static void +bus_expirelist_expire (BusExpireList *list) +{ + int next_interval; + + next_interval = -1; + + if (list->items != NULL) + { + long tv_sec, tv_usec; + + _dbus_get_current_time (&tv_sec, &tv_usec); + + next_interval = do_expiration_with_current_time (list, tv_sec, tv_usec); + } + + bus_expire_timeout_set_interval (list->timeout, next_interval); +} + +static dbus_bool_t +expire_timeout_handler (void *data) +{ + BusExpireList *list = data; + + _dbus_verbose ("Running %s\n", _DBUS_FUNCTION_NAME); + + /* note that this may remove the timeout */ + bus_expirelist_expire (list); + + return TRUE; +} + +void +bus_expire_list_remove_link (BusExpireList *list, + DBusList *link) +{ + _dbus_list_remove_link (&list->items, link); +} + +dbus_bool_t +bus_expire_list_remove (BusExpireList *list, + BusExpireItem *item) +{ + return _dbus_list_remove (&list->items, item); +} + +void +bus_expire_list_unlink (BusExpireList *list, + DBusList *link) +{ + _dbus_list_unlink (&list->items, link); +} + +dbus_bool_t +bus_expire_list_add (BusExpireList *list, + BusExpireItem *item) +{ + dbus_bool_t ret; + + ret = _dbus_list_prepend (&list->items, item); + if (ret && !dbus_timeout_get_enabled (list->timeout)) + bus_expire_timeout_set_interval (list->timeout, 0); + + return ret; +} + +void +bus_expire_list_add_link (BusExpireList *list, + DBusList *link) +{ + _dbus_assert (link->data != NULL); + + _dbus_list_prepend_link (&list->items, link); + + if (!dbus_timeout_get_enabled (list->timeout)) + bus_expire_timeout_set_interval (list->timeout, 0); +} + +DBusList* +bus_expire_list_get_first_link (BusExpireList *list) +{ + return _dbus_list_get_first_link (&list->items); +} + +DBusList* +bus_expire_list_get_next_link (BusExpireList *list, + DBusList *link) +{ + return _dbus_list_get_next_link (&list->items, link); +} + +dbus_bool_t +bus_expire_list_contains_item (BusExpireList *list, + BusExpireItem *item) +{ + return _dbus_list_find_last (&list->items, item) != NULL; +} + +#ifdef DBUS_BUILD_TESTS + +typedef struct +{ + BusExpireItem item; + int expire_count; +} TestExpireItem; + +static dbus_bool_t +test_expire_func (BusExpireList *list, + DBusList *link, + void *data) +{ + TestExpireItem *t; + + t = (TestExpireItem*) link->data; + + t->expire_count += 1; + + return TRUE; +} + +static void +time_add_milliseconds (long *tv_sec, + long *tv_usec, + int milliseconds) +{ + *tv_sec = *tv_sec + milliseconds / 1000; + *tv_usec = *tv_usec + milliseconds * 1000; + if (*tv_usec >= 1000000) + { + *tv_usec -= 1000000; + *tv_sec += 1; + } +} + +dbus_bool_t +bus_expire_list_test (const DBusString *test_data_dir) +{ + DBusLoop *loop; + BusExpireList *list; + long tv_sec, tv_usec; + long tv_sec_not_expired, tv_usec_not_expired; + long tv_sec_expired, tv_usec_expired; + long tv_sec_past, tv_usec_past; + TestExpireItem *item; + int next_interval; + dbus_bool_t result = FALSE; + + + loop = _dbus_loop_new (); + _dbus_assert (loop != NULL); + +#define EXPIRE_AFTER 100 + + list = bus_expire_list_new (loop, EXPIRE_AFTER, + test_expire_func, NULL); + _dbus_assert (list != NULL); + + _dbus_get_current_time (&tv_sec, &tv_usec); + + tv_sec_not_expired = tv_sec; + tv_usec_not_expired = tv_usec; + time_add_milliseconds (&tv_sec_not_expired, + &tv_usec_not_expired, EXPIRE_AFTER - 1); + + tv_sec_expired = tv_sec; + tv_usec_expired = tv_usec; + time_add_milliseconds (&tv_sec_expired, + &tv_usec_expired, EXPIRE_AFTER); + + + tv_sec_past = tv_sec - 1; + tv_usec_past = tv_usec; + + item = dbus_new0 (TestExpireItem, 1); + + if (item == NULL) + goto oom; + + item->item.added_tv_sec = tv_sec; + item->item.added_tv_usec = tv_usec; + if (!bus_expire_list_add (list, &item->item)) + _dbus_assert_not_reached ("out of memory"); + + next_interval = + do_expiration_with_current_time (list, tv_sec_not_expired, + tv_usec_not_expired); + _dbus_assert (item->expire_count == 0); + _dbus_verbose ("next_interval = %d\n", next_interval); + _dbus_assert (next_interval == 1); + + next_interval = + do_expiration_with_current_time (list, tv_sec_expired, + tv_usec_expired); + _dbus_assert (item->expire_count == 1); + _dbus_verbose ("next_interval = %d\n", next_interval); + _dbus_assert (next_interval == -1); + + next_interval = + do_expiration_with_current_time (list, tv_sec_past, + tv_usec_past); + _dbus_assert (item->expire_count == 1); + _dbus_verbose ("next_interval = %d\n", next_interval); + _dbus_assert (next_interval == 1000 + EXPIRE_AFTER); + + bus_expire_list_remove (list, &item->item); + dbus_free (item); + + bus_expire_list_free (list); + _dbus_loop_unref (loop); + + result = TRUE; + + oom: + return result; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/bus/expirelist.h b/bus/expirelist.h new file mode 100644 index 00000000..887cb97b --- /dev/null +++ b/bus/expirelist.h @@ -0,0 +1,80 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* expirelist.h List of stuff that expires + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_EXPIRE_LIST_H +#define BUS_EXPIRE_LIST_H + +#include +#include +#include + +typedef struct BusExpireList BusExpireList; +typedef struct BusExpireItem BusExpireItem; + +typedef dbus_bool_t (* BusExpireFunc) (BusExpireList *list, + DBusList *link, + void *data); + + +/* embed this in a child expire item struct */ +struct BusExpireItem +{ + long added_tv_sec; /**< Time we were added (seconds component) */ + long added_tv_usec; /**< Time we were added (microsec component) */ +}; + +BusExpireList* bus_expire_list_new (DBusLoop *loop, + int expire_after, + BusExpireFunc expire_func, + void *data); +void bus_expire_list_free (BusExpireList *list); +void bus_expire_list_recheck_immediately (BusExpireList *list); +void bus_expire_list_remove_link (BusExpireList *list, + DBusList *link); +dbus_bool_t bus_expire_list_remove (BusExpireList *list, + BusExpireItem *item); +DBusList* bus_expire_list_get_first_link (BusExpireList *list); +DBusList* bus_expire_list_get_next_link (BusExpireList *list, + DBusList *link); +dbus_bool_t bus_expire_list_add (BusExpireList *list, + BusExpireItem *item); +void bus_expire_list_add_link (BusExpireList *list, + DBusList *link); +dbus_bool_t bus_expire_list_contains_item (BusExpireList *list, + BusExpireItem *item); +void bus_expire_list_unlink (BusExpireList *list, + DBusList *link); + +/* this macro and function are semi-related utility functions, not really part of the + * BusExpireList API + */ + +#define ELAPSED_MILLISECONDS_SINCE(orig_tv_sec, orig_tv_usec, \ + now_tv_sec, now_tv_usec) \ + (((double) (now_tv_sec) - (double) (orig_tv_sec)) * 1000.0 + \ + ((double) (now_tv_usec) - (double) (orig_tv_usec)) / 1000.0) + +void bus_expire_timeout_set_interval (DBusTimeout *timeout, + int next_interval); + +#endif /* BUS_EXPIRE_LIST_H */ diff --git a/bus/main.c b/bus/main.c new file mode 100644 index 00000000..d17486dd --- /dev/null +++ b/bus/main.c @@ -0,0 +1,479 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* main.c main() for message bus + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "bus.h" +#include "driver.h" +#include +#include +#include +#include +#include +#include +#ifdef HAVE_ERRNO_H +#include +#endif +#include "selinux.h" + +static BusContext *context; + +static int reload_pipe[2]; +#define RELOAD_READ_END 0 +#define RELOAD_WRITE_END 1 + +static void close_reload_pipe (void); + +static void +signal_handler (int sig) +{ + + switch (sig) + { +#ifdef DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX + case SIGIO: + /* explicit fall-through */ +#endif /* DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX */ +#ifdef SIGHUP + case SIGHUP: + { + DBusString str; + _dbus_string_init_const (&str, "foo"); + if ((reload_pipe[RELOAD_WRITE_END] > 0) && + !_dbus_write_socket (reload_pipe[RELOAD_WRITE_END], &str, 0, 1)) + { + _dbus_warn ("Unable to write to reload pipe.\n"); + close_reload_pipe (); + } + } + break; +#endif + } +} + +static void +usage (void) +{ + fprintf (stderr, DAEMON_NAME " [--version] [--session] [--system] [--config-file=FILE] [--print-address[=DESCRIPTOR]] [--print-pid[=DESCRIPTOR]] [--fork] [--nofork] [--introspect]\n"); + exit (1); +} + +static void +version (void) +{ + printf ("D-Bus Message Bus Daemon %s\n" + "Copyright (C) 2002, 2003 Red Hat, Inc., CodeFactory AB, and others\n" + "This is free software; see the source for copying conditions.\n" + "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", + VERSION); + exit (0); +} + +static void +introspect (void) +{ + DBusString xml; + const char *v_STRING; + + if (!_dbus_string_init (&xml)) + goto oom; + + if (!bus_driver_generate_introspect_string (&xml)) + { + _dbus_string_free (&xml); + goto oom; + } + + v_STRING = _dbus_string_get_const_data (&xml); + printf ("%s\n", v_STRING); + + exit (0); + + oom: + _dbus_warn ("Can not introspect - Out of memory\n"); + exit (1); +} +static void +check_two_config_files (const DBusString *config_file, + const char *extra_arg) +{ + if (_dbus_string_get_length (config_file) > 0) + { + fprintf (stderr, "--%s specified but configuration file %s already requested\n", + extra_arg, _dbus_string_get_const_data (config_file)); + exit (1); + } +} + +static void +check_two_addr_descriptors (const DBusString *addr_fd, + const char *extra_arg) +{ + if (_dbus_string_get_length (addr_fd) > 0) + { + fprintf (stderr, "--%s specified but printing address to %s already requested\n", + extra_arg, _dbus_string_get_const_data (addr_fd)); + exit (1); + } +} + +static void +check_two_pid_descriptors (const DBusString *pid_fd, + const char *extra_arg) +{ + if (_dbus_string_get_length (pid_fd) > 0) + { + fprintf (stderr, "--%s specified but printing pid to %s already requested\n", + extra_arg, _dbus_string_get_const_data (pid_fd)); + exit (1); + } +} + +static dbus_bool_t +handle_reload_watch (DBusWatch *watch, + unsigned int flags, + void *data) +{ + DBusError error; + DBusString str; + + while (!_dbus_string_init (&str)) + _dbus_wait_for_memory (); + + if ((reload_pipe[RELOAD_READ_END] > 0) && + _dbus_read_socket (reload_pipe[RELOAD_READ_END], &str, 1) != 1) + { + _dbus_warn ("Couldn't read from reload pipe.\n"); + close_reload_pipe (); + return TRUE; + } + _dbus_string_free (&str); + + /* this can only fail if we don't understand the config file + * or OOM. Either way we should just stick with the currently + * loaded config. + */ + dbus_error_init (&error); + if (! bus_context_reload_config (context, &error)) + { + _DBUS_ASSERT_ERROR_IS_SET (&error); + _dbus_assert (dbus_error_has_name (&error, DBUS_ERROR_FAILED) || + dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)); + _dbus_warn ("Unable to reload configuration: %s\n", + error.message); + dbus_error_free (&error); + } + return TRUE; +} + +static dbus_bool_t +reload_watch_callback (DBusWatch *watch, + unsigned int condition, + void *data) +{ + return dbus_watch_handle (watch, condition); +} + +static void +setup_reload_pipe (DBusLoop *loop) +{ + DBusError error; + DBusWatch *watch; + + dbus_error_init (&error); + + if (!_dbus_full_duplex_pipe (&reload_pipe[0], &reload_pipe[1], + TRUE, &error)) + { + _dbus_warn ("Unable to create reload pipe: %s\n", + error.message); + dbus_error_free (&error); + exit (1); + } + + _dbus_fd_set_close_on_exec (reload_pipe[0]); + _dbus_fd_set_close_on_exec (reload_pipe[1]); + + watch = _dbus_watch_new (reload_pipe[RELOAD_READ_END], + DBUS_WATCH_READABLE, TRUE, + handle_reload_watch, NULL, NULL); + + if (watch == NULL) + { + _dbus_warn ("Unable to create reload watch: %s\n", + error.message); + dbus_error_free (&error); + exit (1); + } + + if (!_dbus_loop_add_watch (loop, watch, reload_watch_callback, + NULL, NULL)) + { + _dbus_warn ("Unable to add reload watch to main loop: %s\n", + error.message); + dbus_error_free (&error); + exit (1); + } + +} + +static void +close_reload_pipe (void) +{ + _dbus_close_socket (reload_pipe[RELOAD_READ_END], NULL); + reload_pipe[RELOAD_READ_END] = -1; + + _dbus_close_socket (reload_pipe[RELOAD_WRITE_END], NULL); + reload_pipe[RELOAD_WRITE_END] = -1; +} + +int +main (int argc, char **argv) +{ + DBusError error; + DBusString config_file; + DBusString addr_fd; + DBusString pid_fd; + const char *prev_arg; + DBusPipe print_addr_pipe; + DBusPipe print_pid_pipe; + int i; + dbus_bool_t print_address; + dbus_bool_t print_pid; + int force_fork; + + if (!_dbus_string_init (&config_file)) + return 1; + + if (!_dbus_string_init (&addr_fd)) + return 1; + + if (!_dbus_string_init (&pid_fd)) + return 1; + + print_address = FALSE; + print_pid = FALSE; + force_fork = FORK_FOLLOW_CONFIG_FILE; + + prev_arg = NULL; + i = 1; + while (i < argc) + { + const char *arg = argv[i]; + + if (strcmp (arg, "--help") == 0 || + strcmp (arg, "-h") == 0 || + strcmp (arg, "-?") == 0) + usage (); + else if (strcmp (arg, "--version") == 0) + version (); + else if (strcmp (arg, "--introspect") == 0) + introspect (); + else if (strcmp (arg, "--nofork") == 0) + force_fork = FORK_NEVER; + else if (strcmp (arg, "--fork") == 0) + force_fork = FORK_ALWAYS; + else if (strcmp (arg, "--system") == 0) + { + check_two_config_files (&config_file, "system"); + + if (!_dbus_append_system_config_file (&config_file)) + exit (1); + } + else if (strcmp (arg, "--session") == 0) + { + check_two_config_files (&config_file, "session"); + + if (!_dbus_append_session_config_file (&config_file)) + exit (1); + } + else if (strstr (arg, "--config-file=") == arg) + { + const char *file; + + check_two_config_files (&config_file, "config-file"); + + file = strchr (arg, '='); + ++file; + + if (!_dbus_string_append (&config_file, file)) + exit (1); + } + else if (prev_arg && + strcmp (prev_arg, "--config-file") == 0) + { + check_two_config_files (&config_file, "config-file"); + + if (!_dbus_string_append (&config_file, arg)) + exit (1); + } + else if (strcmp (arg, "--config-file") == 0) + ; /* wait for next arg */ + else if (strstr (arg, "--print-address=") == arg) + { + const char *desc; + + check_two_addr_descriptors (&addr_fd, "print-address"); + + desc = strchr (arg, '='); + ++desc; + + if (!_dbus_string_append (&addr_fd, desc)) + exit (1); + + print_address = TRUE; + } + else if (prev_arg && + strcmp (prev_arg, "--print-address") == 0) + { + check_two_addr_descriptors (&addr_fd, "print-address"); + + if (!_dbus_string_append (&addr_fd, arg)) + exit (1); + + print_address = TRUE; + } + else if (strcmp (arg, "--print-address") == 0) + print_address = TRUE; /* and we'll get the next arg if appropriate */ + else if (strstr (arg, "--print-pid=") == arg) + { + const char *desc; + + check_two_pid_descriptors (&pid_fd, "print-pid"); + + desc = strchr (arg, '='); + ++desc; + + if (!_dbus_string_append (&pid_fd, desc)) + exit (1); + + print_pid = TRUE; + } + else if (prev_arg && + strcmp (prev_arg, "--print-pid") == 0) + { + check_two_pid_descriptors (&pid_fd, "print-pid"); + + if (!_dbus_string_append (&pid_fd, arg)) + exit (1); + + print_pid = TRUE; + } + else if (strcmp (arg, "--print-pid") == 0) + print_pid = TRUE; /* and we'll get the next arg if appropriate */ + else + usage (); + + prev_arg = arg; + + ++i; + } + + if (_dbus_string_get_length (&config_file) == 0) + { + fprintf (stderr, "No configuration file specified.\n"); + usage (); + } + + _dbus_pipe_invalidate (&print_addr_pipe); + if (print_address) + { + _dbus_pipe_init_stdout (&print_addr_pipe); + if (_dbus_string_get_length (&addr_fd) > 0) + { + long val; + int end; + if (!_dbus_string_parse_int (&addr_fd, 0, &val, &end) || + end != _dbus_string_get_length (&addr_fd) || + val < 0 || val > _DBUS_INT_MAX) + { + fprintf (stderr, "Invalid file descriptor: \"%s\"\n", + _dbus_string_get_const_data (&addr_fd)); + exit (1); + } + + _dbus_pipe_init (&print_addr_pipe, val); + } + } + _dbus_string_free (&addr_fd); + + _dbus_pipe_invalidate (&print_pid_pipe); + if (print_pid) + { + _dbus_pipe_init_stdout (&print_pid_pipe); + if (_dbus_string_get_length (&pid_fd) > 0) + { + long val; + int end; + if (!_dbus_string_parse_int (&pid_fd, 0, &val, &end) || + end != _dbus_string_get_length (&pid_fd) || + val < 0 || val > _DBUS_INT_MAX) + { + fprintf (stderr, "Invalid file descriptor: \"%s\"\n", + _dbus_string_get_const_data (&pid_fd)); + exit (1); + } + + _dbus_pipe_init (&print_pid_pipe, val); + } + } + _dbus_string_free (&pid_fd); + + if (!bus_selinux_pre_init ()) + { + _dbus_warn ("SELinux pre-initialization failed\n"); + exit (1); + } + + dbus_error_init (&error); + context = bus_context_new (&config_file, force_fork, + &print_addr_pipe, &print_pid_pipe, + &error); + _dbus_string_free (&config_file); + if (context == NULL) + { + _dbus_warn ("Failed to start message bus: %s\n", + error.message); + dbus_error_free (&error); + exit (1); + } + + /* bus_context_new() closes the print_addr_pipe and + * print_pid_pipe + */ + + setup_reload_pipe (bus_context_get_loop (context)); + +#ifdef SIGHUP + _dbus_set_signal_handler (SIGHUP, signal_handler); +#endif +#ifdef DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX + _dbus_set_signal_handler (SIGIO, signal_handler); +#endif /* DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX */ + + _dbus_verbose ("We are on D-Bus...\n"); + _dbus_loop_run (bus_context_get_loop (context)); + + bus_context_shutdown (context); + bus_context_unref (context); + bus_selinux_shutdown (); + + return 0; +} diff --git a/bus/messagebus.in b/bus/messagebus.in new file mode 100755 index 00000000..1f1004b1 --- /dev/null +++ b/bus/messagebus.in @@ -0,0 +1,92 @@ +#!/bin/sh +# +# messagebus: The D-BUS systemwide message bus +# +# chkconfig: 345 22 85 +# description: This is a daemon which broadcasts notifications of system events \ +# and other messages. See http://www.freedesktop.org/software/dbus/ +# +# processname: dbus-daemon +# pidfile: @DBUS_SYSTEM_PID_FILE@ +# +### BEGIN INIT INFO +# Provides: messagebus +# Required-Start: $syslog $local_fs +# Required-Stop: $syslog $local_fs +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: The D-Bus systemwide message bus +# Description: This is a daemon which broadcasts notifications of system +# events and other messages. See http://www.freedesktop.org/software/dbus +### END INIT INFO + +# Sanity checks. +[ -x @EXPANDED_BINDIR@/dbus-daemon ] || exit 0 + +# Source function library. +. @EXPANDED_SYSCONFDIR@/rc.d/init.d/functions + +# so we can rearrange this easily +processname=dbus-daemon +servicename=messagebus + +RETVAL=0 + +start() { + echo -n $"Starting system message bus: " + if [ -x @EXPANDED_BINDIR@/dbus-uuidgen ] ; then + @EXPANDED_BINDIR@/dbus-uuidgen --ensure + fi + + daemon --check $servicename $processname --system + RETVAL=$? + echo + [ $RETVAL -eq 0 ] && touch @EXPANDED_LOCALSTATEDIR@/lock/subsys/$servicename +} + +stop() { + echo -n $"Stopping system message bus: " + + ## we don't want to kill all the per-user $processname, we want + ## to use the pid file *only*; because we use the fake nonexistent + ## program name "$servicename" that should be safe-ish + killproc $servicename -TERM + RETVAL=$? + echo + if [ $RETVAL -eq 0 ]; then + rm -f @EXPANDED_LOCALSTATEDIR@/lock/subsys/$servicename + rm -f @DBUS_SYSTEM_PID_FILE@ + fi +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status $processname + RETVAL=$? + ;; + restart) + stop + start + ;; + condrestart) + if [ -f @EXPANDED_LOCALSTATEDIR@/lock/subsys/$servicename ]; then + stop + start + fi + ;; + reload) + echo "Message bus can't reload its configuration, you have to restart it" + RETVAL=$? + ;; + *) + echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}" + ;; +esac +exit $RETVAL diff --git a/bus/policy.c b/bus/policy.c new file mode 100644 index 00000000..bc1d2d9d --- /dev/null +++ b/bus/policy.c @@ -0,0 +1,1296 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* policy.c Bus security policy + * + * Copyright (C) 2003, 2004 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "policy.h" +#include "services.h" +#include "test.h" +#include "utils.h" +#include +#include +#include + +BusPolicyRule* +bus_policy_rule_new (BusPolicyRuleType type, + dbus_bool_t allow) +{ + BusPolicyRule *rule; + + rule = dbus_new0 (BusPolicyRule, 1); + if (rule == NULL) + return NULL; + + rule->type = type; + rule->refcount = 1; + rule->allow = allow; + + switch (rule->type) + { + case BUS_POLICY_RULE_USER: + rule->d.user.uid = DBUS_UID_UNSET; + break; + case BUS_POLICY_RULE_GROUP: + rule->d.group.gid = DBUS_GID_UNSET; + break; + case BUS_POLICY_RULE_SEND: + rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID; + + /* allow rules default to TRUE (only requested replies allowed) + * deny rules default to FALSE (only unrequested replies denied) + */ + rule->d.send.requested_reply = rule->allow; + break; + case BUS_POLICY_RULE_RECEIVE: + rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID; + /* allow rules default to TRUE (only requested replies allowed) + * deny rules default to FALSE (only unrequested replies denied) + */ + rule->d.receive.requested_reply = rule->allow; + break; + case BUS_POLICY_RULE_OWN: + break; + } + + return rule; +} + +BusPolicyRule * +bus_policy_rule_ref (BusPolicyRule *rule) +{ + _dbus_assert (rule->refcount > 0); + + rule->refcount += 1; + + return rule; +} + +void +bus_policy_rule_unref (BusPolicyRule *rule) +{ + _dbus_assert (rule->refcount > 0); + + rule->refcount -= 1; + + if (rule->refcount == 0) + { + switch (rule->type) + { + case BUS_POLICY_RULE_SEND: + dbus_free (rule->d.send.path); + dbus_free (rule->d.send.interface); + dbus_free (rule->d.send.member); + dbus_free (rule->d.send.error); + dbus_free (rule->d.send.destination); + break; + case BUS_POLICY_RULE_RECEIVE: + dbus_free (rule->d.receive.path); + dbus_free (rule->d.receive.interface); + dbus_free (rule->d.receive.member); + dbus_free (rule->d.receive.error); + dbus_free (rule->d.receive.origin); + break; + case BUS_POLICY_RULE_OWN: + dbus_free (rule->d.own.service_name); + break; + case BUS_POLICY_RULE_USER: + break; + case BUS_POLICY_RULE_GROUP: + break; + } + + dbus_free (rule); + } +} + +struct BusPolicy +{ + int refcount; + + DBusList *default_rules; /**< Default policy rules */ + DBusList *mandatory_rules; /**< Mandatory policy rules */ + DBusHashTable *rules_by_uid; /**< per-UID policy rules */ + DBusHashTable *rules_by_gid; /**< per-GID policy rules */ + DBusList *at_console_true_rules; /**< console user policy rules where at_console="true"*/ + DBusList *at_console_false_rules; /**< console user policy rules where at_console="false"*/ +}; + +static void +free_rule_func (void *data, + void *user_data) +{ + BusPolicyRule *rule = data; + + bus_policy_rule_unref (rule); +} + +static void +free_rule_list_func (void *data) +{ + DBusList **list = data; + + if (list == NULL) /* DBusHashTable is on crack */ + return; + + _dbus_list_foreach (list, free_rule_func, NULL); + + _dbus_list_clear (list); + + dbus_free (list); +} + +BusPolicy* +bus_policy_new (void) +{ + BusPolicy *policy; + + policy = dbus_new0 (BusPolicy, 1); + if (policy == NULL) + return NULL; + + policy->refcount = 1; + + policy->rules_by_uid = _dbus_hash_table_new (DBUS_HASH_ULONG, + NULL, + free_rule_list_func); + if (policy->rules_by_uid == NULL) + goto failed; + + policy->rules_by_gid = _dbus_hash_table_new (DBUS_HASH_ULONG, + NULL, + free_rule_list_func); + if (policy->rules_by_gid == NULL) + goto failed; + + return policy; + + failed: + bus_policy_unref (policy); + return NULL; +} + +BusPolicy * +bus_policy_ref (BusPolicy *policy) +{ + _dbus_assert (policy->refcount > 0); + + policy->refcount += 1; + + return policy; +} + +void +bus_policy_unref (BusPolicy *policy) +{ + _dbus_assert (policy->refcount > 0); + + policy->refcount -= 1; + + if (policy->refcount == 0) + { + _dbus_list_foreach (&policy->default_rules, free_rule_func, NULL); + _dbus_list_clear (&policy->default_rules); + + _dbus_list_foreach (&policy->mandatory_rules, free_rule_func, NULL); + _dbus_list_clear (&policy->mandatory_rules); + + _dbus_list_foreach (&policy->at_console_true_rules, free_rule_func, NULL); + _dbus_list_clear (&policy->at_console_true_rules); + + _dbus_list_foreach (&policy->at_console_false_rules, free_rule_func, NULL); + _dbus_list_clear (&policy->at_console_false_rules); + + if (policy->rules_by_uid) + { + _dbus_hash_table_unref (policy->rules_by_uid); + policy->rules_by_uid = NULL; + } + + if (policy->rules_by_gid) + { + _dbus_hash_table_unref (policy->rules_by_gid); + policy->rules_by_gid = NULL; + } + + dbus_free (policy); + } +} + +static dbus_bool_t +add_list_to_client (DBusList **list, + BusClientPolicy *client) +{ + DBusList *link; + + link = _dbus_list_get_first_link (list); + while (link != NULL) + { + BusPolicyRule *rule = link->data; + link = _dbus_list_get_next_link (list, link); + + switch (rule->type) + { + case BUS_POLICY_RULE_USER: + case BUS_POLICY_RULE_GROUP: + /* These aren't per-connection policies */ + break; + + case BUS_POLICY_RULE_OWN: + case BUS_POLICY_RULE_SEND: + case BUS_POLICY_RULE_RECEIVE: + /* These are per-connection */ + if (!bus_client_policy_append_rule (client, rule)) + return FALSE; + break; + } + } + + return TRUE; +} + +BusClientPolicy* +bus_policy_create_client_policy (BusPolicy *policy, + DBusConnection *connection, + DBusError *error) +{ + BusClientPolicy *client; + dbus_uid_t uid; + dbus_bool_t at_console; + + _dbus_assert (dbus_connection_get_is_authenticated (connection)); + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + client = bus_client_policy_new (); + if (client == NULL) + goto nomem; + + if (!add_list_to_client (&policy->default_rules, + client)) + goto nomem; + + /* we avoid the overhead of looking up user's groups + * if we don't have any group rules anyway + */ + if (_dbus_hash_table_get_n_entries (policy->rules_by_gid) > 0) + { + unsigned long *groups; + int n_groups; + int i; + + if (!bus_connection_get_unix_groups (connection, &groups, &n_groups, error)) + goto failed; + + i = 0; + while (i < n_groups) + { + DBusList **list; + + list = _dbus_hash_table_lookup_ulong (policy->rules_by_gid, + groups[i]); + + if (list != NULL) + { + if (!add_list_to_client (list, client)) + { + dbus_free (groups); + goto nomem; + } + } + + ++i; + } + + dbus_free (groups); + } + + if (dbus_connection_get_unix_user (connection, &uid)) + { + if (_dbus_hash_table_get_n_entries (policy->rules_by_uid) > 0) + { + DBusList **list; + + list = _dbus_hash_table_lookup_ulong (policy->rules_by_uid, + uid); + + if (list != NULL) + { + if (!add_list_to_client (list, client)) + goto nomem; + } + } + + /* Add console rules */ + at_console = _dbus_unix_user_is_at_console (uid, error); + + if (at_console) + { + if (!add_list_to_client (&policy->at_console_true_rules, client)) + goto nomem; + } + else if (dbus_error_is_set (error) == TRUE) + { + goto failed; + } + else if (!add_list_to_client (&policy->at_console_false_rules, client)) + { + goto nomem; + } + } + + if (!add_list_to_client (&policy->mandatory_rules, + client)) + goto nomem; + + bus_client_policy_optimize (client); + + return client; + + nomem: + BUS_SET_OOM (error); + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (client) + bus_client_policy_unref (client); + return NULL; +} + +static dbus_bool_t +list_allows_user (dbus_bool_t def, + DBusList **list, + unsigned long uid, + const unsigned long *group_ids, + int n_group_ids) +{ + DBusList *link; + dbus_bool_t allowed; + + allowed = def; + + link = _dbus_list_get_first_link (list); + while (link != NULL) + { + BusPolicyRule *rule = link->data; + link = _dbus_list_get_next_link (list, link); + + if (rule->type == BUS_POLICY_RULE_USER) + { + _dbus_verbose ("List %p user rule uid="DBUS_UID_FORMAT"\n", + list, rule->d.user.uid); + + if (rule->d.user.uid == DBUS_UID_UNSET) + ; /* '*' wildcard */ + else if (rule->d.user.uid != uid) + continue; + } + else if (rule->type == BUS_POLICY_RULE_GROUP) + { + _dbus_verbose ("List %p group rule uid="DBUS_UID_FORMAT"\n", + list, rule->d.user.uid); + + if (rule->d.group.gid == DBUS_GID_UNSET) + ; /* '*' wildcard */ + else + { + int i; + + i = 0; + while (i < n_group_ids) + { + if (rule->d.group.gid == group_ids[i]) + break; + ++i; + } + + if (i == n_group_ids) + continue; + } + } + else + continue; + + allowed = rule->allow; + } + + return allowed; +} + +dbus_bool_t +bus_policy_allow_unix_user (BusPolicy *policy, + unsigned long uid) +{ + dbus_bool_t allowed; + unsigned long *group_ids; + int n_group_ids; + + /* On OOM or error we always reject the user */ + if (!_dbus_unix_groups_from_uid (uid, &group_ids, &n_group_ids)) + { + _dbus_verbose ("Did not get any groups for UID %lu\n", + uid); + return FALSE; + } + + /* Default to "user owning bus" can connect */ + allowed = _dbus_unix_user_is_process_owner (uid); + + allowed = list_allows_user (allowed, + &policy->default_rules, + uid, + group_ids, n_group_ids); + + allowed = list_allows_user (allowed, + &policy->mandatory_rules, + uid, + group_ids, n_group_ids); + + dbus_free (group_ids); + + _dbus_verbose ("UID %lu allowed = %d\n", uid, allowed); + + return allowed; +} + +/* For now this is never actually called because the default + * DBusConnection behavior of 'same user that owns the bus can + * connect' is all it would do. Set the windows user function in + * connection.c if the config file ever supports doing something + * interesting here. + */ +dbus_bool_t +bus_policy_allow_windows_user (BusPolicy *policy, + const char *windows_sid) +{ + /* Windows has no policies here since only the session bus + * is really used for now, so just checking that the + * connecting person is the same as the bus owner is fine. + */ + return _dbus_windows_user_is_process_owner (windows_sid); +} + +dbus_bool_t +bus_policy_append_default_rule (BusPolicy *policy, + BusPolicyRule *rule) +{ + if (!_dbus_list_append (&policy->default_rules, rule)) + return FALSE; + + bus_policy_rule_ref (rule); + + return TRUE; +} + +dbus_bool_t +bus_policy_append_mandatory_rule (BusPolicy *policy, + BusPolicyRule *rule) +{ + if (!_dbus_list_append (&policy->mandatory_rules, rule)) + return FALSE; + + bus_policy_rule_ref (rule); + + return TRUE; +} + + + +static DBusList** +get_list (DBusHashTable *hash, + unsigned long key) +{ + DBusList **list; + + list = _dbus_hash_table_lookup_ulong (hash, key); + + if (list == NULL) + { + list = dbus_new0 (DBusList*, 1); + if (list == NULL) + return NULL; + + if (!_dbus_hash_table_insert_ulong (hash, key, list)) + { + dbus_free (list); + return NULL; + } + } + + return list; +} + +dbus_bool_t +bus_policy_append_user_rule (BusPolicy *policy, + dbus_uid_t uid, + BusPolicyRule *rule) +{ + DBusList **list; + + list = get_list (policy->rules_by_uid, uid); + + if (list == NULL) + return FALSE; + + if (!_dbus_list_append (list, rule)) + return FALSE; + + bus_policy_rule_ref (rule); + + return TRUE; +} + +dbus_bool_t +bus_policy_append_group_rule (BusPolicy *policy, + dbus_gid_t gid, + BusPolicyRule *rule) +{ + DBusList **list; + + list = get_list (policy->rules_by_gid, gid); + + if (list == NULL) + return FALSE; + + if (!_dbus_list_append (list, rule)) + return FALSE; + + bus_policy_rule_ref (rule); + + return TRUE; +} + +dbus_bool_t +bus_policy_append_console_rule (BusPolicy *policy, + dbus_bool_t at_console, + BusPolicyRule *rule) +{ + if (at_console) + { + if (!_dbus_list_append (&policy->at_console_true_rules, rule)) + return FALSE; + } + else + { + if (!_dbus_list_append (&policy->at_console_false_rules, rule)) + return FALSE; + } + + bus_policy_rule_ref (rule); + + return TRUE; + +} + +static dbus_bool_t +append_copy_of_policy_list (DBusList **list, + DBusList **to_append) +{ + DBusList *link; + DBusList *tmp_list; + + tmp_list = NULL; + + /* Preallocate all our links */ + link = _dbus_list_get_first_link (to_append); + while (link != NULL) + { + if (!_dbus_list_append (&tmp_list, link->data)) + { + _dbus_list_clear (&tmp_list); + return FALSE; + } + + link = _dbus_list_get_next_link (to_append, link); + } + + /* Now append them */ + while ((link = _dbus_list_pop_first_link (&tmp_list))) + { + bus_policy_rule_ref (link->data); + _dbus_list_append_link (list, link); + } + + return TRUE; +} + +static dbus_bool_t +merge_id_hash (DBusHashTable *dest, + DBusHashTable *to_absorb) +{ + DBusHashIter iter; + + _dbus_hash_iter_init (to_absorb, &iter); + while (_dbus_hash_iter_next (&iter)) + { + unsigned long id = _dbus_hash_iter_get_ulong_key (&iter); + DBusList **list = _dbus_hash_iter_get_value (&iter); + DBusList **target = get_list (dest, id); + + if (target == NULL) + return FALSE; + + if (!append_copy_of_policy_list (target, list)) + return FALSE; + } + + return TRUE; +} + +dbus_bool_t +bus_policy_merge (BusPolicy *policy, + BusPolicy *to_absorb) +{ + /* FIXME Not properly atomic, but as used for configuration files we + * don't rely on it quite so much. + */ + + if (!append_copy_of_policy_list (&policy->default_rules, + &to_absorb->default_rules)) + return FALSE; + + if (!append_copy_of_policy_list (&policy->mandatory_rules, + &to_absorb->mandatory_rules)) + return FALSE; + + if (!append_copy_of_policy_list (&policy->at_console_true_rules, + &to_absorb->at_console_true_rules)) + return FALSE; + + if (!append_copy_of_policy_list (&policy->at_console_false_rules, + &to_absorb->at_console_false_rules)) + return FALSE; + + if (!merge_id_hash (policy->rules_by_uid, + to_absorb->rules_by_uid)) + return FALSE; + + if (!merge_id_hash (policy->rules_by_gid, + to_absorb->rules_by_gid)) + return FALSE; + + return TRUE; +} + +struct BusClientPolicy +{ + int refcount; + + DBusList *rules; +}; + +BusClientPolicy* +bus_client_policy_new (void) +{ + BusClientPolicy *policy; + + policy = dbus_new0 (BusClientPolicy, 1); + if (policy == NULL) + return NULL; + + policy->refcount = 1; + + return policy; +} + +BusClientPolicy * +bus_client_policy_ref (BusClientPolicy *policy) +{ + _dbus_assert (policy->refcount > 0); + + policy->refcount += 1; + + return policy; +} + +static void +rule_unref_foreach (void *data, + void *user_data) +{ + BusPolicyRule *rule = data; + + bus_policy_rule_unref (rule); +} + +void +bus_client_policy_unref (BusClientPolicy *policy) +{ + _dbus_assert (policy->refcount > 0); + + policy->refcount -= 1; + + if (policy->refcount == 0) + { + _dbus_list_foreach (&policy->rules, + rule_unref_foreach, + NULL); + + _dbus_list_clear (&policy->rules); + + dbus_free (policy); + } +} + +static void +remove_rules_by_type_up_to (BusClientPolicy *policy, + BusPolicyRuleType type, + DBusList *up_to) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&policy->rules); + while (link != up_to) + { + BusPolicyRule *rule = link->data; + DBusList *next = _dbus_list_get_next_link (&policy->rules, link); + + if (rule->type == type) + { + _dbus_list_remove_link (&policy->rules, link); + bus_policy_rule_unref (rule); + } + + link = next; + } +} + +void +bus_client_policy_optimize (BusClientPolicy *policy) +{ + DBusList *link; + + /* The idea here is that if we have: + * + * + * + * + * (for example) the deny will always override the allow. So we + * delete the allow. Ditto for deny followed by allow, etc. This is + * a dumb thing to put in a config file, but the feature + * of files allows for an "inheritance and override" pattern where + * it could make sense. If an included file wants to "start over" + * with a blanket deny, no point keeping the rules from the parent + * file. + */ + + _dbus_verbose ("Optimizing policy with %d rules\n", + _dbus_list_get_length (&policy->rules)); + + link = _dbus_list_get_first_link (&policy->rules); + while (link != NULL) + { + BusPolicyRule *rule; + DBusList *next; + dbus_bool_t remove_preceding; + + next = _dbus_list_get_next_link (&policy->rules, link); + rule = link->data; + + remove_preceding = FALSE; + + _dbus_assert (rule != NULL); + + switch (rule->type) + { + case BUS_POLICY_RULE_SEND: + remove_preceding = + rule->d.send.message_type == DBUS_MESSAGE_TYPE_INVALID && + rule->d.send.path == NULL && + rule->d.send.interface == NULL && + rule->d.send.member == NULL && + rule->d.send.error == NULL && + rule->d.send.destination == NULL; + break; + case BUS_POLICY_RULE_RECEIVE: + remove_preceding = + rule->d.receive.message_type == DBUS_MESSAGE_TYPE_INVALID && + rule->d.receive.path == NULL && + rule->d.receive.interface == NULL && + rule->d.receive.member == NULL && + rule->d.receive.error == NULL && + rule->d.receive.origin == NULL; + break; + case BUS_POLICY_RULE_OWN: + remove_preceding = + rule->d.own.service_name == NULL; + break; + case BUS_POLICY_RULE_USER: + case BUS_POLICY_RULE_GROUP: + _dbus_assert_not_reached ("invalid rule"); + break; + } + + if (remove_preceding) + remove_rules_by_type_up_to (policy, rule->type, + link); + + link = next; + } + + _dbus_verbose ("After optimization, policy has %d rules\n", + _dbus_list_get_length (&policy->rules)); +} + +dbus_bool_t +bus_client_policy_append_rule (BusClientPolicy *policy, + BusPolicyRule *rule) +{ + _dbus_verbose ("Appending rule %p with type %d to policy %p\n", + rule, rule->type, policy); + + if (!_dbus_list_append (&policy->rules, rule)) + return FALSE; + + bus_policy_rule_ref (rule); + + return TRUE; +} + +dbus_bool_t +bus_client_policy_check_can_send (BusClientPolicy *policy, + BusRegistry *registry, + dbus_bool_t requested_reply, + DBusConnection *receiver, + DBusMessage *message, + dbus_int32_t *toggles, + dbus_bool_t *log) +{ + DBusList *link; + dbus_bool_t allowed; + + /* policy->rules is in the order the rules appeared + * in the config file, i.e. last rule that applies wins + */ + + _dbus_verbose (" (policy) checking send rules\n"); + *toggles = 0; + + allowed = FALSE; + link = _dbus_list_get_first_link (&policy->rules); + while (link != NULL) + { + BusPolicyRule *rule = link->data; + + link = _dbus_list_get_next_link (&policy->rules, link); + + /* Rule is skipped if it specifies a different + * message name from the message, or a different + * destination from the message + */ + + if (rule->type != BUS_POLICY_RULE_SEND) + { + _dbus_verbose (" (policy) skipping non-send rule\n"); + continue; + } + + if (rule->d.send.message_type != DBUS_MESSAGE_TYPE_INVALID) + { + if (dbus_message_get_type (message) != rule->d.send.message_type) + { + _dbus_verbose (" (policy) skipping rule for different message type\n"); + continue; + } + } + + /* If it's a reply, the requested_reply flag kicks in */ + if (dbus_message_get_reply_serial (message) != 0) + { + /* for allow, requested_reply=true means the rule applies + * only when reply was requested. requested_reply=false means + * always allow. + */ + if (!requested_reply && rule->allow && rule->d.send.requested_reply && !rule->d.send.eavesdrop) + { + _dbus_verbose (" (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n"); + continue; + } + + /* for deny, requested_reply=false means the rule applies only + * when the reply was not requested. requested_reply=true means the + * rule always applies. + */ + if (requested_reply && !rule->allow && !rule->d.send.requested_reply) + { + _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n"); + continue; + } + } + + if (rule->d.send.path != NULL) + { + if (dbus_message_get_path (message) != NULL && + strcmp (dbus_message_get_path (message), + rule->d.send.path) != 0) + { + _dbus_verbose (" (policy) skipping rule for different path\n"); + continue; + } + } + + if (rule->d.send.interface != NULL) + { + /* The interface is optional in messages. For allow rules, if the message + * has no interface we want to skip the rule (and thus not allow); + * for deny rules, if the message has no interface we want to use the + * rule (and thus deny). + */ + dbus_bool_t no_interface; + + no_interface = dbus_message_get_interface (message) == NULL; + + if ((no_interface && rule->allow) || + (!no_interface && + strcmp (dbus_message_get_interface (message), + rule->d.send.interface) != 0)) + { + _dbus_verbose (" (policy) skipping rule for different interface\n"); + continue; + } + } + + if (rule->d.send.member != NULL) + { + if (dbus_message_get_member (message) != NULL && + strcmp (dbus_message_get_member (message), + rule->d.send.member) != 0) + { + _dbus_verbose (" (policy) skipping rule for different member\n"); + continue; + } + } + + if (rule->d.send.error != NULL) + { + if (dbus_message_get_error_name (message) != NULL && + strcmp (dbus_message_get_error_name (message), + rule->d.send.error) != 0) + { + _dbus_verbose (" (policy) skipping rule for different error name\n"); + continue; + } + } + + if (rule->d.send.destination != NULL) + { + /* receiver can be NULL for messages that are sent to the + * message bus itself, we check the strings in that case as + * built-in services don't have a DBusConnection but messages + * to them have a destination service name. + */ + if (receiver == NULL) + { + if (!dbus_message_has_destination (message, + rule->d.send.destination)) + { + _dbus_verbose (" (policy) skipping rule because message dest is not %s\n", + rule->d.send.destination); + continue; + } + } + else + { + DBusString str; + BusService *service; + + _dbus_string_init_const (&str, rule->d.send.destination); + + service = bus_registry_lookup (registry, &str); + if (service == NULL) + { + _dbus_verbose (" (policy) skipping rule because dest %s doesn't exist\n", + rule->d.send.destination); + continue; + } + + if (!bus_service_has_owner (service, receiver)) + { + _dbus_verbose (" (policy) skipping rule because dest %s isn't owned by receiver\n", + rule->d.send.destination); + continue; + } + } + } + + /* Use this rule */ + allowed = rule->allow; + *log = rule->d.send.log; + (*toggles)++; + + _dbus_verbose (" (policy) used rule, allow now = %d\n", + allowed); + } + + return allowed; +} + +/* See docs on what the args mean on bus_context_check_security_policy() + * comment + */ +dbus_bool_t +bus_client_policy_check_can_receive (BusClientPolicy *policy, + BusRegistry *registry, + dbus_bool_t requested_reply, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, + DBusMessage *message, + dbus_int32_t *toggles) +{ + DBusList *link; + dbus_bool_t allowed; + dbus_bool_t eavesdropping; + + eavesdropping = + addressed_recipient != proposed_recipient && + dbus_message_get_destination (message) != NULL; + + /* policy->rules is in the order the rules appeared + * in the config file, i.e. last rule that applies wins + */ + + _dbus_verbose (" (policy) checking receive rules, eavesdropping = %d\n", eavesdropping); + *toggles = 0; + + allowed = FALSE; + link = _dbus_list_get_first_link (&policy->rules); + while (link != NULL) + { + BusPolicyRule *rule = link->data; + + link = _dbus_list_get_next_link (&policy->rules, link); + + if (rule->type != BUS_POLICY_RULE_RECEIVE) + { + _dbus_verbose (" (policy) skipping non-receive rule\n"); + continue; + } + + if (rule->d.receive.message_type != DBUS_MESSAGE_TYPE_INVALID) + { + if (dbus_message_get_type (message) != rule->d.receive.message_type) + { + _dbus_verbose (" (policy) skipping rule for different message type\n"); + continue; + } + } + + /* for allow, eavesdrop=false means the rule doesn't apply when + * eavesdropping. eavesdrop=true means always allow. + */ + if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop) + { + _dbus_verbose (" (policy) skipping allow rule since it doesn't apply to eavesdropping\n"); + continue; + } + + /* for deny, eavesdrop=true means the rule applies only when + * eavesdropping; eavesdrop=false means always deny. + */ + if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop) + { + _dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n"); + continue; + } + + /* If it's a reply, the requested_reply flag kicks in */ + if (dbus_message_get_reply_serial (message) != 0) + { + /* for allow, requested_reply=true means the rule applies + * only when reply was requested. requested_reply=false means + * always allow. + */ + if (!requested_reply && rule->allow && rule->d.receive.requested_reply && !rule->d.receive.eavesdrop) + { + _dbus_verbose (" (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n"); + continue; + } + + /* for deny, requested_reply=false means the rule applies only + * when the reply was not requested. requested_reply=true means the + * rule always applies. + */ + if (requested_reply && !rule->allow && !rule->d.receive.requested_reply) + { + _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n"); + continue; + } + } + + if (rule->d.receive.path != NULL) + { + if (dbus_message_get_path (message) != NULL && + strcmp (dbus_message_get_path (message), + rule->d.receive.path) != 0) + { + _dbus_verbose (" (policy) skipping rule for different path\n"); + continue; + } + } + + if (rule->d.receive.interface != NULL) + { + /* The interface is optional in messages. For allow rules, if the message + * has no interface we want to skip the rule (and thus not allow); + * for deny rules, if the message has no interface we want to use the + * rule (and thus deny). + */ + dbus_bool_t no_interface; + + no_interface = dbus_message_get_interface (message) == NULL; + + if ((no_interface && rule->allow) || + (!no_interface && + strcmp (dbus_message_get_interface (message), + rule->d.receive.interface) != 0)) + { + _dbus_verbose (" (policy) skipping rule for different interface\n"); + continue; + } + } + + if (rule->d.receive.member != NULL) + { + if (dbus_message_get_member (message) != NULL && + strcmp (dbus_message_get_member (message), + rule->d.receive.member) != 0) + { + _dbus_verbose (" (policy) skipping rule for different member\n"); + continue; + } + } + + if (rule->d.receive.error != NULL) + { + if (dbus_message_get_error_name (message) != NULL && + strcmp (dbus_message_get_error_name (message), + rule->d.receive.error) != 0) + { + _dbus_verbose (" (policy) skipping rule for different error name\n"); + continue; + } + } + + if (rule->d.receive.origin != NULL) + { + /* sender can be NULL for messages that originate from the + * message bus itself, we check the strings in that case as + * built-in services don't have a DBusConnection but will + * still set the sender on their messages. + */ + if (sender == NULL) + { + if (!dbus_message_has_sender (message, + rule->d.receive.origin)) + { + _dbus_verbose (" (policy) skipping rule because message sender is not %s\n", + rule->d.receive.origin); + continue; + } + } + else + { + BusService *service; + DBusString str; + + _dbus_string_init_const (&str, rule->d.receive.origin); + + service = bus_registry_lookup (registry, &str); + + if (service == NULL) + { + _dbus_verbose (" (policy) skipping rule because origin %s doesn't exist\n", + rule->d.receive.origin); + continue; + } + + if (!bus_service_has_owner (service, sender)) + { + _dbus_verbose (" (policy) skipping rule because origin %s isn't owned by sender\n", + rule->d.receive.origin); + continue; + } + } + } + + /* Use this rule */ + allowed = rule->allow; + (*toggles)++; + + _dbus_verbose (" (policy) used rule, allow now = %d\n", + allowed); + } + + return allowed; +} + +dbus_bool_t +bus_client_policy_check_can_own (BusClientPolicy *policy, + DBusConnection *connection, + const DBusString *service_name) +{ + DBusList *link; + dbus_bool_t allowed; + + /* policy->rules is in the order the rules appeared + * in the config file, i.e. last rule that applies wins + */ + + allowed = FALSE; + link = _dbus_list_get_first_link (&policy->rules); + while (link != NULL) + { + BusPolicyRule *rule = link->data; + + link = _dbus_list_get_next_link (&policy->rules, link); + + /* Rule is skipped if it specifies a different service name from + * the desired one. + */ + + if (rule->type != BUS_POLICY_RULE_OWN) + continue; + + if (rule->d.own.service_name != NULL) + { + if (!_dbus_string_equal_c_str (service_name, + rule->d.own.service_name)) + continue; + } + + /* Use this rule */ + allowed = rule->allow; + } + + return allowed; +} + +#ifdef DBUS_BUILD_TESTS + +dbus_bool_t +bus_policy_test (const DBusString *test_data_dir) +{ + /* This doesn't do anything for now because I decided to do it in + * dispatch.c instead by having some of the clients in dispatch.c + * have particular policies applied to them. + */ + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/bus/policy.h b/bus/policy.h new file mode 100644 index 00000000..1782dbf3 --- /dev/null +++ b/bus/policy.h @@ -0,0 +1,164 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* policy.h Bus security policy + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_POLICY_H +#define BUS_POLICY_H + +#include +#include +#include +#include +#include "bus.h" + +typedef enum +{ + BUS_POLICY_RULE_SEND, + BUS_POLICY_RULE_RECEIVE, + BUS_POLICY_RULE_OWN, + BUS_POLICY_RULE_USER, + BUS_POLICY_RULE_GROUP +} BusPolicyRuleType; + +/** determines whether the rule affects a connection, or some global item */ +#define BUS_POLICY_RULE_IS_PER_CLIENT(rule) (!((rule)->type == BUS_POLICY_RULE_USER || \ + (rule)->type == BUS_POLICY_RULE_GROUP)) + +struct BusPolicyRule +{ + int refcount; + + BusPolicyRuleType type; + + unsigned int allow : 1; /**< #TRUE if this allows, #FALSE if it denies */ + + union + { + struct + { + /* message type can be DBUS_MESSAGE_TYPE_INVALID meaning "any" */ + int message_type; + /* any of these can be NULL meaning "any" */ + char *path; + char *interface; + char *member; + char *error; + char *destination; + unsigned int eavesdrop : 1; + unsigned int requested_reply : 1; + unsigned int log : 1; + } send; + + struct + { + /* message type can be DBUS_MESSAGE_TYPE_INVALID meaning "any" */ + int message_type; + /* any of these can be NULL meaning "any" */ + char *path; + char *interface; + char *member; + char *error; + char *origin; + unsigned int eavesdrop : 1; + unsigned int requested_reply : 1; + } receive; + + struct + { + /* can be NULL meaning "any" */ + char *service_name; + } own; + + struct + { + /* can be DBUS_UID_UNSET meaning "any" */ + dbus_uid_t uid; + } user; + + struct + { + /* can be DBUS_GID_UNSET meaning "any" */ + dbus_gid_t gid; + } group; + + } d; +}; + +BusPolicyRule* bus_policy_rule_new (BusPolicyRuleType type, + dbus_bool_t allow); +BusPolicyRule* bus_policy_rule_ref (BusPolicyRule *rule); +void bus_policy_rule_unref (BusPolicyRule *rule); + +BusPolicy* bus_policy_new (void); +BusPolicy* bus_policy_ref (BusPolicy *policy); +void bus_policy_unref (BusPolicy *policy); +BusClientPolicy* bus_policy_create_client_policy (BusPolicy *policy, + DBusConnection *connection, + DBusError *error); +dbus_bool_t bus_policy_allow_unix_user (BusPolicy *policy, + unsigned long uid); +dbus_bool_t bus_policy_allow_windows_user (BusPolicy *policy, + const char *windows_sid); +dbus_bool_t bus_policy_append_default_rule (BusPolicy *policy, + BusPolicyRule *rule); +dbus_bool_t bus_policy_append_mandatory_rule (BusPolicy *policy, + BusPolicyRule *rule); +dbus_bool_t bus_policy_append_user_rule (BusPolicy *policy, + dbus_uid_t uid, + BusPolicyRule *rule); +dbus_bool_t bus_policy_append_group_rule (BusPolicy *policy, + dbus_gid_t gid, + BusPolicyRule *rule); +dbus_bool_t bus_policy_append_console_rule (BusPolicy *policy, + dbus_bool_t at_console, + BusPolicyRule *rule); + +dbus_bool_t bus_policy_merge (BusPolicy *policy, + BusPolicy *to_absorb); + +BusClientPolicy* bus_client_policy_new (void); +BusClientPolicy* bus_client_policy_ref (BusClientPolicy *policy); +void bus_client_policy_unref (BusClientPolicy *policy); +dbus_bool_t bus_client_policy_check_can_send (BusClientPolicy *policy, + BusRegistry *registry, + dbus_bool_t requested_reply, + DBusConnection *receiver, + DBusMessage *message, + dbus_int32_t *toggles, + dbus_bool_t *log); +dbus_bool_t bus_client_policy_check_can_receive (BusClientPolicy *policy, + BusRegistry *registry, + dbus_bool_t requested_reply, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusConnection *proposed_recipient, + DBusMessage *message, + dbus_int32_t *toggles); +dbus_bool_t bus_client_policy_check_can_own (BusClientPolicy *policy, + DBusConnection *connection, + const DBusString *service_name); +dbus_bool_t bus_client_policy_append_rule (BusClientPolicy *policy, + BusPolicyRule *rule); +void bus_client_policy_optimize (BusClientPolicy *policy); + + +#endif /* BUS_POLICY_H */ diff --git a/bus/rc.messagebus.in b/bus/rc.messagebus.in new file mode 100644 index 00000000..b147503d --- /dev/null +++ b/bus/rc.messagebus.in @@ -0,0 +1,79 @@ +#!/bin/sh +# +# messagebus: The D-BUS systemwide message bus +# +# chkconfig: 345 97 03 +# description: This is a daemon which broadcasts notifications of system events \ +# and other messages. See http://www.freedesktop.org/software/dbus/ +# +# processname: dbus-daemon +# pidfile: @DBUS_SYSTEM_PID_FILE@ +# + +# Sanity checks. +#[ -x @EXPANDED_BINDIR@/dbus-daemon ] || exit 0 + +# Source function library. +#. @EXPANDED_SYSCONFDIR@/rc.d/init.d/functions + +# so we can rearrange this easily +#processname=dbus-daemon +#servicename=messagebus + +#RETVAL=0 + +start() { + echo "Starting system message bus" + if [ -x @EXPANDED_BINDIR@/dbus-uuidgen ] ; then + @EXPANDED_BINDIR@/dbus-uuidgen --ensure + fi + + if [ -x @EXPANDED_BINDIR@/dbus-daemon ];then + @EXPANDED_BINDIR@/dbus-daemon --system + fi + #daemon --check $servicename $processname --system + #RETVAL=$? + #echo + #[ $RETVAL -eq 0 ] && touch @EXPANDED_LOCALSTATEDIR@/lock/subsys/$servicename +} + +stop() { + echo "Stopping system message bus" + + ## we don't want to kill all the per-user $processname, we want + ## to use the pid file *only*; because we use the fake nonexistent + ## program name "$servicename" that should be safe-ish + killall dbus-daemon + #RETVAL=$? + #echo + #if [ $RETVAL -eq 0 ]; then + # rm -f @EXPANDED_LOCALSTATEDIR@/lock/subsys/$servicename + # rm -f @DBUS_SYSTEM_PID_FILE@ + #fi +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status $processname + RETVAL=$? + ;; + restart) + stop + start + ;; + reload) + echo "Message bus can't reload its configuration, you have to restart it" + RETVAL=$? + ;; + *) + echo $"Usage: $0 {start|stop|status|restart|reload}" + ;; +esac +exit $RETVAL diff --git a/bus/selinux.c b/bus/selinux.c new file mode 100644 index 00000000..5a9af5ac --- /dev/null +++ b/bus/selinux.c @@ -0,0 +1,1091 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * selinux.c SELinux security checks for D-Bus + * + * Author: Matthew Rickard + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include +#include +#include +#include "selinux.h" +#include "services.h" +#include "policy.h" +#include "utils.h" +#include "config-parser.h" + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_SELINUX +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* HAVE_SELINUX */ +#ifdef HAVE_LIBAUDIT +#include +#include +#endif /* HAVE_LIBAUDIT */ + +#define BUS_SID_FROM_SELINUX(sid) ((BusSELinuxID*) (sid)) +#define SELINUX_SID_FROM_BUS(sid) ((security_id_t) (sid)) + +#ifdef HAVE_SELINUX +/* Store the value telling us if SELinux is enabled in the kernel. */ +static dbus_bool_t selinux_enabled = FALSE; + +/* Store an avc_entry_ref to speed AVC decisions. */ +static struct avc_entry_ref aeref; + +/* Store the SID of the bus itself to use as the default. */ +static security_id_t bus_sid = SECSID_WILD; + +/* Thread to listen for SELinux status changes via netlink. */ +static pthread_t avc_notify_thread; + +/* Prototypes for AVC callback functions. */ +static void log_callback (const char *fmt, ...); +static void log_audit_callback (void *data, security_class_t class, char *buf, size_t bufleft); +static void *avc_create_thread (void (*run) (void)); +static void avc_stop_thread (void *thread); +static void *avc_alloc_lock (void); +static void avc_get_lock (void *lock); +static void avc_release_lock (void *lock); +static void avc_free_lock (void *lock); + +/* AVC callback structures for use in avc_init. */ +static const struct avc_memory_callback mem_cb = +{ + .func_malloc = dbus_malloc, + .func_free = dbus_free +}; +static const struct avc_log_callback log_cb = +{ + .func_log = log_callback, + .func_audit = log_audit_callback +}; +static const struct avc_thread_callback thread_cb = +{ + .func_create_thread = avc_create_thread, + .func_stop_thread = avc_stop_thread +}; +static const struct avc_lock_callback lock_cb = +{ + .func_alloc_lock = avc_alloc_lock, + .func_get_lock = avc_get_lock, + .func_release_lock = avc_release_lock, + .func_free_lock = avc_free_lock +}; +#endif /* HAVE_SELINUX */ + +/** + * Log callback to log denial messages from the AVC. + * This is used in avc_init. Logs to both standard + * error and syslogd. + * + * @param fmt the format string + * @param variable argument list + */ +#ifdef HAVE_SELINUX + +#ifdef HAVE_LIBAUDIT +static int audit_fd = -1; +#endif + +void +bus_selinux_audit_init(void) +{ +#ifdef HAVE_LIBAUDIT + audit_fd = audit_open (); + + if (audit_fd < 0) + { + /* If kernel doesn't support audit, bail out */ + if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) + return; + /* If user bus, bail out */ + if (errno == EPERM && getuid() != 0) + return; + _dbus_warn ("Failed opening connection to the audit subsystem"); + } +#endif /* HAVE_LIBAUDIT */ +} + +static void +log_callback (const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + +#ifdef HAVE_LIBAUDIT + if (audit_fd >= 0) + { + capng_get_caps_process(); + if (capng_have_capability(CAPNG_EFFECTIVE, CAP_AUDIT_WRITE)) + { + char buf[PATH_MAX*2]; + + /* FIXME: need to change this to show real user */ + vsnprintf(buf, sizeof(buf), fmt, ap); + audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL, + NULL, getuid()); + return; + } + } +#endif /* HAVE_LIBAUDIT */ + + vsyslog (LOG_INFO, fmt, ap); + va_end(ap); +} + +/** + * On a policy reload we need to reparse the SELinux configuration file, since + * this could have changed. Send a SIGHUP to reload all configs. + */ +static int +policy_reload_callback (u_int32_t event, security_id_t ssid, + security_id_t tsid, security_class_t tclass, + access_vector_t perms, access_vector_t *out_retained) +{ + if (event == AVC_CALLBACK_RESET) + return raise (SIGHUP); + + return 0; +} + +/** + * Log any auxiliary data + */ +static void +log_audit_callback (void *data, security_class_t class, char *buf, size_t bufleft) +{ + DBusString *audmsg = data; + + if (bufleft > (size_t) _dbus_string_get_length(audmsg)) + { + _dbus_string_copy_to_buffer_with_nul (audmsg, buf, bufleft); + } + else + { + DBusString s; + + _dbus_string_init_const(&s, "Buffer too small for audit message"); + + if (bufleft > (size_t) _dbus_string_get_length(&s)) + _dbus_string_copy_to_buffer_with_nul (&s, buf, bufleft); + } +} + +/** + * Create thread to notify the AVC of enforcing and policy reload + * changes via netlink. + * + * @param run the thread run function + * @return pointer to the thread + */ +static void * +avc_create_thread (void (*run) (void)) +{ + int rc; + + rc = pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL); + if (rc != 0) + { + _dbus_warn ("Failed to start AVC thread: %s\n", _dbus_strerror (rc)); + exit (1); + } + return &avc_notify_thread; +} + +/* Stop AVC netlink thread. */ +static void +avc_stop_thread (void *thread) +{ + pthread_cancel (*(pthread_t *) thread); +} + +/* Allocate a new AVC lock. */ +static void * +avc_alloc_lock (void) +{ + pthread_mutex_t *avc_mutex; + + avc_mutex = dbus_new (pthread_mutex_t, 1); + if (avc_mutex == NULL) + { + _dbus_warn ("Could not create mutex: %s\n", _dbus_strerror (errno)); + exit (1); + } + pthread_mutex_init (avc_mutex, NULL); + + return avc_mutex; +} + +/* Acquire an AVC lock. */ +static void +avc_get_lock (void *lock) +{ + pthread_mutex_lock (lock); +} + +/* Release an AVC lock. */ +static void +avc_release_lock (void *lock) +{ + pthread_mutex_unlock (lock); +} + +/* Free an AVC lock. */ +static void +avc_free_lock (void *lock) +{ + pthread_mutex_destroy (lock); + dbus_free (lock); +} +#endif /* HAVE_SELINUX */ + +/** + * Return whether or not SELinux is enabled; must be + * called after bus_selinux_init. + */ +dbus_bool_t +bus_selinux_enabled (void) +{ +#ifdef HAVE_SELINUX + return selinux_enabled; +#else + return FALSE; +#endif /* HAVE_SELINUX */ +} + +/** + * Do early initialization; determine whether SELinux is enabled. + */ +dbus_bool_t +bus_selinux_pre_init (void) +{ +#ifdef HAVE_SELINUX + int r; + _dbus_assert (bus_sid == SECSID_WILD); + + /* Determine if we are running an SELinux kernel. */ + r = is_selinux_enabled (); + if (r < 0) + { + _dbus_warn ("Could not tell if SELinux is enabled: %s\n", + _dbus_strerror (errno)); + return FALSE; + } + + selinux_enabled = r != 0; + return TRUE; +#else + return TRUE; +#endif +} + +/** + * Initialize the user space access vector cache (AVC) for D-Bus and set up + * logging callbacks. + */ +dbus_bool_t +bus_selinux_full_init (void) +{ +#ifdef HAVE_SELINUX + char *bus_context; + + _dbus_assert (bus_sid == SECSID_WILD); + + if (!selinux_enabled) + { + _dbus_verbose ("SELinux not enabled in this kernel.\n"); + return TRUE; + } + + _dbus_verbose ("SELinux is enabled in this kernel.\n"); + + avc_entry_ref_init (&aeref); + if (avc_init ("avc", &mem_cb, &log_cb, &thread_cb, &lock_cb) < 0) + { + _dbus_warn ("Failed to start Access Vector Cache (AVC).\n"); + return FALSE; + } + else + { + openlog ("dbus", LOG_PERROR, LOG_USER); + _dbus_verbose ("Access Vector Cache (AVC) started.\n"); + } + + if (avc_add_callback (policy_reload_callback, AVC_CALLBACK_RESET, + NULL, NULL, 0, 0) < 0) + { + _dbus_warn ("Failed to add policy reload callback: %s\n", + _dbus_strerror (errno)); + avc_destroy (); + return FALSE; + } + + bus_context = NULL; + bus_sid = SECSID_WILD; + + if (getcon (&bus_context) < 0) + { + _dbus_verbose ("Error getting context of bus: %s\n", + _dbus_strerror (errno)); + return FALSE; + } + + if (avc_context_to_sid (bus_context, &bus_sid) < 0) + { + _dbus_verbose ("Error getting SID from bus context: %s\n", + _dbus_strerror (errno)); + freecon (bus_context); + return FALSE; + } + + freecon (bus_context); + +#endif /* HAVE_SELINUX */ + return TRUE; +} + +/** + * Decrement SID reference count. + * + * @param sid the SID to decrement + */ +void +bus_selinux_id_unref (BusSELinuxID *sid) +{ +#ifdef HAVE_SELINUX + if (!selinux_enabled) + return; + + _dbus_assert (sid != NULL); + + sidput (SELINUX_SID_FROM_BUS (sid)); +#endif /* HAVE_SELINUX */ +} + +void +bus_selinux_id_ref (BusSELinuxID *sid) +{ +#ifdef HAVE_SELINUX + if (!selinux_enabled) + return; + + _dbus_assert (sid != NULL); + + sidget (SELINUX_SID_FROM_BUS (sid)); +#endif /* HAVE_SELINUX */ +} + +/** + * Determine if the SELinux security policy allows the given sender + * security context to go to the given recipient security context. + * This function determines if the requested permissions are to be + * granted from the connection to the message bus or to another + * optionally supplied security identifier (e.g. for a service + * context). Currently these permissions are either send_msg or + * acquire_svc in the dbus class. + * + * @param sender_sid source security context + * @param override_sid is the target security context. If SECSID_WILD this will + * use the context of the bus itself (e.g. the default). + * @param target_class is the target security class. + * @param requested is the requested permissions. + * @returns #TRUE if security policy allows the send. + */ +#ifdef HAVE_SELINUX +static dbus_bool_t +bus_selinux_check (BusSELinuxID *sender_sid, + BusSELinuxID *override_sid, + security_class_t target_class, + access_vector_t requested, + DBusString *auxdata) +{ + if (!selinux_enabled) + return TRUE; + + /* Make the security check. AVC checks enforcing mode here as well. */ + if (avc_has_perm (SELINUX_SID_FROM_BUS (sender_sid), + override_sid ? + SELINUX_SID_FROM_BUS (override_sid) : + SELINUX_SID_FROM_BUS (bus_sid), + target_class, requested, &aeref, auxdata) < 0) + { + switch (errno) + { + case EACCES: + _dbus_verbose ("SELinux denying due to security policy.\n"); + return FALSE; + case EINVAL: + _dbus_verbose ("SELinux denying due to invalid security context.\n"); + return FALSE; + default: + _dbus_verbose ("SELinux denying due to: %s\n", _dbus_strerror (errno)); + return FALSE; + } + } + else + return TRUE; +} +#endif /* HAVE_SELINUX */ + +/** + * Returns true if the given connection can acquire a service, + * assuming the given security ID is needed for that service. + * + * @param connection connection that wants to own the service + * @param service_sid the SID of the service from the table + * @returns #TRUE if acquire is permitted. + */ +dbus_bool_t +bus_selinux_allows_acquire_service (DBusConnection *connection, + BusSELinuxID *service_sid, + const char *service_name, + DBusError *error) +{ +#ifdef HAVE_SELINUX + BusSELinuxID *connection_sid; + unsigned long spid; + DBusString auxdata; + dbus_bool_t ret; + + if (!selinux_enabled) + return TRUE; + + connection_sid = bus_connection_get_selinux_id (connection); + if (!dbus_connection_get_unix_process_id (connection, &spid)) + spid = 0; + + if (!_dbus_string_init (&auxdata)) + goto oom; + + if (!_dbus_string_append (&auxdata, "service=")) + goto oom; + + if (!_dbus_string_append (&auxdata, service_name)) + goto oom; + + if (spid) + { + if (!_dbus_string_append (&auxdata, " spid=")) + goto oom; + + if (!_dbus_string_append_uint (&auxdata, spid)) + goto oom; + } + + ret = bus_selinux_check (connection_sid, + service_sid, + SECCLASS_DBUS, + DBUS__ACQUIRE_SVC, + &auxdata); + + _dbus_string_free (&auxdata); + return ret; + + oom: + _dbus_string_free (&auxdata); + BUS_SET_OOM (error); + return FALSE; + +#else + return TRUE; +#endif /* HAVE_SELINUX */ +} + +/** + * Check if SELinux security controls allow the message to be sent to a + * particular connection based on the security context of the sender and + * that of the receiver. The destination connection need not be the + * addressed recipient, it could be an "eavesdropper" + * + * @param sender the sender of the message. + * @param proposed_recipient the connection the message is to be sent to. + * @returns whether to allow the send + */ +dbus_bool_t +bus_selinux_allows_send (DBusConnection *sender, + DBusConnection *proposed_recipient, + const char *msgtype, + const char *interface, + const char *member, + const char *error_name, + const char *destination, + DBusError *error) +{ +#ifdef HAVE_SELINUX + BusSELinuxID *recipient_sid; + BusSELinuxID *sender_sid; + unsigned long spid, tpid; + DBusString auxdata; + dbus_bool_t ret; + dbus_bool_t string_alloced; + + if (!selinux_enabled) + return TRUE; + + if (!sender || !dbus_connection_get_unix_process_id (sender, &spid)) + spid = 0; + if (!proposed_recipient || !dbus_connection_get_unix_process_id (proposed_recipient, &tpid)) + tpid = 0; + + string_alloced = FALSE; + if (!_dbus_string_init (&auxdata)) + goto oom; + string_alloced = TRUE; + + if (!_dbus_string_append (&auxdata, "msgtype=")) + goto oom; + + if (!_dbus_string_append (&auxdata, msgtype)) + goto oom; + + if (interface) + { + if (!_dbus_string_append (&auxdata, " interface=")) + goto oom; + if (!_dbus_string_append (&auxdata, interface)) + goto oom; + } + + if (member) + { + if (!_dbus_string_append (&auxdata, " member=")) + goto oom; + if (!_dbus_string_append (&auxdata, member)) + goto oom; + } + + if (error_name) + { + if (!_dbus_string_append (&auxdata, " error_name=")) + goto oom; + if (!_dbus_string_append (&auxdata, error_name)) + goto oom; + } + + if (destination) + { + if (!_dbus_string_append (&auxdata, " dest=")) + goto oom; + if (!_dbus_string_append (&auxdata, destination)) + goto oom; + } + + if (spid) + { + if (!_dbus_string_append (&auxdata, " spid=")) + goto oom; + + if (!_dbus_string_append_uint (&auxdata, spid)) + goto oom; + } + + if (tpid) + { + if (!_dbus_string_append (&auxdata, " tpid=")) + goto oom; + + if (!_dbus_string_append_uint (&auxdata, tpid)) + goto oom; + } + + sender_sid = bus_connection_get_selinux_id (sender); + /* A NULL proposed_recipient means the bus itself. */ + if (proposed_recipient) + recipient_sid = bus_connection_get_selinux_id (proposed_recipient); + else + recipient_sid = BUS_SID_FROM_SELINUX (bus_sid); + + ret = bus_selinux_check (sender_sid, + recipient_sid, + SECCLASS_DBUS, + DBUS__SEND_MSG, + &auxdata); + + _dbus_string_free (&auxdata); + + return ret; + + oom: + if (string_alloced) + _dbus_string_free (&auxdata); + BUS_SET_OOM (error); + return FALSE; + +#else + return TRUE; +#endif /* HAVE_SELINUX */ +} + +dbus_bool_t +bus_selinux_append_context (DBusMessage *message, + BusSELinuxID *sid, + DBusError *error) +{ +#ifdef HAVE_SELINUX + char *context; + + if (avc_sid_to_context (SELINUX_SID_FROM_BUS (sid), &context) < 0) + { + if (errno == ENOMEM) + BUS_SET_OOM (error); + else + dbus_set_error (error, DBUS_ERROR_FAILED, + "Error getting context from SID: %s\n", + _dbus_strerror (errno)); + return FALSE; + } + if (!dbus_message_append_args (message, + DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE, + &context, + strlen (context), + DBUS_TYPE_INVALID)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + freecon (context); + return TRUE; +#else + return TRUE; +#endif +} + +/** + * Gets the security context of a connection to the bus. It is up to + * the caller to freecon() when they are done. + * + * @param connection the connection to get the context of. + * @param con the location to store the security context. + * @returns #TRUE if context is successfully obtained. + */ +#ifdef HAVE_SELINUX +static dbus_bool_t +bus_connection_read_selinux_context (DBusConnection *connection, + char **con) +{ + int fd; + + if (!selinux_enabled) + return FALSE; + + _dbus_assert (connection != NULL); + + if (!dbus_connection_get_unix_fd (connection, &fd)) + { + _dbus_verbose ("Failed to get file descriptor of socket.\n"); + return FALSE; + } + + if (getpeercon (fd, con) < 0) + { + _dbus_verbose ("Error getting context of socket peer: %s\n", + _dbus_strerror (errno)); + return FALSE; + } + + _dbus_verbose ("Successfully read connection context.\n"); + return TRUE; +} +#endif /* HAVE_SELINUX */ + +/** + * Read the SELinux ID from the connection. + * + * @param connection the connection to read from + * @returns the SID if successfully determined, #NULL otherwise. + */ +BusSELinuxID* +bus_selinux_init_connection_id (DBusConnection *connection, + DBusError *error) +{ +#ifdef HAVE_SELINUX + char *con; + security_id_t sid; + + if (!selinux_enabled) + return NULL; + + if (!bus_connection_read_selinux_context (connection, &con)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to read an SELinux context from connection"); + _dbus_verbose ("Error getting peer context.\n"); + return NULL; + } + + _dbus_verbose ("Converting context to SID to store on connection\n"); + + if (avc_context_to_sid (con, &sid) < 0) + { + if (errno == ENOMEM) + BUS_SET_OOM (error); + else + dbus_set_error (error, DBUS_ERROR_FAILED, + "Error getting SID from context \"%s\": %s\n", + con, _dbus_strerror (errno)); + + _dbus_warn ("Error getting SID from context \"%s\": %s\n", + con, _dbus_strerror (errno)); + + freecon (con); + return NULL; + } + + freecon (con); + return BUS_SID_FROM_SELINUX (sid); +#else + return NULL; +#endif /* HAVE_SELINUX */ +} + + +/** + * Function for freeing hash table data. These SIDs + * should no longer be referenced. + */ +static void +bus_selinux_id_table_free_value (BusSELinuxID *sid) +{ +#ifdef HAVE_SELINUX + /* NULL sometimes due to how DBusHashTable works */ + if (sid) + bus_selinux_id_unref (sid); +#endif /* HAVE_SELINUX */ +} + +/** + * Creates a new table mapping service names to security ID. + * A security ID is a "compiled" security context, a security + * context is just a string. + * + * @returns the new table or #NULL if no memory + */ +DBusHashTable* +bus_selinux_id_table_new (void) +{ + return _dbus_hash_table_new (DBUS_HASH_STRING, + (DBusFreeFunction) dbus_free, + (DBusFreeFunction) bus_selinux_id_table_free_value); +} + +/** + * Hashes a service name and service context into the service SID + * table as a string and a SID. + * + * @param service_name is the name of the service. + * @param service_context is the context of the service. + * @param service_table is the table to hash them into. + * @return #FALSE if not enough memory + */ +dbus_bool_t +bus_selinux_id_table_insert (DBusHashTable *service_table, + const char *service_name, + const char *service_context) +{ +#ifdef HAVE_SELINUX + dbus_bool_t retval; + security_id_t sid; + char *key; + + if (!selinux_enabled) + return TRUE; + + sid = SECSID_WILD; + retval = FALSE; + + key = _dbus_strdup (service_name); + if (key == NULL) + return retval; + + if (avc_context_to_sid ((char *) service_context, &sid) < 0) + { + if (errno == ENOMEM) + { + dbus_free (key); + return FALSE; + } + + _dbus_warn ("Error getting SID from context \"%s\": %s\n", + (char *) service_context, + _dbus_strerror (errno)); + goto out; + } + + if (!_dbus_hash_table_insert_string (service_table, + key, + BUS_SID_FROM_SELINUX (sid))) + goto out; + + _dbus_verbose ("Parsed \tservice: %s \n\t\tcontext: %s\n", + key, + sid->ctx); + + /* These are owned by the hash, so clear them to avoid unref */ + key = NULL; + sid = SECSID_WILD; + + retval = TRUE; + + out: + if (sid != SECSID_WILD) + sidput (sid); + + if (key) + dbus_free (key); + + return retval; +#else + return TRUE; +#endif /* HAVE_SELINUX */ +} + + +/** + * Find the security identifier associated with a particular service + * name. Return a pointer to this SID, or #NULL/SECSID_WILD if the + * service is not found in the hash table. This should be nearly a + * constant time operation. If SELinux support is not available, + * always return NULL. + * + * @param service_table the hash table to check for service name. + * @param service_name the name of the service to look for. + * @returns the SELinux ID associated with the service + */ +BusSELinuxID* +bus_selinux_id_table_lookup (DBusHashTable *service_table, + const DBusString *service_name) +{ +#ifdef HAVE_SELINUX + security_id_t sid; + + sid = SECSID_WILD; /* default context */ + + if (!selinux_enabled) + return NULL; + + _dbus_verbose ("Looking up service SID for %s\n", + _dbus_string_get_const_data (service_name)); + + sid = _dbus_hash_table_lookup_string (service_table, + _dbus_string_get_const_data (service_name)); + + if (sid == SECSID_WILD) + _dbus_verbose ("Service %s not found\n", + _dbus_string_get_const_data (service_name)); + else + _dbus_verbose ("Service %s found\n", + _dbus_string_get_const_data (service_name)); + + return BUS_SID_FROM_SELINUX (sid); +#endif /* HAVE_SELINUX */ + return NULL; +} + +/** + * Get the SELinux policy root. This is used to find the D-Bus + * specific config file within the policy. + */ +const char * +bus_selinux_get_policy_root (void) +{ +#ifdef HAVE_SELINUX + return selinux_policy_root (); +#else + return NULL; +#endif /* HAVE_SELINUX */ +} + +/** + * For debugging: Print out the current hash table of service SIDs. + */ +void +bus_selinux_id_table_print (DBusHashTable *service_table) +{ +#ifdef DBUS_ENABLE_VERBOSE_MODE +#ifdef HAVE_SELINUX + DBusHashIter iter; + + if (!selinux_enabled) + return; + + _dbus_verbose ("Service SID Table:\n"); + _dbus_hash_iter_init (service_table, &iter); + while (_dbus_hash_iter_next (&iter)) + { + const char *key = _dbus_hash_iter_get_string_key (&iter); + security_id_t sid = _dbus_hash_iter_get_value (&iter); + _dbus_verbose ("The key is %s\n", key); + _dbus_verbose ("The context is %s\n", sid->ctx); + _dbus_verbose ("The refcount is %d\n", sid->refcnt); + } +#endif /* HAVE_SELINUX */ +#endif /* DBUS_ENABLE_VERBOSE_MODE */ +} + + +#ifdef DBUS_ENABLE_VERBOSE_MODE +#ifdef HAVE_SELINUX +/** + * Print out some AVC statistics. + */ +static void +bus_avc_print_stats (void) +{ + struct avc_cache_stats cstats; + + if (!selinux_enabled) + return; + + _dbus_verbose ("AVC Statistics:\n"); + avc_cache_stats (&cstats); + avc_av_stats (); + _dbus_verbose ("AVC Cache Statistics:\n"); + _dbus_verbose ("Entry lookups: %d\n", cstats.entry_lookups); + _dbus_verbose ("Entry hits: %d\n", cstats.entry_hits); + _dbus_verbose ("Entry misses %d\n", cstats.entry_misses); + _dbus_verbose ("Entry discards: %d\n", cstats.entry_discards); + _dbus_verbose ("CAV lookups: %d\n", cstats.cav_lookups); + _dbus_verbose ("CAV hits: %d\n", cstats.cav_hits); + _dbus_verbose ("CAV probes: %d\n", cstats.cav_probes); + _dbus_verbose ("CAV misses: %d\n", cstats.cav_misses); +} +#endif /* HAVE_SELINUX */ +#endif /* DBUS_ENABLE_VERBOSE_MODE */ + + +/** + * Destroy the AVC before we terminate. + */ +void +bus_selinux_shutdown (void) +{ +#ifdef HAVE_SELINUX + if (!selinux_enabled) + return; + + _dbus_verbose ("AVC shutdown\n"); + + if (bus_sid != SECSID_WILD) + { + sidput (bus_sid); + bus_sid = SECSID_WILD; + +#ifdef DBUS_ENABLE_VERBOSE_MODE + + if (_dbus_is_verbose()) + bus_avc_print_stats (); + +#endif /* DBUS_ENABLE_VERBOSE_MODE */ + + avc_destroy (); +#ifdef HAVE_LIBAUDIT + audit_close (audit_fd); +#endif /* HAVE_LIBAUDIT */ + } +#endif /* HAVE_SELINUX */ +} + +/* The !HAVE_LIBAUDIT case lives in dbus-sysdeps-util-unix.c */ +#ifdef HAVE_LIBAUDIT +/** + * Changes the user and group the bus is running as. + * + * @param user the user to become + * @param error return location for errors + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_change_to_daemon_user (const char *user, + DBusError *error) +{ + dbus_uid_t uid; + dbus_gid_t gid; + DBusString u; + + _dbus_string_init_const (&u, user); + + if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "User '%s' does not appear to exist?", + user); + return FALSE; + } + + /* If we were root */ + if (_dbus_geteuid () == 0) + { + int rc; + + capng_clear (CAPNG_SELECT_BOTH); + capng_update (CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, + CAP_AUDIT_WRITE); + rc = capng_change_id (uid, gid, 0); + if (rc) + { + switch (rc) { + default: + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to drop capabilities: %s\n", + _dbus_strerror (errno)); + break; + case -4: + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to set GID to %lu: %s", gid, + _dbus_strerror (errno)); + break; + case -5: + _dbus_warn ("Failed to drop supplementary groups: %s\n", + _dbus_strerror (errno)); + break; + case -6: + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to set UID to %lu: %s", uid, + _dbus_strerror (errno)); + break; + case -7: + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to unset keep-capabilities: %s\n", + _dbus_strerror (errno)); + break; + } + return FALSE; + } + } + + return TRUE; +} +#endif + diff --git a/bus/selinux.h b/bus/selinux.h new file mode 100644 index 00000000..3bab36de --- /dev/null +++ b/bus/selinux.h @@ -0,0 +1,72 @@ +/* selinux.h SELinux security check headers for D-BUS + * + * Author: Matthew Rickard + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_SELINUX_H +#define BUS_SELINUX_H + +#include +#include +#include "services.h" + +dbus_bool_t bus_selinux_pre_init (void); +dbus_bool_t bus_selinux_full_init(void); +void bus_selinux_shutdown (void); + +dbus_bool_t bus_selinux_enabled (void); + +void bus_selinux_id_ref (BusSELinuxID *sid); +void bus_selinux_id_unref (BusSELinuxID *sid); + +DBusHashTable* bus_selinux_id_table_new (void); +BusSELinuxID* bus_selinux_id_table_lookup (DBusHashTable *service_table, + const DBusString *service_name); +dbus_bool_t bus_selinux_id_table_insert (DBusHashTable *service_table, + const char *service_name, + const char *service_context); +void bus_selinux_id_table_print (DBusHashTable *service_table); +const char* bus_selinux_get_policy_root (void); + +dbus_bool_t bus_selinux_append_context (DBusMessage *message, + BusSELinuxID *context, + DBusError *error); + +dbus_bool_t bus_selinux_allows_acquire_service (DBusConnection *connection, + BusSELinuxID *service_sid, + const char *service_name, + DBusError *error); + +dbus_bool_t bus_selinux_allows_send (DBusConnection *sender, + DBusConnection *proposed_recipient, + const char *msgtype, /* Supplementary audit data */ + const char *interface, + const char *member, + const char *error_name, + const char *destination, + DBusError *error); + +BusSELinuxID* bus_selinux_init_connection_id (DBusConnection *connection, + DBusError *error); + + +void bus_selinux_audit_init(void); + +#endif /* BUS_SELINUX_H */ diff --git a/bus/services.c b/bus/services.c new file mode 100644 index 00000000..b260c633 --- /dev/null +++ b/bus/services.c @@ -0,0 +1,1306 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* services.c Service management + * + * Copyright (C) 2003 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include +#include +#include +#include + +#include "driver.h" +#include "services.h" +#include "connection.h" +#include "utils.h" +#include "activation.h" +#include "policy.h" +#include "bus.h" +#include "selinux.h" + +struct BusService +{ + int refcount; + + BusRegistry *registry; + char *name; + DBusList *owners; +}; + +struct BusOwner +{ + int refcount; + + BusService *service; + DBusConnection *conn; + + unsigned int allow_replacement : 1; + unsigned int do_not_queue : 1; +}; + +struct BusRegistry +{ + int refcount; + + BusContext *context; + + DBusHashTable *service_hash; + DBusMemPool *service_pool; + DBusMemPool *owner_pool; + + DBusHashTable *service_sid_table; +}; + +BusRegistry* +bus_registry_new (BusContext *context) +{ + BusRegistry *registry; + + registry = dbus_new0 (BusRegistry, 1); + if (registry == NULL) + return NULL; + + registry->refcount = 1; + registry->context = context; + + registry->service_hash = _dbus_hash_table_new (DBUS_HASH_STRING, + NULL, NULL); + if (registry->service_hash == NULL) + goto failed; + + registry->service_pool = _dbus_mem_pool_new (sizeof (BusService), + TRUE); + + if (registry->service_pool == NULL) + goto failed; + + registry->owner_pool = _dbus_mem_pool_new (sizeof (BusOwner), + TRUE); + + if (registry->owner_pool == NULL) + goto failed; + + registry->service_sid_table = NULL; + + return registry; + + failed: + bus_registry_unref (registry); + return NULL; +} + +BusRegistry * +bus_registry_ref (BusRegistry *registry) +{ + _dbus_assert (registry->refcount > 0); + registry->refcount += 1; + + return registry; +} + +void +bus_registry_unref (BusRegistry *registry) +{ + _dbus_assert (registry->refcount > 0); + registry->refcount -= 1; + + if (registry->refcount == 0) + { + if (registry->service_hash) + _dbus_hash_table_unref (registry->service_hash); + if (registry->service_pool) + _dbus_mem_pool_free (registry->service_pool); + if (registry->owner_pool) + _dbus_mem_pool_free (registry->owner_pool); + if (registry->service_sid_table) + _dbus_hash_table_unref (registry->service_sid_table); + + dbus_free (registry); + } +} + +BusService* +bus_registry_lookup (BusRegistry *registry, + const DBusString *service_name) +{ + BusService *service; + + service = _dbus_hash_table_lookup_string (registry->service_hash, + _dbus_string_get_const_data (service_name)); + + return service; +} + +static DBusList * +_bus_service_find_owner_link (BusService *service, + DBusConnection *connection) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&service->owners); + + while (link != NULL) + { + BusOwner *bus_owner; + + bus_owner = (BusOwner *) link->data; + if (bus_owner->conn == connection) + break; + + link = _dbus_list_get_next_link (&service->owners, link); + } + + return link; +} + +static void +bus_owner_set_flags (BusOwner *owner, + dbus_uint32_t flags) +{ + owner->allow_replacement = + (flags & DBUS_NAME_FLAG_ALLOW_REPLACEMENT) != FALSE; + + owner->do_not_queue = + (flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) != FALSE; +} + +static BusOwner * +bus_owner_new (BusService *service, + DBusConnection *conn, + dbus_uint32_t flags) +{ + BusOwner *result; + + result = _dbus_mem_pool_alloc (service->registry->owner_pool); + if (result != NULL) + { + result->refcount = 1; + /* don't ref the connection because we don't want + to block the connection from going away. + transactions take care of reffing the connection + but we need to use refcounting on the owner + so that the owner does not get freed before + we can deref the connection in the transaction + */ + result->conn = conn; + result->service = service; + + if (!bus_connection_add_owned_service (conn, service)) + { + _dbus_mem_pool_dealloc (service->registry->owner_pool, result); + return NULL; + } + + bus_owner_set_flags (result, flags); + } + return result; +} + +static BusOwner * +bus_owner_ref (BusOwner *owner) +{ + _dbus_assert (owner->refcount > 0); + owner->refcount += 1; + + return owner; +} + +static void +bus_owner_unref (BusOwner *owner) +{ + _dbus_assert (owner->refcount > 0); + owner->refcount -= 1; + + if (owner->refcount == 0) + { + bus_connection_remove_owned_service (owner->conn, owner->service); + _dbus_mem_pool_dealloc (owner->service->registry->owner_pool, owner); + } +} + +BusService* +bus_registry_ensure (BusRegistry *registry, + const DBusString *service_name, + DBusConnection *owner_connection_if_created, + dbus_uint32_t flags, + BusTransaction *transaction, + DBusError *error) +{ + BusService *service; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_assert (owner_connection_if_created != NULL); + _dbus_assert (transaction != NULL); + + service = _dbus_hash_table_lookup_string (registry->service_hash, + _dbus_string_get_const_data (service_name)); + if (service != NULL) + return service; + + service = _dbus_mem_pool_alloc (registry->service_pool); + if (service == NULL) + { + BUS_SET_OOM (error); + return NULL; + } + + service->registry = registry; + service->refcount = 1; + + _dbus_verbose ("copying string %p '%s' to service->name\n", + service_name, _dbus_string_get_const_data (service_name)); + if (!_dbus_string_copy_data (service_name, &service->name)) + { + _dbus_mem_pool_dealloc (registry->service_pool, service); + BUS_SET_OOM (error); + return NULL; + } + _dbus_verbose ("copied string %p '%s' to '%s'\n", + service_name, _dbus_string_get_const_data (service_name), + service->name); + + if (!bus_driver_send_service_owner_changed (service->name, + NULL, + bus_connection_get_name (owner_connection_if_created), + transaction, error)) + { + bus_service_unref (service); + return NULL; + } + + if (!bus_activation_service_created (bus_context_get_activation (registry->context), + service->name, transaction, error)) + { + bus_service_unref (service); + return NULL; + } + + if (!bus_service_add_owner (service, owner_connection_if_created, flags, + transaction, error)) + { + bus_service_unref (service); + return NULL; + } + + if (!_dbus_hash_table_insert_string (registry->service_hash, + service->name, + service)) + { + /* The add_owner gets reverted on transaction cancel */ + BUS_SET_OOM (error); + return NULL; + } + + return service; +} + +void +bus_registry_foreach (BusRegistry *registry, + BusServiceForeachFunction function, + void *data) +{ + DBusHashIter iter; + + _dbus_hash_iter_init (registry->service_hash, &iter); + while (_dbus_hash_iter_next (&iter)) + { + BusService *service = _dbus_hash_iter_get_value (&iter); + + (* function) (service, data); + } +} + +dbus_bool_t +bus_registry_list_services (BusRegistry *registry, + char ***listp, + int *array_len) +{ + int i, j, len; + char **retval; + DBusHashIter iter; + + len = _dbus_hash_table_get_n_entries (registry->service_hash); + retval = dbus_new (char *, len + 1); + + if (retval == NULL) + return FALSE; + + _dbus_hash_iter_init (registry->service_hash, &iter); + i = 0; + while (_dbus_hash_iter_next (&iter)) + { + BusService *service = _dbus_hash_iter_get_value (&iter); + + retval[i] = _dbus_strdup (service->name); + if (retval[i] == NULL) + goto error; + + i++; + } + + retval[i] = NULL; + + if (array_len) + *array_len = len; + + *listp = retval; + return TRUE; + + error: + for (j = 0; j < i; j++) + dbus_free (retval[i]); + dbus_free (retval); + + return FALSE; +} + +dbus_bool_t +bus_registry_acquire_service (BusRegistry *registry, + DBusConnection *connection, + const DBusString *service_name, + dbus_uint32_t flags, + dbus_uint32_t *result, + BusTransaction *transaction, + DBusError *error) +{ + dbus_bool_t retval; + DBusConnection *old_owner_conn; + DBusConnection *current_owner_conn; + BusClientPolicy *policy; + BusService *service; + BusActivation *activation; + BusSELinuxID *sid; + BusOwner *primary_owner; + + retval = FALSE; + + if (!_dbus_validate_bus_name (service_name, 0, + _dbus_string_get_length (service_name))) + { + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Requested bus name \"%s\" is not valid", + _dbus_string_get_const_data (service_name)); + + _dbus_verbose ("Attempt to acquire invalid service name\n"); + + goto out; + } + + if (_dbus_string_get_byte (service_name, 0) == ':') + { + /* Not allowed; only base services can start with ':' */ + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Cannot acquire a service starting with ':' such as \"%s\"", + _dbus_string_get_const_data (service_name)); + + _dbus_verbose ("Attempt to acquire invalid base service name \"%s\"", + _dbus_string_get_const_data (service_name)); + + goto out; + } + + if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS)) + { + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Connection \"%s\" is not allowed to own the service \"%s\"because " + "it is reserved for D-Bus' use only", + bus_connection_is_active (connection) ? + bus_connection_get_name (connection) : + "(inactive)", + DBUS_SERVICE_DBUS); + goto out; + } + + policy = bus_connection_get_policy (connection); + _dbus_assert (policy != NULL); + + /* Note that if sid is #NULL then the bus's own context gets used + * in bus_connection_selinux_allows_acquire_service() + */ + sid = bus_selinux_id_table_lookup (registry->service_sid_table, + service_name); + + if (!bus_selinux_allows_acquire_service (connection, sid, + _dbus_string_get_const_data (service_name), error)) + { + + if (dbus_error_is_set (error) && + dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY)) + { + goto out; + } + + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Connection \"%s\" is not allowed to own the service \"%s\" due " + "to SELinux policy", + bus_connection_is_active (connection) ? + bus_connection_get_name (connection) : + "(inactive)", + _dbus_string_get_const_data (service_name)); + goto out; + } + + if (!bus_client_policy_check_can_own (policy, connection, + service_name)) + { + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Connection \"%s\" is not allowed to own the service \"%s\" due " + "to security policies in the configuration file", + bus_connection_is_active (connection) ? + bus_connection_get_name (connection) : + "(inactive)", + _dbus_string_get_const_data (service_name)); + goto out; + } + + if (bus_connection_get_n_services_owned (connection) >= + bus_context_get_max_services_per_connection (registry->context)) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "Connection \"%s\" is not allowed to own more services " + "(increase limits in configuration file if required)", + bus_connection_is_active (connection) ? + bus_connection_get_name (connection) : + "(inactive)"); + goto out; + } + + service = bus_registry_lookup (registry, service_name); + + if (service != NULL) + { + primary_owner = bus_service_get_primary_owner (service); + if (primary_owner != NULL) + old_owner_conn = primary_owner->conn; + else + old_owner_conn = NULL; + } + else + old_owner_conn = NULL; + + if (service == NULL) + { + service = bus_registry_ensure (registry, + service_name, connection, flags, + transaction, error); + if (service == NULL) + goto out; + } + + primary_owner = bus_service_get_primary_owner (service); + if (primary_owner == NULL) + goto out; + + current_owner_conn = primary_owner->conn; + + if (old_owner_conn == NULL) + { + _dbus_assert (current_owner_conn == connection); + + *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; + } + else if (old_owner_conn == connection) + { + bus_owner_set_flags (primary_owner, flags); + *result = DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER; + } + else if (((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && + !(bus_service_get_allow_replacement (service))) || + ((flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && + !(flags & DBUS_NAME_FLAG_REPLACE_EXISTING))) + { + DBusList *link; + BusOwner *temp_owner; + /* Since we can't be queued if we are already in the queue + remove us */ + + link = _bus_service_find_owner_link (service, connection); + if (link != NULL) + { + _dbus_list_unlink (&service->owners, link); + temp_owner = (BusOwner *)link->data; + bus_owner_unref (temp_owner); + _dbus_list_free_link (link); + } + + *result = DBUS_REQUEST_NAME_REPLY_EXISTS; + } + else if (!(flags & DBUS_NAME_FLAG_DO_NOT_QUEUE) && + (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || + !(bus_service_get_allow_replacement (service)))) + { + /* Queue the connection */ + if (!bus_service_add_owner (service, connection, + flags, + transaction, error)) + goto out; + + *result = DBUS_REQUEST_NAME_REPLY_IN_QUEUE; + } + else + { + /* Replace the current owner */ + + /* We enqueue the new owner and remove the first one because + * that will cause NameAcquired and NameLost messages to + * be sent. + */ + + if (!bus_service_add_owner (service, connection, + flags, + transaction, error)) + goto out; + + if (primary_owner->do_not_queue) + { + if (!bus_service_remove_owner (service, old_owner_conn, + transaction, error)) + goto out; + } + else + { + if (!bus_service_swap_owner (service, old_owner_conn, + transaction, error)) + goto out; + } + + + _dbus_assert (connection == bus_service_get_primary_owner (service)->conn); + *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER; + } + + activation = bus_context_get_activation (registry->context); + retval = bus_activation_send_pending_auto_activation_messages (activation, + service, + transaction, + error); + + out: + return retval; +} + +dbus_bool_t +bus_registry_release_service (BusRegistry *registry, + DBusConnection *connection, + const DBusString *service_name, + dbus_uint32_t *result, + BusTransaction *transaction, + DBusError *error) +{ + dbus_bool_t retval; + BusService *service; + + retval = FALSE; + + if (!_dbus_validate_bus_name (service_name, 0, + _dbus_string_get_length (service_name))) + { + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Given bus name \"%s\" is not valid", + _dbus_string_get_const_data (service_name)); + + _dbus_verbose ("Attempt to release invalid service name\n"); + + goto out; + } + + if (_dbus_string_get_byte (service_name, 0) == ':') + { + /* Not allowed; the base service name cannot be created or released */ + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Cannot release a service starting with ':' such as \"%s\"", + _dbus_string_get_const_data (service_name)); + + _dbus_verbose ("Attempt to release invalid base service name \"%s\"", + _dbus_string_get_const_data (service_name)); + + goto out; + } + + if (_dbus_string_equal_c_str (service_name, DBUS_SERVICE_DBUS)) + { + /* Not allowed; the base service name cannot be created or released */ + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Cannot release the %s service because it is owned by the bus", + DBUS_SERVICE_DBUS); + + _dbus_verbose ("Attempt to release service name \"%s\"", + DBUS_SERVICE_DBUS); + + goto out; + } + + service = bus_registry_lookup (registry, service_name); + + if (service == NULL) + { + *result = DBUS_RELEASE_NAME_REPLY_NON_EXISTENT; + } + else if (!bus_service_has_owner (service, connection)) + { + *result = DBUS_RELEASE_NAME_REPLY_NOT_OWNER; + } + else + { + if (!bus_service_remove_owner (service, connection, + transaction, error)) + goto out; + + _dbus_assert (!bus_service_has_owner (service, connection)); + *result = DBUS_RELEASE_NAME_REPLY_RELEASED; + } + + retval = TRUE; + + out: + return retval; +} + +dbus_bool_t +bus_registry_set_service_context_table (BusRegistry *registry, + DBusHashTable *table) +{ + DBusHashTable *new_table; + DBusHashIter iter; + + new_table = bus_selinux_id_table_new (); + if (!new_table) + return FALSE; + + _dbus_hash_iter_init (table, &iter); + while (_dbus_hash_iter_next (&iter)) + { + const char *service = _dbus_hash_iter_get_string_key (&iter); + const char *context = _dbus_hash_iter_get_value (&iter); + + if (!bus_selinux_id_table_insert (new_table, + service, + context)) + return FALSE; + } + + if (registry->service_sid_table) + _dbus_hash_table_unref (registry->service_sid_table); + registry->service_sid_table = new_table; + return TRUE; +} + +static void +bus_service_unlink_owner (BusService *service, + BusOwner *owner) +{ + _dbus_list_remove_last (&service->owners, owner); + bus_owner_unref (owner); +} + +static void +bus_service_unlink (BusService *service) +{ + _dbus_assert (service->owners == NULL); + + /* the service may not be in the hash, if + * the failure causing transaction cancel + * was in the right place, but that's OK + */ + _dbus_hash_table_remove_string (service->registry->service_hash, + service->name); + + bus_service_unref (service); +} + +static void +bus_service_relink (BusService *service, + DBusPreallocatedHash *preallocated) +{ + _dbus_assert (service->owners == NULL); + _dbus_assert (preallocated != NULL); + + _dbus_hash_table_insert_string_preallocated (service->registry->service_hash, + preallocated, + service->name, + service); + + bus_service_ref (service); +} + +/** + * Data used to represent an ownership cancellation in + * a bus transaction. + */ +typedef struct +{ + BusOwner *owner; /**< the owner */ + BusService *service; /**< service to cancel ownership of */ +} OwnershipCancelData; + +static void +cancel_ownership (void *data) +{ + OwnershipCancelData *d = data; + + /* We don't need to send messages notifying of these + * changes, since we're reverting something that was + * cancelled (effectively never really happened) + */ + bus_service_unlink_owner (d->service, d->owner); + + if (d->service->owners == NULL) + bus_service_unlink (d->service); +} + +static void +free_ownership_cancel_data (void *data) +{ + OwnershipCancelData *d = data; + + dbus_connection_unref (d->owner->conn); + bus_owner_unref (d->owner); + bus_service_unref (d->service); + + dbus_free (d); +} + +static dbus_bool_t +add_cancel_ownership_to_transaction (BusTransaction *transaction, + BusService *service, + BusOwner *owner) +{ + OwnershipCancelData *d; + + d = dbus_new (OwnershipCancelData, 1); + if (d == NULL) + return FALSE; + + d->service = service; + d->owner = owner; + + if (!bus_transaction_add_cancel_hook (transaction, cancel_ownership, d, + free_ownership_cancel_data)) + { + dbus_free (d); + return FALSE; + } + + bus_service_ref (d->service); + bus_owner_ref (owner); + dbus_connection_ref (d->owner->conn); + + return TRUE; +} + +/* this function is self-cancelling if you cancel the transaction */ +dbus_bool_t +bus_service_add_owner (BusService *service, + DBusConnection *connection, + dbus_uint32_t flags, + BusTransaction *transaction, + DBusError *error) +{ + BusOwner *bus_owner; + DBusList *bus_owner_link; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* Send service acquired message first, OOM will result + * in cancelling the transaction + */ + if (service->owners == NULL) + { + if (!bus_driver_send_service_acquired (connection, service->name, transaction, error)) + return FALSE; + } + + bus_owner_link = _bus_service_find_owner_link (service, connection); + + if (bus_owner_link == NULL) + { + bus_owner = bus_owner_new (service, connection, flags); + if (bus_owner == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + bus_owner_set_flags (bus_owner, flags); + if (!(flags & DBUS_NAME_FLAG_REPLACE_EXISTING) || service->owners == NULL) + { + if (!_dbus_list_append (&service->owners, + bus_owner)) + { + bus_owner_unref (bus_owner); + BUS_SET_OOM (error); + return FALSE; + } + } + else + { + if (!_dbus_list_insert_after (&service->owners, + _dbus_list_get_first_link (&service->owners), + bus_owner)) + { + bus_owner_unref (bus_owner); + BUS_SET_OOM (error); + return FALSE; + } + } + } + else + { + /* Update the link since we are already in the queue + * No need for operations that can produce OOM + */ + + bus_owner = (BusOwner *) bus_owner_link->data; + if (flags & DBUS_NAME_FLAG_REPLACE_EXISTING) + { + DBusList *link; + _dbus_list_unlink (&service->owners, bus_owner_link); + link = _dbus_list_get_first_link (&service->owners); + _dbus_assert (link != NULL); + + _dbus_list_insert_after_link (&service->owners, link, bus_owner_link); + } + + bus_owner_set_flags (bus_owner, flags); + return TRUE; + } + + if (!add_cancel_ownership_to_transaction (transaction, + service, + bus_owner)) + { + bus_service_unlink_owner (service, bus_owner); + BUS_SET_OOM (error); + return FALSE; + } + + return TRUE; +} + +typedef struct +{ + BusOwner *owner; + BusService *service; + BusOwner *before_owner; /* restore to position before this connection in owners list */ + DBusList *owner_link; + DBusList *service_link; + DBusPreallocatedHash *hash_entry; +} OwnershipRestoreData; + +static void +restore_ownership (void *data) +{ + OwnershipRestoreData *d = data; + DBusList *link; + + _dbus_assert (d->service_link != NULL); + _dbus_assert (d->owner_link != NULL); + + if (d->service->owners == NULL) + { + _dbus_assert (d->hash_entry != NULL); + bus_service_relink (d->service, d->hash_entry); + } + else + { + _dbus_assert (d->hash_entry == NULL); + } + + /* We don't need to send messages notifying of these + * changes, since we're reverting something that was + * cancelled (effectively never really happened) + */ + link = _dbus_list_get_first_link (&d->service->owners); + while (link != NULL) + { + if (link->data == d->before_owner) + break; + + link = _dbus_list_get_next_link (&d->service->owners, link); + } + + _dbus_list_insert_before_link (&d->service->owners, link, d->owner_link); + + /* Note that removing then restoring this changes the order in which + * ServiceDeleted messages are sent on destruction of the + * connection. This should be OK as the only guarantee there is + * that the base service is destroyed last, and we never even + * tentatively remove the base service. + */ + bus_connection_add_owned_service_link (d->owner->conn, d->service_link); + + d->hash_entry = NULL; + d->service_link = NULL; + d->owner_link = NULL; +} + +static void +free_ownership_restore_data (void *data) +{ + OwnershipRestoreData *d = data; + + if (d->service_link) + _dbus_list_free_link (d->service_link); + if (d->owner_link) + _dbus_list_free_link (d->owner_link); + if (d->hash_entry) + _dbus_hash_table_free_preallocated_entry (d->service->registry->service_hash, + d->hash_entry); + + dbus_connection_unref (d->owner->conn); + bus_owner_unref (d->owner); + bus_service_unref (d->service); + + dbus_free (d); +} + +static dbus_bool_t +add_restore_ownership_to_transaction (BusTransaction *transaction, + BusService *service, + BusOwner *owner) +{ + OwnershipRestoreData *d; + DBusList *link; + + d = dbus_new (OwnershipRestoreData, 1); + if (d == NULL) + return FALSE; + + d->service = service; + d->owner = owner; + d->service_link = _dbus_list_alloc_link (service); + d->owner_link = _dbus_list_alloc_link (owner); + d->hash_entry = _dbus_hash_table_preallocate_entry (service->registry->service_hash); + + bus_service_ref (d->service); + bus_owner_ref (d->owner); + dbus_connection_ref (d->owner->conn); + + d->before_owner = NULL; + link = _dbus_list_get_first_link (&service->owners); + while (link != NULL) + { + if (link->data == owner) + { + link = _dbus_list_get_next_link (&service->owners, link); + + if (link) + d->before_owner = link->data; + + break; + } + + link = _dbus_list_get_next_link (&service->owners, link); + } + + if (d->service_link == NULL || + d->owner_link == NULL || + d->hash_entry == NULL || + !bus_transaction_add_cancel_hook (transaction, restore_ownership, d, + free_ownership_restore_data)) + { + free_ownership_restore_data (d); + return FALSE; + } + + return TRUE; +} + +dbus_bool_t +bus_service_swap_owner (BusService *service, + DBusConnection *connection, + BusTransaction *transaction, + DBusError *error) +{ + DBusList *swap_link; + BusOwner *primary_owner; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* We send out notifications before we do any work we + * might have to undo if the notification-sending failed + */ + + /* Send service lost message */ + primary_owner = bus_service_get_primary_owner (service); + if (primary_owner == NULL || primary_owner->conn != connection) + _dbus_assert_not_reached ("Tried to swap a non primary owner"); + + + if (!bus_driver_send_service_lost (connection, service->name, + transaction, error)) + return FALSE; + + if (service->owners == NULL) + { + _dbus_assert_not_reached ("Tried to swap owner of a service that has no owners"); + } + else if (_dbus_list_length_is_one (&service->owners)) + { + _dbus_assert_not_reached ("Tried to swap owner of a service that has no other owners in the queue"); + } + else + { + DBusList *link; + BusOwner *new_owner; + DBusConnection *new_owner_conn; + link = _dbus_list_get_first_link (&service->owners); + _dbus_assert (link != NULL); + link = _dbus_list_get_next_link (&service->owners, link); + _dbus_assert (link != NULL); + + new_owner = (BusOwner *)link->data; + new_owner_conn = new_owner->conn; + + if (!bus_driver_send_service_owner_changed (service->name, + bus_connection_get_name (connection), + bus_connection_get_name (new_owner_conn), + transaction, error)) + return FALSE; + + /* This will be our new owner */ + if (!bus_driver_send_service_acquired (new_owner_conn, + service->name, + transaction, + error)) + return FALSE; + } + + if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) + { + BUS_SET_OOM (error); + return FALSE; + } + + /* unlink the primary and make it the second link */ + swap_link = _dbus_list_get_first_link (&service->owners); + _dbus_list_unlink (&service->owners, swap_link); + + _dbus_list_insert_after_link (&service->owners, + _dbus_list_get_first_link (&service->owners), + swap_link); + + return TRUE; +} + +/* this function is self-cancelling if you cancel the transaction */ +dbus_bool_t +bus_service_remove_owner (BusService *service, + DBusConnection *connection, + BusTransaction *transaction, + DBusError *error) +{ + BusOwner *primary_owner; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* We send out notifications before we do any work we + * might have to undo if the notification-sending failed + */ + + /* Send service lost message */ + primary_owner = bus_service_get_primary_owner (service); + if (primary_owner != NULL && primary_owner->conn == connection) + { + if (!bus_driver_send_service_lost (connection, service->name, + transaction, error)) + return FALSE; + } + else + { + /* if we are not the primary owner then just remove us from the queue */ + DBusList *link; + BusOwner *temp_owner; + + link = _bus_service_find_owner_link (service, connection); + _dbus_list_unlink (&service->owners, link); + temp_owner = (BusOwner *)link->data; + bus_owner_unref (temp_owner); + _dbus_list_free_link (link); + + return TRUE; + } + + if (service->owners == NULL) + { + _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners"); + } + else if (_dbus_list_length_is_one (&service->owners)) + { + if (!bus_driver_send_service_owner_changed (service->name, + bus_connection_get_name (connection), + NULL, + transaction, error)) + return FALSE; + } + else + { + DBusList *link; + BusOwner *new_owner; + DBusConnection *new_owner_conn; + link = _dbus_list_get_first_link (&service->owners); + _dbus_assert (link != NULL); + link = _dbus_list_get_next_link (&service->owners, link); + _dbus_assert (link != NULL); + + new_owner = (BusOwner *)link->data; + new_owner_conn = new_owner->conn; + + if (!bus_driver_send_service_owner_changed (service->name, + bus_connection_get_name (connection), + bus_connection_get_name (new_owner_conn), + transaction, error)) + return FALSE; + + /* This will be our new owner */ + if (!bus_driver_send_service_acquired (new_owner_conn, + service->name, + transaction, + error)) + return FALSE; + } + + if (!add_restore_ownership_to_transaction (transaction, service, primary_owner)) + { + BUS_SET_OOM (error); + return FALSE; + } + + bus_service_unlink_owner (service, primary_owner); + + if (service->owners == NULL) + bus_service_unlink (service); + + return TRUE; +} + +BusService * +bus_service_ref (BusService *service) +{ + _dbus_assert (service->refcount > 0); + + service->refcount += 1; + + return service; +} + +void +bus_service_unref (BusService *service) +{ + _dbus_assert (service->refcount > 0); + + service->refcount -= 1; + + if (service->refcount == 0) + { + _dbus_assert (service->owners == NULL); + + dbus_free (service->name); + _dbus_mem_pool_dealloc (service->registry->service_pool, service); + } +} + +DBusConnection * +bus_service_get_primary_owners_connection (BusService *service) +{ + BusOwner *owner; + + owner = bus_service_get_primary_owner (service); + + if (owner != NULL) + return owner->conn; + else + return NULL; +} + +BusOwner* +bus_service_get_primary_owner (BusService *service) +{ + return _dbus_list_get_first (&service->owners); +} + +const char* +bus_service_get_name (BusService *service) +{ + return service->name; +} + +dbus_bool_t +bus_service_get_allow_replacement (BusService *service) +{ + BusOwner *owner; + DBusList *link; + + _dbus_assert (service->owners != NULL); + + link = _dbus_list_get_first_link (&service->owners); + owner = (BusOwner *) link->data; + + return owner->allow_replacement; +} + +dbus_bool_t +bus_service_has_owner (BusService *service, + DBusConnection *connection) +{ + DBusList *link; + + link = _bus_service_find_owner_link (service, connection); + + if (link == NULL) + return FALSE; + else + return TRUE; +} + +dbus_bool_t +bus_service_list_queued_owners (BusService *service, + DBusList **return_list, + DBusError *error) +{ + DBusList *link; + + _dbus_assert (*return_list == NULL); + + link = _dbus_list_get_first_link (&service->owners); + _dbus_assert (link != NULL); + + while (link != NULL) + { + BusOwner *owner; + const char *uname; + + owner = (BusOwner *) link->data; + uname = bus_connection_get_name (owner->conn); + + if (!_dbus_list_append (return_list, (char *)uname)) + goto oom; + + link = _dbus_list_get_next_link (&service->owners, link); + } + + return TRUE; + + oom: + _dbus_list_clear (return_list); + BUS_SET_OOM (error); + return FALSE; +} diff --git a/bus/services.h b/bus/services.h new file mode 100644 index 00000000..056dd9fa --- /dev/null +++ b/bus/services.h @@ -0,0 +1,94 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* services.h Service management + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_SERVICES_H +#define BUS_SERVICES_H + +#include +#include +#include +#include "connection.h" +#include "bus.h" + +typedef void (* BusServiceForeachFunction) (BusService *service, + void *data); + +BusRegistry* bus_registry_new (BusContext *context); +BusRegistry* bus_registry_ref (BusRegistry *registry); +void bus_registry_unref (BusRegistry *registry); +BusService* bus_registry_lookup (BusRegistry *registry, + const DBusString *service_name); +BusService* bus_registry_ensure (BusRegistry *registry, + const DBusString *service_name, + DBusConnection *owner_connection_if_created, + dbus_uint32_t flags, + BusTransaction *transaction, + DBusError *error); +void bus_registry_foreach (BusRegistry *registry, + BusServiceForeachFunction function, + void *data); +dbus_bool_t bus_registry_list_services (BusRegistry *registry, + char ***listp, + int *array_len); +dbus_bool_t bus_registry_acquire_service (BusRegistry *registry, + DBusConnection *connection, + const DBusString *service_name, + dbus_uint32_t flags, + dbus_uint32_t *result, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_registry_release_service (BusRegistry *registry, + DBusConnection *connection, + const DBusString *service_name, + dbus_uint32_t *result, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_registry_set_service_context_table (BusRegistry *registry, + DBusHashTable *table); + +BusService* bus_service_ref (BusService *service); +void bus_service_unref (BusService *service); +dbus_bool_t bus_service_add_owner (BusService *service, + DBusConnection *connection, + dbus_uint32_t flags, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_service_swap_owner (BusService *service, + DBusConnection *connection, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_service_remove_owner (BusService *service, + DBusConnection *connection, + BusTransaction *transaction, + DBusError *error); +dbus_bool_t bus_service_has_owner (BusService *service, + DBusConnection *connection); +BusOwner* bus_service_get_primary_owner (BusService *service); +dbus_bool_t bus_service_get_allow_replacement (BusService *service); +const char* bus_service_get_name (BusService *service); +dbus_bool_t bus_service_list_queued_owners (BusService *service, + DBusList **return_list, + DBusError *error); + +DBusConnection* bus_service_get_primary_owners_connection (BusService *service); +#endif /* BUS_SERVICES_H */ diff --git a/bus/session.conf.in b/bus/session.conf.in new file mode 100644 index 00000000..e7229ad5 --- /dev/null +++ b/bus/session.conf.in @@ -0,0 +1,60 @@ + + + + + + session + + + + + unix:tmpdir=@DBUS_SESSION_SOCKET_DIR@ + + + + + + + + + + + + + + session.d + + + session-local.conf + + contexts/dbus_contexts + + + + + 1000000000 + 1000000000 + 1000000000 + 120000 + 240000 + 100000 + 10000 + 100000 + 10000 + 50000 + 50000 + 50000 + + diff --git a/bus/signals.c b/bus/signals.c new file mode 100644 index 00000000..b020a76c --- /dev/null +++ b/bus/signals.c @@ -0,0 +1,2030 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* signals.c Bus signal connection implementation + * + * Copyright (C) 2003, 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "signals.h" +#include "services.h" +#include "utils.h" +#include + +struct BusMatchRule +{ + int refcount; /**< reference count */ + + DBusConnection *matches_go_to; /**< Owner of the rule */ + + unsigned int flags; /**< BusMatchFlags */ + + int message_type; + char *interface; + char *member; + char *sender; + char *destination; + char *path; + + unsigned int *arg_lens; + char **args; + int args_len; +}; + +#define BUS_MATCH_ARG_IS_PATH 0x8000000u + +BusMatchRule* +bus_match_rule_new (DBusConnection *matches_go_to) +{ + BusMatchRule *rule; + + rule = dbus_new0 (BusMatchRule, 1); + if (rule == NULL) + return NULL; + + rule->refcount = 1; + rule->matches_go_to = matches_go_to; + +#ifndef DBUS_BUILD_TESTS + _dbus_assert (rule->matches_go_to != NULL); +#endif + + return rule; +} + +BusMatchRule * +bus_match_rule_ref (BusMatchRule *rule) +{ + _dbus_assert (rule->refcount > 0); + + rule->refcount += 1; + + return rule; +} + +void +bus_match_rule_unref (BusMatchRule *rule) +{ + _dbus_assert (rule->refcount > 0); + + rule->refcount -= 1; + if (rule->refcount == 0) + { + dbus_free (rule->interface); + dbus_free (rule->member); + dbus_free (rule->sender); + dbus_free (rule->destination); + dbus_free (rule->path); + dbus_free (rule->arg_lens); + + /* can't use dbus_free_string_array() since there + * are embedded NULL + */ + if (rule->args) + { + int i; + + i = 0; + while (i < rule->args_len) + { + if (rule->args[i]) + dbus_free (rule->args[i]); + ++i; + } + + dbus_free (rule->args); + } + + dbus_free (rule); + } +} + +#ifdef DBUS_ENABLE_VERBOSE_MODE +/* Note this function does not do escaping, so it's only + * good for debug spew at the moment + */ +static char* +match_rule_to_string (BusMatchRule *rule) +{ + DBusString str; + char *ret; + + if (!_dbus_string_init (&str)) + { + char *s; + while ((s = _dbus_strdup ("nomem")) == NULL) + ; /* only OK for debug spew... */ + return s; + } + + if (rule->flags & BUS_MATCH_MESSAGE_TYPE) + { + /* FIXME make type readable */ + if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type)) + goto nomem; + } + + if (rule->flags & BUS_MATCH_INTERFACE) + { + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface)) + goto nomem; + } + + if (rule->flags & BUS_MATCH_MEMBER) + { + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + if (!_dbus_string_append_printf (&str, "member='%s'", rule->member)) + goto nomem; + } + + if (rule->flags & BUS_MATCH_PATH) + { + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + if (!_dbus_string_append_printf (&str, "path='%s'", rule->path)) + goto nomem; + } + + if (rule->flags & BUS_MATCH_SENDER) + { + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender)) + goto nomem; + } + + if (rule->flags & BUS_MATCH_DESTINATION) + { + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination)) + goto nomem; + } + + if (rule->flags & BUS_MATCH_ARGS) + { + int i; + + _dbus_assert (rule->args != NULL); + + i = 0; + while (i < rule->args_len) + { + if (rule->args[i] != NULL) + { + dbus_bool_t is_path; + + if (_dbus_string_get_length (&str) > 0) + { + if (!_dbus_string_append (&str, ",")) + goto nomem; + } + + is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0; + + if (!_dbus_string_append_printf (&str, + "arg%d%s='%s'", + i, is_path ? "path" : "", + rule->args[i])) + goto nomem; + } + + ++i; + } + } + + if (!_dbus_string_steal_data (&str, &ret)) + goto nomem; + + _dbus_string_free (&str); + return ret; + + nomem: + _dbus_string_free (&str); + { + char *s; + while ((s = _dbus_strdup ("nomem")) == NULL) + ; /* only OK for debug spew... */ + return s; + } +} +#endif /* DBUS_ENABLE_VERBOSE_MODE */ + +dbus_bool_t +bus_match_rule_set_message_type (BusMatchRule *rule, + int type) +{ + rule->flags |= BUS_MATCH_MESSAGE_TYPE; + + rule->message_type = type; + + return TRUE; +} + +dbus_bool_t +bus_match_rule_set_interface (BusMatchRule *rule, + const char *interface) +{ + char *new; + + _dbus_assert (interface != NULL); + + new = _dbus_strdup (interface); + if (new == NULL) + return FALSE; + + rule->flags |= BUS_MATCH_INTERFACE; + dbus_free (rule->interface); + rule->interface = new; + + return TRUE; +} + +dbus_bool_t +bus_match_rule_set_member (BusMatchRule *rule, + const char *member) +{ + char *new; + + _dbus_assert (member != NULL); + + new = _dbus_strdup (member); + if (new == NULL) + return FALSE; + + rule->flags |= BUS_MATCH_MEMBER; + dbus_free (rule->member); + rule->member = new; + + return TRUE; +} + +dbus_bool_t +bus_match_rule_set_sender (BusMatchRule *rule, + const char *sender) +{ + char *new; + + _dbus_assert (sender != NULL); + + new = _dbus_strdup (sender); + if (new == NULL) + return FALSE; + + rule->flags |= BUS_MATCH_SENDER; + dbus_free (rule->sender); + rule->sender = new; + + return TRUE; +} + +dbus_bool_t +bus_match_rule_set_destination (BusMatchRule *rule, + const char *destination) +{ + char *new; + + _dbus_assert (destination != NULL); + + new = _dbus_strdup (destination); + if (new == NULL) + return FALSE; + + rule->flags |= BUS_MATCH_DESTINATION; + dbus_free (rule->destination); + rule->destination = new; + + return TRUE; +} + +dbus_bool_t +bus_match_rule_set_path (BusMatchRule *rule, + const char *path) +{ + char *new; + + _dbus_assert (path != NULL); + + new = _dbus_strdup (path); + if (new == NULL) + return FALSE; + + rule->flags |= BUS_MATCH_PATH; + dbus_free (rule->path); + rule->path = new; + + return TRUE; +} + +dbus_bool_t +bus_match_rule_set_arg (BusMatchRule *rule, + int arg, + const DBusString *value, + dbus_bool_t is_path) +{ + int length; + char *new; + + _dbus_assert (value != NULL); + + /* args_len is the number of args not including null termination + * in the char** + */ + if (arg >= rule->args_len) + { + unsigned int *new_arg_lens; + char **new_args; + int new_args_len; + int i; + + new_args_len = arg + 1; + + /* add another + 1 here for null termination */ + new_args = dbus_realloc (rule->args, + sizeof (char *) * (new_args_len + 1)); + if (new_args == NULL) + return FALSE; + + /* NULL the new slots */ + i = rule->args_len; + while (i <= new_args_len) /* <= for null termination */ + { + new_args[i] = NULL; + ++i; + } + + rule->args = new_args; + + /* and now add to the lengths */ + new_arg_lens = dbus_realloc (rule->arg_lens, + sizeof (int) * (new_args_len + 1)); + + if (new_arg_lens == NULL) + return FALSE; + + /* zero the new slots */ + i = rule->args_len; + while (i <= new_args_len) /* <= for null termination */ + { + new_arg_lens[i] = 0; + ++i; + } + + rule->arg_lens = new_arg_lens; + rule->args_len = new_args_len; + } + + length = _dbus_string_get_length (value); + if (!_dbus_string_copy_data (value, &new)) + return FALSE; + + rule->flags |= BUS_MATCH_ARGS; + + dbus_free (rule->args[arg]); + rule->arg_lens[arg] = length; + rule->args[arg] = new; + + if (is_path) + rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH; + + /* NULL termination didn't get busted */ + _dbus_assert (rule->args[rule->args_len] == NULL); + _dbus_assert (rule->arg_lens[rule->args_len] == 0); + + return TRUE; +} + +#define ISWHITE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r')) + +static dbus_bool_t +find_key (const DBusString *str, + int start, + DBusString *key, + int *value_pos, + DBusError *error) +{ + const char *p; + const char *s; + const char *key_start; + const char *key_end; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + s = _dbus_string_get_const_data (str); + + p = s + start; + + while (*p && ISWHITE (*p)) + ++p; + + key_start = p; + + while (*p && *p != '=' && !ISWHITE (*p)) + ++p; + + key_end = p; + + while (*p && ISWHITE (*p)) + ++p; + + if (key_start == key_end) + { + /* Empty match rules or trailing whitespace are OK */ + *value_pos = p - s; + return TRUE; + } + + if (*p != '=') + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Match rule has a key with no subsequent '=' character"); + return FALSE; + } + ++p; + + if (!_dbus_string_append_len (key, key_start, key_end - key_start)) + { + BUS_SET_OOM (error); + return FALSE; + } + + *value_pos = p - s; + + return TRUE; +} + +static dbus_bool_t +find_value (const DBusString *str, + int start, + const char *key, + DBusString *value, + int *value_end, + DBusError *error) +{ + const char *p; + const char *s; + char quote_char; + int orig_len; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + orig_len = _dbus_string_get_length (value); + + s = _dbus_string_get_const_data (str); + + p = s + start; + + quote_char = '\0'; + + while (*p) + { + if (quote_char == '\0') + { + switch (*p) + { + case '\0': + goto done; + + case '\'': + quote_char = '\''; + goto next; + + case ',': + ++p; + goto done; + + case '\\': + quote_char = '\\'; + goto next; + + default: + if (!_dbus_string_append_byte (value, *p)) + { + BUS_SET_OOM (error); + goto failed; + } + } + } + else if (quote_char == '\\') + { + /* \ only counts as an escape if escaping a quote mark */ + if (*p != '\'') + { + if (!_dbus_string_append_byte (value, '\\')) + { + BUS_SET_OOM (error); + goto failed; + } + } + + if (!_dbus_string_append_byte (value, *p)) + { + BUS_SET_OOM (error); + goto failed; + } + + quote_char = '\0'; + } + else + { + _dbus_assert (quote_char == '\''); + + if (*p == '\'') + { + quote_char = '\0'; + } + else + { + if (!_dbus_string_append_byte (value, *p)) + { + BUS_SET_OOM (error); + goto failed; + } + } + } + + next: + ++p; + } + + done: + + if (quote_char == '\\') + { + if (!_dbus_string_append_byte (value, '\\')) + { + BUS_SET_OOM (error); + goto failed; + } + } + else if (quote_char == '\'') + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Unbalanced quotation marks in match rule"); + goto failed; + } + else + _dbus_assert (quote_char == '\0'); + + /* Zero-length values are allowed */ + + *value_end = p - s; + + return TRUE; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_string_set_length (value, orig_len); + return FALSE; +} + +/* duplicates aren't allowed so the real legitimate max is only 6 or + * so. Leaving extra so we don't have to bother to update it. + * FIXME this is sort of busted now with arg matching, but we let + * you match on up to 10 args for now + */ +#define MAX_RULE_TOKENS 16 + +/* this is slightly too high level to be termed a "token" + * but let's not be pedantic. + */ +typedef struct +{ + char *key; + char *value; +} RuleToken; + +static dbus_bool_t +tokenize_rule (const DBusString *rule_text, + RuleToken tokens[MAX_RULE_TOKENS], + DBusError *error) +{ + int i; + int pos; + DBusString key; + DBusString value; + dbus_bool_t retval; + + retval = FALSE; + + if (!_dbus_string_init (&key)) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_init (&value)) + { + _dbus_string_free (&key); + BUS_SET_OOM (error); + return FALSE; + } + + i = 0; + pos = 0; + while (i < MAX_RULE_TOKENS && + pos < _dbus_string_get_length (rule_text)) + { + _dbus_assert (tokens[i].key == NULL); + _dbus_assert (tokens[i].value == NULL); + + if (!find_key (rule_text, pos, &key, &pos, error)) + goto out; + + if (_dbus_string_get_length (&key) == 0) + goto next; + + if (!_dbus_string_steal_data (&key, &tokens[i].key)) + { + BUS_SET_OOM (error); + goto out; + } + + if (!find_value (rule_text, pos, tokens[i].key, &value, &pos, error)) + goto out; + + if (!_dbus_string_steal_data (&value, &tokens[i].value)) + { + BUS_SET_OOM (error); + goto out; + } + + next: + ++i; + } + + retval = TRUE; + + out: + if (!retval) + { + i = 0; + while (tokens[i].key || tokens[i].value) + { + dbus_free (tokens[i].key); + dbus_free (tokens[i].value); + tokens[i].key = NULL; + tokens[i].value = NULL; + ++i; + } + } + + _dbus_string_free (&key); + _dbus_string_free (&value); + + return retval; +} + +static dbus_bool_t +bus_match_rule_parse_arg_match (BusMatchRule *rule, + const char *key, + const DBusString *value, + DBusError *error) +{ + dbus_bool_t is_path; + DBusString key_str; + unsigned long arg; + int length; + int end; + + /* For now, arg0='foo' always implies that 'foo' is a + * DBUS_TYPE_STRING. Someday we could add an arg0type='int32' thing + * if we wanted, which would specify another type, in which case + * arg0='5' would have the 5 parsed as an int rather than string. + */ + + /* First we need to parse arg0 = 0, arg27 = 27 */ + + _dbus_string_init_const (&key_str, key); + length = _dbus_string_get_length (&key_str); + + if (_dbus_string_get_length (&key_str) < 4) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key '%s' in match rule starts with 'arg' but lacks an arg number. Should be 'arg0' or 'arg7' for example.\n", key); + goto failed; + } + + if (!_dbus_string_parse_uint (&key_str, 3, &arg, &end)) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key '%s' in match rule starts with 'arg' but could not parse arg number. Should be 'arg0' or 'arg7' for example.\n", key); + goto failed; + } + + if (end != length && + ((end + 4) != length || + !_dbus_string_ends_with_c_str (&key_str, "path"))) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key '%s' in match rule contains junk after argument number. Only 'path' is optionally valid ('arg0path' for example).\n", key); + goto failed; + } + + is_path = end != length; + + /* If we didn't check this we could allocate a huge amount of RAM */ + if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key '%s' in match rule has arg number %lu but the maximum is %d.\n", key, (unsigned long) arg, DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER); + goto failed; + } + + if ((rule->flags & BUS_MATCH_ARGS) && + rule->args_len > (int) arg && + rule->args[arg] != NULL) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Argument %d matched more than once in match rule\n", key); + goto failed; + } + + if (!bus_match_rule_set_arg (rule, arg, value, is_path)) + { + BUS_SET_OOM (error); + goto failed; + } + + return TRUE; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + return FALSE; +} + +/* + * The format is comma-separated with strings quoted with single quotes + * as for the shell (to escape a literal single quote, use '\''). + * + * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo', + * path='/bar/foo',destination=':452345.34' + * + */ +BusMatchRule* +bus_match_rule_parse (DBusConnection *matches_go_to, + const DBusString *rule_text, + DBusError *error) +{ + BusMatchRule *rule; + RuleToken tokens[MAX_RULE_TOKENS+1]; /* NULL termination + 1 */ + int i; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (_dbus_string_get_length (rule_text) > DBUS_MAXIMUM_MATCH_RULE_LENGTH) + { + dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED, + "Match rule text is %d bytes, maximum is %d", + _dbus_string_get_length (rule_text), + DBUS_MAXIMUM_MATCH_RULE_LENGTH); + return NULL; + } + + memset (tokens, '\0', sizeof (tokens)); + + rule = bus_match_rule_new (matches_go_to); + if (rule == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!tokenize_rule (rule_text, tokens, error)) + goto failed; + + i = 0; + while (tokens[i].key != NULL) + { + DBusString tmp_str; + int len; + const char *key = tokens[i].key; + const char *value = tokens[i].value; + + _dbus_string_init_const (&tmp_str, value); + len = _dbus_string_get_length (&tmp_str); + + if (strcmp (key, "type") == 0) + { + int t; + + if (rule->flags & BUS_MATCH_MESSAGE_TYPE) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key %s specified twice in match rule\n", key); + goto failed; + } + + t = dbus_message_type_from_string (value); + + if (t == DBUS_MESSAGE_TYPE_INVALID) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Invalid message type (%s) in match rule\n", value); + goto failed; + } + + if (!bus_match_rule_set_message_type (rule, t)) + { + BUS_SET_OOM (error); + goto failed; + } + } + else if (strcmp (key, "sender") == 0) + { + if (rule->flags & BUS_MATCH_SENDER) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key %s specified twice in match rule\n", key); + goto failed; + } + + if (!_dbus_validate_bus_name (&tmp_str, 0, len)) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Sender name '%s' is invalid\n", value); + goto failed; + } + + if (!bus_match_rule_set_sender (rule, value)) + { + BUS_SET_OOM (error); + goto failed; + } + } + else if (strcmp (key, "interface") == 0) + { + if (rule->flags & BUS_MATCH_INTERFACE) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key %s specified twice in match rule\n", key); + goto failed; + } + + if (!_dbus_validate_interface (&tmp_str, 0, len)) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Interface name '%s' is invalid\n", value); + goto failed; + } + + if (!bus_match_rule_set_interface (rule, value)) + { + BUS_SET_OOM (error); + goto failed; + } + } + else if (strcmp (key, "member") == 0) + { + if (rule->flags & BUS_MATCH_MEMBER) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key %s specified twice in match rule\n", key); + goto failed; + } + + if (!_dbus_validate_member (&tmp_str, 0, len)) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Member name '%s' is invalid\n", value); + goto failed; + } + + if (!bus_match_rule_set_member (rule, value)) + { + BUS_SET_OOM (error); + goto failed; + } + } + else if (strcmp (key, "path") == 0) + { + if (rule->flags & BUS_MATCH_PATH) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key %s specified twice in match rule\n", key); + goto failed; + } + + if (!_dbus_validate_path (&tmp_str, 0, len)) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Path '%s' is invalid\n", value); + goto failed; + } + + if (!bus_match_rule_set_path (rule, value)) + { + BUS_SET_OOM (error); + goto failed; + } + } + else if (strcmp (key, "destination") == 0) + { + if (rule->flags & BUS_MATCH_DESTINATION) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Key %s specified twice in match rule\n", key); + goto failed; + } + + if (!_dbus_validate_bus_name (&tmp_str, 0, len)) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Destination name '%s' is invalid\n", value); + goto failed; + } + + if (!bus_match_rule_set_destination (rule, value)) + { + BUS_SET_OOM (error); + goto failed; + } + } + else if (strncmp (key, "arg", 3) == 0) + { + if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error)) + goto failed; + } + else + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID, + "Unknown key \"%s\" in match rule", + key); + goto failed; + } + + ++i; + } + + + goto out; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + if (rule) + { + bus_match_rule_unref (rule); + rule = NULL; + } + + out: + + i = 0; + while (tokens[i].key || tokens[i].value) + { + _dbus_assert (i < MAX_RULE_TOKENS); + dbus_free (tokens[i].key); + dbus_free (tokens[i].value); + ++i; + } + + return rule; +} + +struct BusMatchmaker +{ + int refcount; + + DBusList *all_rules; +}; + +BusMatchmaker* +bus_matchmaker_new (void) +{ + BusMatchmaker *matchmaker; + + matchmaker = dbus_new0 (BusMatchmaker, 1); + if (matchmaker == NULL) + return NULL; + + matchmaker->refcount = 1; + + return matchmaker; +} + +BusMatchmaker * +bus_matchmaker_ref (BusMatchmaker *matchmaker) +{ + _dbus_assert (matchmaker->refcount > 0); + + matchmaker->refcount += 1; + + return matchmaker; +} + +void +bus_matchmaker_unref (BusMatchmaker *matchmaker) +{ + _dbus_assert (matchmaker->refcount > 0); + + matchmaker->refcount -= 1; + if (matchmaker->refcount == 0) + { + while (matchmaker->all_rules != NULL) + { + BusMatchRule *rule; + + rule = matchmaker->all_rules->data; + bus_match_rule_unref (rule); + _dbus_list_remove_link (&matchmaker->all_rules, + matchmaker->all_rules); + } + + dbus_free (matchmaker); + } +} + +/* The rule can't be modified after it's added. */ +dbus_bool_t +bus_matchmaker_add_rule (BusMatchmaker *matchmaker, + BusMatchRule *rule) +{ + _dbus_assert (bus_connection_is_active (rule->matches_go_to)); + + if (!_dbus_list_append (&matchmaker->all_rules, rule)) + return FALSE; + + if (!bus_connection_add_match_rule (rule->matches_go_to, rule)) + { + _dbus_list_remove_last (&matchmaker->all_rules, rule); + return FALSE; + } + + bus_match_rule_ref (rule); + +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + char *s = match_rule_to_string (rule); + + _dbus_verbose ("Added match rule %s to connection %p\n", + s, rule->matches_go_to); + dbus_free (s); + } +#endif + + return TRUE; +} + +static dbus_bool_t +match_rule_equal (BusMatchRule *a, + BusMatchRule *b) +{ + if (a->flags != b->flags) + return FALSE; + + if (a->matches_go_to != b->matches_go_to) + return FALSE; + + if ((a->flags & BUS_MATCH_MESSAGE_TYPE) && + a->message_type != b->message_type) + return FALSE; + + if ((a->flags & BUS_MATCH_MEMBER) && + strcmp (a->member, b->member) != 0) + return FALSE; + + if ((a->flags & BUS_MATCH_PATH) && + strcmp (a->path, b->path) != 0) + return FALSE; + + if ((a->flags & BUS_MATCH_INTERFACE) && + strcmp (a->interface, b->interface) != 0) + return FALSE; + + if ((a->flags & BUS_MATCH_SENDER) && + strcmp (a->sender, b->sender) != 0) + return FALSE; + + if ((a->flags & BUS_MATCH_DESTINATION) && + strcmp (a->destination, b->destination) != 0) + return FALSE; + + if (a->flags & BUS_MATCH_ARGS) + { + int i; + + if (a->args_len != b->args_len) + return FALSE; + + i = 0; + while (i < a->args_len) + { + int length; + + if ((a->args[i] != NULL) != (b->args[i] != NULL)) + return FALSE; + + if (a->arg_lens[i] != b->arg_lens[i]) + return FALSE; + + length = a->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH; + + if (a->args[i] != NULL) + { + _dbus_assert (b->args[i] != NULL); + if (memcmp (a->args[i], b->args[i], length) != 0) + return FALSE; + } + + ++i; + } + } + + return TRUE; +} + +static void +bus_matchmaker_remove_rule_link (BusMatchmaker *matchmaker, + DBusList *link) +{ + BusMatchRule *rule = link->data; + + bus_connection_remove_match_rule (rule->matches_go_to, rule); + _dbus_list_remove_link (&matchmaker->all_rules, link); + +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + char *s = match_rule_to_string (rule); + + _dbus_verbose ("Removed match rule %s for connection %p\n", + s, rule->matches_go_to); + dbus_free (s); + } +#endif + + bus_match_rule_unref (rule); +} + +void +bus_matchmaker_remove_rule (BusMatchmaker *matchmaker, + BusMatchRule *rule) +{ + bus_connection_remove_match_rule (rule->matches_go_to, rule); + _dbus_list_remove (&matchmaker->all_rules, rule); + +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + char *s = match_rule_to_string (rule); + + _dbus_verbose ("Removed match rule %s for connection %p\n", + s, rule->matches_go_to); + dbus_free (s); + } +#endif + + bus_match_rule_unref (rule); +} + +/* Remove a single rule which is equal to the given rule by value */ +dbus_bool_t +bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker, + BusMatchRule *value, + DBusError *error) +{ + /* FIXME this is an unoptimized linear scan */ + + DBusList *link; + + /* we traverse backward because bus_connection_remove_match_rule() + * removes the most-recently-added rule + */ + link = _dbus_list_get_last_link (&matchmaker->all_rules); + while (link != NULL) + { + BusMatchRule *rule; + DBusList *prev; + + rule = link->data; + prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link); + + if (match_rule_equal (rule, value)) + { + bus_matchmaker_remove_rule_link (matchmaker, link); + break; + } + + link = prev; + } + + if (link == NULL) + { + dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND, + "The given match rule wasn't found and can't be removed"); + return FALSE; + } + + return TRUE; +} + +void +bus_matchmaker_disconnected (BusMatchmaker *matchmaker, + DBusConnection *disconnected) +{ + DBusList *link; + + /* FIXME + * + * This scans all match rules on the bus. We could avoid that + * for the rules belonging to the connection, since we keep + * a list of those; but for the rules that just refer to + * the connection we'd need to do something more elaborate. + * + */ + + _dbus_assert (bus_connection_is_active (disconnected)); + + link = _dbus_list_get_first_link (&matchmaker->all_rules); + while (link != NULL) + { + BusMatchRule *rule; + DBusList *next; + + rule = link->data; + next = _dbus_list_get_next_link (&matchmaker->all_rules, link); + + if (rule->matches_go_to == disconnected) + { + bus_matchmaker_remove_rule_link (matchmaker, link); + } + else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') || + ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':')) + { + /* The rule matches to/from a base service, see if it's the + * one being disconnected, since we know this service name + * will never be recycled. + */ + const char *name; + + name = bus_connection_get_name (disconnected); + _dbus_assert (name != NULL); /* because we're an active connection */ + + if (((rule->flags & BUS_MATCH_SENDER) && + strcmp (rule->sender, name) == 0) || + ((rule->flags & BUS_MATCH_DESTINATION) && + strcmp (rule->destination, name) == 0)) + { + bus_matchmaker_remove_rule_link (matchmaker, link); + } + } + + link = next; + } +} + +static dbus_bool_t +connection_is_primary_owner (DBusConnection *connection, + const char *service_name) +{ + BusService *service; + DBusString str; + BusRegistry *registry; + + _dbus_assert (connection != NULL); + + registry = bus_connection_get_registry (connection); + + _dbus_string_init_const (&str, service_name); + service = bus_registry_lookup (registry, &str); + + if (service == NULL) + return FALSE; /* Service doesn't exist so connection can't own it. */ + + return bus_service_get_primary_owners_connection (service) == connection; +} + +static dbus_bool_t +match_rule_matches (BusMatchRule *rule, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusMessage *message) +{ + /* All features of the match rule are AND'd together, + * so FALSE if any of them don't match. + */ + + /* sender/addressed_recipient of #NULL may mean bus driver, + * or for addressed_recipient may mean a message with no + * specific recipient (i.e. a signal) + */ + + if (rule->flags & BUS_MATCH_MESSAGE_TYPE) + { + _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID); + + if (rule->message_type != dbus_message_get_type (message)) + return FALSE; + } + + if (rule->flags & BUS_MATCH_INTERFACE) + { + const char *iface; + + _dbus_assert (rule->interface != NULL); + + iface = dbus_message_get_interface (message); + if (iface == NULL) + return FALSE; + + if (strcmp (iface, rule->interface) != 0) + return FALSE; + } + + if (rule->flags & BUS_MATCH_MEMBER) + { + const char *member; + + _dbus_assert (rule->member != NULL); + + member = dbus_message_get_member (message); + if (member == NULL) + return FALSE; + + if (strcmp (member, rule->member) != 0) + return FALSE; + } + + if (rule->flags & BUS_MATCH_SENDER) + { + _dbus_assert (rule->sender != NULL); + + if (sender == NULL) + { + if (strcmp (rule->sender, + DBUS_SERVICE_DBUS) != 0) + return FALSE; + } + else + { + if (!connection_is_primary_owner (sender, rule->sender)) + return FALSE; + } + } + + if (rule->flags & BUS_MATCH_DESTINATION) + { + const char *destination; + + _dbus_assert (rule->destination != NULL); + + destination = dbus_message_get_destination (message); + if (destination == NULL) + return FALSE; + + if (addressed_recipient == NULL) + { + if (strcmp (rule->destination, + DBUS_SERVICE_DBUS) != 0) + return FALSE; + } + else + { + if (!connection_is_primary_owner (addressed_recipient, rule->destination)) + return FALSE; + } + } + + if (rule->flags & BUS_MATCH_PATH) + { + const char *path; + + _dbus_assert (rule->path != NULL); + + path = dbus_message_get_path (message); + if (path == NULL) + return FALSE; + + if (strcmp (path, rule->path) != 0) + return FALSE; + } + + if (rule->flags & BUS_MATCH_ARGS) + { + int i; + DBusMessageIter iter; + + _dbus_assert (rule->args != NULL); + + dbus_message_iter_init (message, &iter); + + i = 0; + while (i < rule->args_len) + { + int current_type; + const char *expected_arg; + int expected_length; + dbus_bool_t is_path; + + expected_arg = rule->args[i]; + expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH; + is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0; + + current_type = dbus_message_iter_get_arg_type (&iter); + + if (expected_arg != NULL) + { + const char *actual_arg; + int actual_length; + + if (current_type != DBUS_TYPE_STRING) + return FALSE; + + actual_arg = NULL; + dbus_message_iter_get_basic (&iter, &actual_arg); + _dbus_assert (actual_arg != NULL); + + actual_length = strlen (actual_arg); + + if (is_path) + { + if (actual_length < expected_length && + actual_arg[actual_length - 1] != '/') + return FALSE; + + if (expected_length < actual_length && + expected_arg[expected_length - 1] != '/') + return FALSE; + + if (memcmp (actual_arg, expected_arg, + MIN (actual_length, expected_length)) != 0) + return FALSE; + } + else + { + if (expected_length != actual_length || + memcmp (expected_arg, actual_arg, expected_length) != 0) + return FALSE; + } + + } + + if (current_type != DBUS_TYPE_INVALID) + dbus_message_iter_next (&iter); + + ++i; + } + } + + return TRUE; +} + +dbus_bool_t +bus_matchmaker_get_recipients (BusMatchmaker *matchmaker, + BusConnections *connections, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusMessage *message, + DBusList **recipients_p) +{ + /* FIXME for now this is a wholly unoptimized linear search */ + /* Guessing the important optimization is to skip the signal-related + * match lists when processing method call and exception messages. + * So separate match rule lists for signals? + */ + + DBusList *link; + + _dbus_assert (*recipients_p == NULL); + + /* This avoids sending same message to the same connection twice. + * Purpose of the stamp instead of a bool is to avoid iterating over + * all connections resetting the bool each time. + */ + bus_connections_increment_stamp (connections); + + /* addressed_recipient is already receiving the message, don't add to list. + * NULL addressed_recipient means either bus driver, or this is a signal + * and thus lacks a specific addressed_recipient. + */ + if (addressed_recipient != NULL) + bus_connection_mark_stamp (addressed_recipient); + + link = _dbus_list_get_first_link (&matchmaker->all_rules); + while (link != NULL) + { + BusMatchRule *rule; + + rule = link->data; + +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + char *s = match_rule_to_string (rule); + + _dbus_verbose ("Checking whether message matches rule %s for connection %p\n", + s, rule->matches_go_to); + dbus_free (s); + } +#endif + + if (match_rule_matches (rule, + sender, addressed_recipient, message)) + { + _dbus_verbose ("Rule matched\n"); + + /* Append to the list if we haven't already */ + if (bus_connection_mark_stamp (rule->matches_go_to)) + { + if (!_dbus_list_append (recipients_p, rule->matches_go_to)) + goto nomem; + } +#ifdef DBUS_ENABLE_VERBOSE_MODE + else + { + _dbus_verbose ("Connection already receiving this message, so not adding again\n"); + } +#endif /* DBUS_ENABLE_VERBOSE_MODE */ + } + + link = _dbus_list_get_next_link (&matchmaker->all_rules, link); + } + + return TRUE; + + nomem: + _dbus_list_clear (recipients_p); + return FALSE; +} + +#ifdef DBUS_BUILD_TESTS +#include "test.h" +#include + +static BusMatchRule* +check_parse (dbus_bool_t should_succeed, + const char *text) +{ + BusMatchRule *rule; + DBusString str; + DBusError error; + + dbus_error_init (&error); + + _dbus_string_init_const (&str, text); + + rule = bus_match_rule_parse (NULL, &str, &error); + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + dbus_error_free (&error); + return NULL; + } + + if (should_succeed && rule == NULL) + { + _dbus_warn ("Failed to parse: %s: %s: \"%s\"\n", + error.name, error.message, + _dbus_string_get_const_data (&str)); + exit (1); + } + + if (!should_succeed && rule != NULL) + { + _dbus_warn ("Failed to fail to parse: \"%s\"\n", + _dbus_string_get_const_data (&str)); + exit (1); + } + + dbus_error_free (&error); + + return rule; +} + +static void +assert_large_rule (BusMatchRule *rule) +{ + _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE); + _dbus_assert (rule->flags & BUS_MATCH_SENDER); + _dbus_assert (rule->flags & BUS_MATCH_INTERFACE); + _dbus_assert (rule->flags & BUS_MATCH_MEMBER); + _dbus_assert (rule->flags & BUS_MATCH_DESTINATION); + _dbus_assert (rule->flags & BUS_MATCH_PATH); + + _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL); + _dbus_assert (rule->interface != NULL); + _dbus_assert (rule->member != NULL); + _dbus_assert (rule->sender != NULL); + _dbus_assert (rule->destination != NULL); + _dbus_assert (rule->path != NULL); + + _dbus_assert (strcmp (rule->interface, "org.freedesktop.DBusInterface") == 0); + _dbus_assert (strcmp (rule->sender, "org.freedesktop.DBusSender") == 0); + _dbus_assert (strcmp (rule->member, "Foo") == 0); + _dbus_assert (strcmp (rule->path, "/bar/foo") == 0); + _dbus_assert (strcmp (rule->destination, ":452345.34") == 0); +} + +static dbus_bool_t +test_parsing (void *data) +{ + BusMatchRule *rule; + + rule = check_parse (TRUE, "type='signal',sender='org.freedesktop.DBusSender',interface='org.freedesktop.DBusInterface',member='Foo',path='/bar/foo',destination=':452345.34'"); + if (rule != NULL) + { + assert_large_rule (rule); + bus_match_rule_unref (rule); + } + + /* With extra whitespace and useless quotes */ + rule = check_parse (TRUE, " type='signal', \tsender='org.freedes''ktop.DBusSender', interface='org.freedesktop.DBusInterface''''', \tmember='Foo',path='/bar/foo',destination=':452345.34'''''"); + if (rule != NULL) + { + assert_large_rule (rule); + bus_match_rule_unref (rule); + } + + + /* A simple signal connection */ + rule = check_parse (TRUE, "type='signal',path='/foo',interface='org.Bar'"); + if (rule != NULL) + { + _dbus_assert (rule->flags & BUS_MATCH_MESSAGE_TYPE); + _dbus_assert (rule->flags & BUS_MATCH_INTERFACE); + _dbus_assert (rule->flags & BUS_MATCH_PATH); + + _dbus_assert (rule->message_type == DBUS_MESSAGE_TYPE_SIGNAL); + _dbus_assert (rule->interface != NULL); + _dbus_assert (rule->path != NULL); + + _dbus_assert (strcmp (rule->interface, "org.Bar") == 0); + _dbus_assert (strcmp (rule->path, "/foo") == 0); + + bus_match_rule_unref (rule); + } + + /* argN */ + rule = check_parse (TRUE, "arg0='foo'"); + if (rule != NULL) + { + _dbus_assert (rule->flags == BUS_MATCH_ARGS); + _dbus_assert (rule->args != NULL); + _dbus_assert (rule->args_len == 1); + _dbus_assert (rule->args[0] != NULL); + _dbus_assert (rule->args[1] == NULL); + _dbus_assert (strcmp (rule->args[0], "foo") == 0); + + bus_match_rule_unref (rule); + } + + rule = check_parse (TRUE, "arg1='foo'"); + if (rule != NULL) + { + _dbus_assert (rule->flags == BUS_MATCH_ARGS); + _dbus_assert (rule->args != NULL); + _dbus_assert (rule->args_len == 2); + _dbus_assert (rule->args[0] == NULL); + _dbus_assert (rule->args[1] != NULL); + _dbus_assert (rule->args[2] == NULL); + _dbus_assert (strcmp (rule->args[1], "foo") == 0); + + bus_match_rule_unref (rule); + } + + rule = check_parse (TRUE, "arg2='foo'"); + if (rule != NULL) + { + _dbus_assert (rule->flags == BUS_MATCH_ARGS); + _dbus_assert (rule->args != NULL); + _dbus_assert (rule->args_len == 3); + _dbus_assert (rule->args[0] == NULL); + _dbus_assert (rule->args[1] == NULL); + _dbus_assert (rule->args[2] != NULL); + _dbus_assert (rule->args[3] == NULL); + _dbus_assert (strcmp (rule->args[2], "foo") == 0); + + bus_match_rule_unref (rule); + } + + rule = check_parse (TRUE, "arg40='foo'"); + if (rule != NULL) + { + _dbus_assert (rule->flags == BUS_MATCH_ARGS); + _dbus_assert (rule->args != NULL); + _dbus_assert (rule->args_len == 41); + _dbus_assert (rule->args[0] == NULL); + _dbus_assert (rule->args[1] == NULL); + _dbus_assert (rule->args[40] != NULL); + _dbus_assert (rule->args[41] == NULL); + _dbus_assert (strcmp (rule->args[40], "foo") == 0); + + bus_match_rule_unref (rule); + } + + rule = check_parse (TRUE, "arg63='foo'"); + if (rule != NULL) + { + _dbus_assert (rule->flags == BUS_MATCH_ARGS); + _dbus_assert (rule->args != NULL); + _dbus_assert (rule->args_len == 64); + _dbus_assert (rule->args[0] == NULL); + _dbus_assert (rule->args[1] == NULL); + _dbus_assert (rule->args[63] != NULL); + _dbus_assert (rule->args[64] == NULL); + _dbus_assert (strcmp (rule->args[63], "foo") == 0); + + bus_match_rule_unref (rule); + } + + /* Too-large argN */ + rule = check_parse (FALSE, "arg300='foo'"); + _dbus_assert (rule == NULL); + rule = check_parse (FALSE, "arg64='foo'"); + _dbus_assert (rule == NULL); + + /* No N in argN */ + rule = check_parse (FALSE, "arg='foo'"); + _dbus_assert (rule == NULL); + rule = check_parse (FALSE, "argv='foo'"); + _dbus_assert (rule == NULL); + rule = check_parse (FALSE, "arg3junk='foo'"); + _dbus_assert (rule == NULL); + rule = check_parse (FALSE, "argument='foo'"); + _dbus_assert (rule == NULL); + + /* Reject duplicates */ + rule = check_parse (FALSE, "type='signal',type='method_call'"); + _dbus_assert (rule == NULL); + + /* Duplicates with the argN code */ + rule = check_parse (FALSE, "arg0='foo',arg0='bar'"); + _dbus_assert (rule == NULL); + rule = check_parse (FALSE, "arg3='foo',arg3='bar'"); + _dbus_assert (rule == NULL); + rule = check_parse (FALSE, "arg30='foo',arg30='bar'"); + _dbus_assert (rule == NULL); + + /* Reject broken keys */ + rule = check_parse (FALSE, "blah='signal'"); + _dbus_assert (rule == NULL); + + /* Reject broken values */ + rule = check_parse (FALSE, "type='chouin'"); + _dbus_assert (rule == NULL); + rule = check_parse (FALSE, "interface='abc@def++'"); + _dbus_assert (rule == NULL); + rule = check_parse (FALSE, "service='youpi'"); + _dbus_assert (rule == NULL); + + /* Allow empty rule */ + rule = check_parse (TRUE, ""); + if (rule != NULL) + { + _dbus_assert (rule->flags == 0); + + bus_match_rule_unref (rule); + } + + /* All-whitespace rule is the same as empty */ + rule = check_parse (TRUE, " \t"); + if (rule != NULL) + { + _dbus_assert (rule->flags == 0); + + bus_match_rule_unref (rule); + } + + /* But with non-whitespace chars and no =value, it's not OK */ + rule = check_parse (FALSE, "type"); + _dbus_assert (rule == NULL); + + return TRUE; +} + +static struct { + const char *first; + const char *second; +} equality_tests[] = { + { "type='signal'", "type='signal'" }, + { "type='signal',interface='foo.bar'", "interface='foo.bar',type='signal'" }, + { "type='signal',member='bar'", "member='bar',type='signal'" }, + { "type='method_call',sender=':1.0'", "sender=':1.0',type='method_call'" }, + { "type='method_call',destination=':1.0'", "destination=':1.0',type='method_call'" }, + { "type='method_call',path='/foo/bar'", "path='/foo/bar',type='method_call'" }, + { "type='method_call',arg0='blah'", "arg0='blah',type='method_call'" }, + { "type='method_call',arg0='boo'", "arg0='boo',type='method_call'" }, + { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" }, + { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" }, + { "arg3='fool'", "arg3='fool'" }, + { "member='food'", "member='food'" } +}; + +static void +test_equality (void) +{ + int i; + + i = 0; + while (i < _DBUS_N_ELEMENTS (equality_tests)) + { + BusMatchRule *first; + BusMatchRule *second; + int j; + + first = check_parse (TRUE, equality_tests[i].first); + _dbus_assert (first != NULL); + second = check_parse (TRUE, equality_tests[i].second); + _dbus_assert (second != NULL); + + if (!match_rule_equal (first, second)) + { + _dbus_warn ("rule %s and %s should have been equal\n", + equality_tests[i].first, + equality_tests[i].second); + exit (1); + } + + bus_match_rule_unref (second); + + /* Check that the rule is not equal to any of the + * others besides its pair match + */ + j = 0; + while (j < _DBUS_N_ELEMENTS (equality_tests)) + { + if (i != j) + { + second = check_parse (TRUE, equality_tests[j].second); + + if (match_rule_equal (first, second)) + { + _dbus_warn ("rule %s and %s should not have been equal\n", + equality_tests[i].first, + equality_tests[j].second); + exit (1); + } + + bus_match_rule_unref (second); + } + + ++j; + } + + bus_match_rule_unref (first); + + ++i; + } +} + +static const char* +should_match_message_1[] = { + "type='signal'", + "member='Frobated'", + "arg0='foobar'", + "type='signal',member='Frobated'", + "type='signal',member='Frobated',arg0='foobar'", + "member='Frobated',arg0='foobar'", + "type='signal',arg0='foobar'", + NULL +}; + +static const char* +should_not_match_message_1[] = { + "type='method_call'", + "type='error'", + "type='method_return'", + "type='signal',member='Oopsed'", + "arg0='blah'", + "arg1='foobar'", + "arg2='foobar'", + "arg3='foobar'", + "arg0='3'", + "arg1='3'", + "arg0='foobar',arg1='abcdef'", + "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'", + "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'", + NULL +}; + +static void +check_matches (dbus_bool_t expected_to_match, + int number, + DBusMessage *message, + const char *rule_text) +{ + BusMatchRule *rule; + dbus_bool_t matched; + + rule = check_parse (TRUE, rule_text); + _dbus_assert (rule != NULL); + + /* We can't test sender/destination rules since we pass NULL here */ + matched = match_rule_matches (rule, NULL, NULL, message); + + if (matched != expected_to_match) + { + _dbus_warn ("Expected rule %s to %s message %d, failed\n", + rule_text, expected_to_match ? + "match" : "not match", number); + exit (1); + } + + bus_match_rule_unref (rule); +} + +static void +check_matching (DBusMessage *message, + int number, + const char **should_match, + const char **should_not_match) +{ + int i; + + i = 0; + while (should_match[i] != NULL) + { + check_matches (TRUE, number, message, should_match[i]); + ++i; + } + + i = 0; + while (should_not_match[i] != NULL) + { + check_matches (FALSE, number, message, should_not_match[i]); + ++i; + } +} + +static void +test_matching (void) +{ + DBusMessage *message1; + const char *v_STRING; + dbus_int32_t v_INT32; + + message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL); + _dbus_assert (message1 != NULL); + if (!dbus_message_set_member (message1, "Frobated")) + _dbus_assert_not_reached ("oom"); + + v_STRING = "foobar"; + v_INT32 = 3; + if (!dbus_message_append_args (message1, + DBUS_TYPE_STRING, &v_STRING, + DBUS_TYPE_INT32, &v_INT32, + NULL)) + _dbus_assert_not_reached ("oom"); + + check_matching (message1, 1, + should_match_message_1, + should_not_match_message_1); + + dbus_message_unref (message1); +} + +dbus_bool_t +bus_signals_test (const DBusString *test_data_dir) +{ + BusMatchmaker *matchmaker; + + matchmaker = bus_matchmaker_new (); + bus_matchmaker_ref (matchmaker); + bus_matchmaker_unref (matchmaker); + bus_matchmaker_unref (matchmaker); + + if (!_dbus_test_oom_handling ("parsing match rules", test_parsing, NULL)) + _dbus_assert_not_reached ("Parsing match rules test failed"); + + test_equality (); + + test_matching (); + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ + diff --git a/bus/signals.h b/bus/signals.h new file mode 100644 index 00000000..4ea10755 --- /dev/null +++ b/bus/signals.h @@ -0,0 +1,88 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* signals.h Bus signal connection implementation + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_SIGNALS_H +#define BUS_SIGNALS_H + +#include +#include +#include +#include "connection.h" + +typedef enum +{ + BUS_MATCH_MESSAGE_TYPE = 1 << 0, + BUS_MATCH_INTERFACE = 1 << 1, + BUS_MATCH_MEMBER = 1 << 2, + BUS_MATCH_SENDER = 1 << 3, + BUS_MATCH_DESTINATION = 1 << 4, + BUS_MATCH_PATH = 1 << 5, + BUS_MATCH_ARGS = 1 << 6 +} BusMatchFlags; + +BusMatchRule* bus_match_rule_new (DBusConnection *matches_go_to); +BusMatchRule* bus_match_rule_ref (BusMatchRule *rule); +void bus_match_rule_unref (BusMatchRule *rule); + +dbus_bool_t bus_match_rule_set_message_type (BusMatchRule *rule, + int type); +dbus_bool_t bus_match_rule_set_interface (BusMatchRule *rule, + const char *interface); +dbus_bool_t bus_match_rule_set_member (BusMatchRule *rule, + const char *member); +dbus_bool_t bus_match_rule_set_sender (BusMatchRule *rule, + const char *sender); +dbus_bool_t bus_match_rule_set_destination (BusMatchRule *rule, + const char *destination); +dbus_bool_t bus_match_rule_set_path (BusMatchRule *rule, + const char *path); +dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule, + int arg, + const DBusString *value, + dbus_bool_t is_path); + +BusMatchRule* bus_match_rule_parse (DBusConnection *matches_go_to, + const DBusString *rule_text, + DBusError *error); + +BusMatchmaker* bus_matchmaker_new (void); +BusMatchmaker* bus_matchmaker_ref (BusMatchmaker *matchmaker); +void bus_matchmaker_unref (BusMatchmaker *matchmaker); + +dbus_bool_t bus_matchmaker_add_rule (BusMatchmaker *matchmaker, + BusMatchRule *rule); +dbus_bool_t bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker, + BusMatchRule *value, + DBusError *error); +void bus_matchmaker_remove_rule (BusMatchmaker *matchmaker, + BusMatchRule *rule); +void bus_matchmaker_disconnected (BusMatchmaker *matchmaker, + DBusConnection *disconnected); +dbus_bool_t bus_matchmaker_get_recipients (BusMatchmaker *matchmaker, + BusConnections *connections, + DBusConnection *sender, + DBusConnection *addressed_recipient, + DBusMessage *message, + DBusList **recipients_p); + +#endif /* BUS_SIGNALS_H */ diff --git a/bus/system.conf.in b/bus/system.conf.in new file mode 100644 index 00000000..92f4cc42 --- /dev/null +++ b/bus/system.conf.in @@ -0,0 +1,83 @@ + + + + + + + + + system + + + @DBUS_USER@ + + + + + + + + + @DBUS_LIBEXECDIR@/dbus-daemon-launch-helper + + + @DBUS_SYSTEM_PID_FILE@ + + + + + + EXTERNAL + + + @DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + system.d + + + system-local.conf + + contexts/dbus_contexts + + diff --git a/bus/test-launch-helper.c b/bus/test-launch-helper.c new file mode 100644 index 00000000..d78ca519 --- /dev/null +++ b/bus/test-launch-helper.c @@ -0,0 +1,146 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* test-main.c main() for the OOM check of the launch helper + * + * Copyright (C) 2007 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "test.h" +#include "activation-helper.h" + +#include +#include +#include + +#ifdef DBUS_BUILD_TESTS +static void +die (const char *failure) +{ + fprintf (stderr, "Unit test failed: %s\n", failure); + exit (1); +} + +static void +check_memleaks (const char *name) +{ + dbus_shutdown (); + + printf ("%s: checking for memleaks\n", name); + if (_dbus_get_malloc_blocks_outstanding () != 0) + { + _dbus_warn ("%d dbus_malloc blocks were not freed\n", + _dbus_get_malloc_blocks_outstanding ()); + die ("memleaks"); + } +} + +static void +test_post_hook (const char *name) +{ + check_memleaks (name); +} +#endif /* DBUS_BUILD_TESTS */ + + +#ifdef ACTIVATION_LAUNCHER_DO_OOM + +/* returns true if good things happen, or if we get OOM */ +static dbus_bool_t +bus_activation_helper_oom_test (void *data) +{ + const char *service; + DBusError error; + dbus_bool_t retval; + + service = (const char *) data; + retval = TRUE; + + dbus_error_init (&error); + if (!run_launch_helper (service, &error)) + { + _DBUS_ASSERT_ERROR_IS_SET (&error); + /* we failed, but a OOM is good */ + if (!dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + _dbus_warn ("FAILED SELF TEST: Error: %s\n", error.message); + retval = FALSE; + } + dbus_error_free (&error); + } + else + { + /* we succeeded, yay! */ + _DBUS_ASSERT_ERROR_IS_CLEAR (&error); + } + return retval; +} + +#endif + +int +main (int argc, char **argv) +{ +#ifdef DBUS_BUILD_TESTS + const char *dir; + DBusString config_file; + + if (argc > 1) + dir = argv[1]; + else + dir = _dbus_getenv ("DBUS_TEST_DATA"); + + if (dir == NULL) + { + fprintf (stderr, "Must specify test data directory as argv[1] or in DBUS_TEST_DATA env variable\n"); + return 1; + } + + printf ("%s: Running launch helper OOM checks\n", argv[0]); + + if (!_dbus_string_init (&config_file)) + return 1; + if (!_dbus_string_append (&config_file, dir)) + return 1; + if (!_dbus_string_append (&config_file, "/valid-config-files-system/debug-allow-all-pass.conf")) + return 1; + + /* use a config file that will actually work... */ + _dbus_setenv ("TEST_LAUNCH_HELPER_CONFIG", + _dbus_string_get_const_data (&config_file)); + + _dbus_string_free (&config_file); + + if (!_dbus_test_oom_handling ("dbus-daemon-launch-helper", + bus_activation_helper_oom_test, + "org.freedesktop.DBus.TestSuiteEchoService")) + die ("OOM failed"); + + test_post_hook (argv[0]); + + printf ("%s: Success\n", argv[0]); + + return 0; +#else /* DBUS_BUILD_TESTS */ + + printf ("Not compiled with test support\n"); + + return 0; +#endif +} + diff --git a/bus/test-main.c b/bus/test-main.c new file mode 100644 index 00000000..f19d0d55 --- /dev/null +++ b/bus/test-main.c @@ -0,0 +1,151 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* test-main.c main() for make check + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "test.h" +#include +#include +#include +#include +#include +#include "selinux.h" + +#ifdef DBUS_BUILD_TESTS +static void +die (const char *failure) +{ + fprintf (stderr, "Unit test failed: %s\n", failure); + exit (1); +} + +static void +check_memleaks (const char *name) +{ + dbus_shutdown (); + + printf ("%s: checking for memleaks\n", name); + if (_dbus_get_malloc_blocks_outstanding () != 0) + { + _dbus_warn ("%d dbus_malloc blocks were not freed\n", + _dbus_get_malloc_blocks_outstanding ()); + die ("memleaks"); + } +} +#endif /* DBUS_BUILD_TESTS */ + +static void +test_pre_hook (void) +{ + + if (_dbus_getenv ("DBUS_TEST_SELINUX") + && (!bus_selinux_pre_init () + || !bus_selinux_full_init ())) + die ("could not init selinux support"); +} + +static char *progname = ""; +static void +test_post_hook (void) +{ + if (_dbus_getenv ("DBUS_TEST_SELINUX")) + bus_selinux_shutdown (); + check_memleaks (progname); +} + +int +main (int argc, char **argv) +{ +#ifdef DBUS_BUILD_TESTS + const char *dir; + DBusString test_data_dir; + + progname = argv[0]; + + if (argc > 1) + dir = argv[1]; + else + dir = _dbus_getenv ("DBUS_TEST_DATA"); + + if (dir == NULL) + { + fprintf (stderr, "Must specify test data directory as argv[1] or in DBUS_TEST_DATA env variable\n"); + return 1; + } + + _dbus_string_init_const (&test_data_dir, dir); + + if (!_dbus_threads_init_debug ()) + die ("initializing debug threads"); + + test_pre_hook (); + printf ("%s: Running expire list test\n", argv[0]); + if (!bus_expire_list_test (&test_data_dir)) + die ("expire list"); + test_post_hook (); + + test_pre_hook (); + printf ("%s: Running config file parser test\n", argv[0]); + if (!bus_config_parser_test (&test_data_dir)) + die ("parser"); + test_post_hook (); + + test_pre_hook (); + printf ("%s: Running policy test\n", argv[0]); + if (!bus_policy_test (&test_data_dir)) + die ("policy"); + test_post_hook (); + + test_pre_hook (); + printf ("%s: Running signals test\n", argv[0]); + if (!bus_signals_test (&test_data_dir)) + die ("signals"); + test_post_hook (); + + test_pre_hook (); + printf ("%s: Running SHA1 connection test\n", argv[0]); + if (!bus_dispatch_sha1_test (&test_data_dir)) + die ("sha1"); + test_post_hook (); + + test_pre_hook (); + printf ("%s: Running message dispatch test\n", argv[0]); + if (!bus_dispatch_test (&test_data_dir)) + die ("dispatch"); + test_post_hook (); + + test_pre_hook (); + printf ("%s: Running service files reloading test\n", argv[0]); + if (!bus_activation_service_reload_test (&test_data_dir)) + die ("service reload"); + test_post_hook (); + + printf ("%s: Success\n", argv[0]); + + + return 0; +#else /* DBUS_BUILD_TESTS */ + + printf ("Not compiled with test support\n"); + + return 0; +#endif +} diff --git a/bus/test-system.c b/bus/test-system.c new file mode 100644 index 00000000..6224ab5e --- /dev/null +++ b/bus/test-system.c @@ -0,0 +1,106 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* test-main.c main() for make check + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "test.h" +#include +#include +#include +#include +#include + +#ifdef DBUS_BUILD_TESTS +static void +die (const char *failure) +{ + fprintf (stderr, "Unit test failed: %s\n", failure); + exit (1); +} + +static void +check_memleaks (const char *name) +{ + dbus_shutdown (); + + printf ("%s: checking for memleaks\n", name); + if (_dbus_get_malloc_blocks_outstanding () != 0) + { + _dbus_warn ("%d dbus_malloc blocks were not freed\n", + _dbus_get_malloc_blocks_outstanding ()); + die ("memleaks"); + } +} +#endif /* DBUS_BUILD_TESTS */ + +static void +test_pre_hook (void) +{ +} + +static char *progname = ""; +static void +test_post_hook (void) +{ + check_memleaks (progname); +} + +int +main (int argc, char **argv) +{ +#ifdef DBUS_BUILD_TESTS + const char *dir; + DBusString test_data_dir; + + progname = argv[0]; + + if (argc > 1) + dir = argv[1]; + else + dir = _dbus_getenv ("DBUS_TEST_DATA"); + + if (dir == NULL) + { + fprintf (stderr, "Must specify test data directory as argv[1] or in DBUS_TEST_DATA env variable\n"); + return 1; + } + + _dbus_string_init_const (&test_data_dir, dir); + + if (!_dbus_threads_init_debug ()) + die ("initializing debug threads"); + + test_pre_hook (); + printf ("%s: Running config file parser (trivial) test\n", argv[0]); + if (!bus_config_parser_trivial_test (&test_data_dir)) + die ("parser"); + test_post_hook (); + + printf ("%s: Success\n", argv[0]); + + return 0; +#else /* DBUS_BUILD_TESTS */ + + printf ("Not compiled with test support\n"); + + return 0; +#endif +} diff --git a/bus/test.c b/bus/test.c new file mode 100644 index 00000000..8dfe098c --- /dev/null +++ b/bus/test.c @@ -0,0 +1,346 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* test.c unit test routines + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#ifdef DBUS_BUILD_TESTS +#include "test.h" +#include +#include +#include + +/* The "debug client" watch/timeout handlers don't dispatch messages, + * as we manually pull them in order to verify them. This is why they + * are different from the real handlers in connection.c + */ +static DBusList *clients = NULL; +static DBusLoop *client_loop = NULL; + +static dbus_bool_t +client_watch_callback (DBusWatch *watch, + unsigned int condition, + void *data) +{ + /* FIXME this can be done in dbus-mainloop.c + * if the code in activation.c for the babysitter + * watch handler is fixed. + */ + + return dbus_watch_handle (watch, condition); +} + +static dbus_bool_t +add_client_watch (DBusWatch *watch, + void *data) +{ + DBusConnection *connection = data; + + return _dbus_loop_add_watch (client_loop, + watch, client_watch_callback, connection, + NULL); +} + +static void +remove_client_watch (DBusWatch *watch, + void *data) +{ + DBusConnection *connection = data; + + _dbus_loop_remove_watch (client_loop, + watch, client_watch_callback, connection); +} + +static void +client_timeout_callback (DBusTimeout *timeout, + void *data) +{ + DBusConnection *connection = data; + + dbus_connection_ref (connection); + + /* can return FALSE on OOM but we just let it fire again later */ + dbus_timeout_handle (timeout); + + dbus_connection_unref (connection); +} + +static dbus_bool_t +add_client_timeout (DBusTimeout *timeout, + void *data) +{ + DBusConnection *connection = data; + + return _dbus_loop_add_timeout (client_loop, timeout, client_timeout_callback, connection, NULL); +} + +static void +remove_client_timeout (DBusTimeout *timeout, + void *data) +{ + DBusConnection *connection = data; + + _dbus_loop_remove_timeout (client_loop, timeout, client_timeout_callback, connection); +} + +static DBusHandlerResult +client_disconnect_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + if (!dbus_message_is_signal (message, + DBUS_INTERFACE_LOCAL, + "Disconnected")) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + _dbus_verbose ("Removing client %p in disconnect handler\n", + connection); + + _dbus_list_remove (&clients, connection); + + dbus_connection_unref (connection); + + if (clients == NULL) + { + _dbus_loop_unref (client_loop); + client_loop = NULL; + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + +dbus_bool_t +bus_setup_debug_client (DBusConnection *connection) +{ + dbus_bool_t retval; + + if (!dbus_connection_add_filter (connection, + client_disconnect_filter, + NULL, NULL)) + return FALSE; + + retval = FALSE; + + if (client_loop == NULL) + { + client_loop = _dbus_loop_new (); + if (client_loop == NULL) + goto out; + } + + if (!dbus_connection_set_watch_functions (connection, + add_client_watch, + remove_client_watch, + NULL, + connection, + NULL)) + goto out; + + if (!dbus_connection_set_timeout_functions (connection, + add_client_timeout, + remove_client_timeout, + NULL, + connection, NULL)) + goto out; + + if (!_dbus_list_append (&clients, connection)) + goto out; + + retval = TRUE; + + out: + if (!retval) + { + dbus_connection_remove_filter (connection, + client_disconnect_filter, + NULL); + + dbus_connection_set_watch_functions (connection, + NULL, NULL, NULL, NULL, NULL); + dbus_connection_set_timeout_functions (connection, + NULL, NULL, NULL, NULL, NULL); + + _dbus_list_remove_last (&clients, connection); + + if (clients == NULL) + { + _dbus_loop_unref (client_loop); + client_loop = NULL; + } + } + + return retval; +} + +void +bus_test_clients_foreach (BusConnectionForeachFunction function, + void *data) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&clients); + while (link != NULL) + { + DBusConnection *connection = link->data; + DBusList *next = _dbus_list_get_next_link (&clients, link); + + if (!(* function) (connection, data)) + break; + + link = next; + } +} + +dbus_bool_t +bus_test_client_listed (DBusConnection *connection) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&clients); + while (link != NULL) + { + DBusConnection *c = link->data; + DBusList *next = _dbus_list_get_next_link (&clients, link); + + if (c == connection) + return TRUE; + + link = next; + } + + return FALSE; +} + +void +bus_test_run_clients_loop (dbus_bool_t block_once) +{ + if (client_loop == NULL) + return; + + _dbus_verbose ("---> Dispatching on \"client side\"\n"); + + /* dispatch before we block so pending dispatches + * won't make our block return early + */ + _dbus_loop_dispatch (client_loop); + + /* Do one blocking wait, since we're expecting data */ + if (block_once) + { + _dbus_verbose ("---> blocking on \"client side\"\n"); + _dbus_loop_iterate (client_loop, TRUE); + } + + /* Then mop everything up */ + while (_dbus_loop_iterate (client_loop, FALSE)) + ; + + _dbus_verbose ("---> Done dispatching on \"client side\"\n"); +} + +void +bus_test_run_bus_loop (BusContext *context, + dbus_bool_t block_once) +{ + _dbus_verbose ("---> Dispatching on \"server side\"\n"); + + /* dispatch before we block so pending dispatches + * won't make our block return early + */ + _dbus_loop_dispatch (bus_context_get_loop (context)); + + /* Do one blocking wait, since we're expecting data */ + if (block_once) + { + _dbus_verbose ("---> blocking on \"server side\"\n"); + _dbus_loop_iterate (bus_context_get_loop (context), TRUE); + } + + /* Then mop everything up */ + while (_dbus_loop_iterate (bus_context_get_loop (context), FALSE)) + ; + + _dbus_verbose ("---> Done dispatching on \"server side\"\n"); +} + +void +bus_test_run_everything (BusContext *context) +{ + while (_dbus_loop_iterate (bus_context_get_loop (context), FALSE) || + (client_loop == NULL || _dbus_loop_iterate (client_loop, FALSE))) + ; +} + +BusContext* +bus_context_new_test (const DBusString *test_data_dir, + const char *filename) +{ + DBusError error; + DBusString config_file; + DBusString relative; + BusContext *context; + + if (!_dbus_string_init (&config_file)) + { + _dbus_warn ("No memory\n"); + return NULL; + } + + if (!_dbus_string_copy (test_data_dir, 0, + &config_file, 0)) + { + _dbus_warn ("No memory\n"); + _dbus_string_free (&config_file); + return NULL; + } + + _dbus_string_init_const (&relative, filename); + + if (!_dbus_concat_dir_and_file (&config_file, &relative)) + { + _dbus_warn ("No memory\n"); + _dbus_string_free (&config_file); + return NULL; + } + + dbus_error_init (&error); + context = bus_context_new (&config_file, FALSE, NULL, NULL, &error); + if (context == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (&error); + + _dbus_warn ("Failed to create debug bus context from configuration file %s: %s\n", + filename, error.message); + + dbus_error_free (&error); + + _dbus_string_free (&config_file); + + return NULL; + } + + _dbus_string_free (&config_file); + + return context; +} + +#endif diff --git a/bus/test.h b/bus/test.h new file mode 100644 index 00000000..72d68b09 --- /dev/null +++ b/bus/test.h @@ -0,0 +1,58 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* test.h unit test routines + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_TEST_H +#define BUS_TEST_H + +#include + +#ifdef DBUS_BUILD_TESTS + +#include +#include +#include "connection.h" + +dbus_bool_t bus_dispatch_test (const DBusString *test_data_dir); +dbus_bool_t bus_dispatch_sha1_test (const DBusString *test_data_dir); +dbus_bool_t bus_policy_test (const DBusString *test_data_dir); +dbus_bool_t bus_config_parser_test (const DBusString *test_data_dir); +dbus_bool_t bus_config_parser_trivial_test (const DBusString *test_data_dir); +dbus_bool_t bus_signals_test (const DBusString *test_data_dir); +dbus_bool_t bus_expire_list_test (const DBusString *test_data_dir); +dbus_bool_t bus_activation_service_reload_test (const DBusString *test_data_dir); +dbus_bool_t bus_setup_debug_client (DBusConnection *connection); +void bus_test_clients_foreach (BusConnectionForeachFunction function, + void *data); +dbus_bool_t bus_test_client_listed (DBusConnection *connection); +void bus_test_run_bus_loop (BusContext *context, + dbus_bool_t block); +void bus_test_run_clients_loop (dbus_bool_t block); +void bus_test_run_everything (BusContext *context); +BusContext* bus_context_new_test (const DBusString *test_data_dir, + const char *filename); + + + +#endif + +#endif /* BUS_TEST_H */ diff --git a/bus/utils.c b/bus/utils.c new file mode 100644 index 00000000..7d248727 --- /dev/null +++ b/bus/utils.c @@ -0,0 +1,48 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* utils.c General utility functions + * + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include "utils.h" +#include +#include + +const char bus_no_memory_message[] = "Memory allocation failure in message bus"; + +void +bus_connection_dispatch_all_messages (DBusConnection *connection) +{ + while (bus_connection_dispatch_one_message (connection)) + ; +} + +dbus_bool_t +bus_connection_dispatch_one_message (DBusConnection *connection) +{ + DBusDispatchStatus status; + + while ((status = dbus_connection_dispatch (connection)) == DBUS_DISPATCH_NEED_MEMORY) + _dbus_wait_for_memory (); + + return status == DBUS_DISPATCH_DATA_REMAINS; +} diff --git a/bus/utils.h b/bus/utils.h new file mode 100644 index 00000000..f533895f --- /dev/null +++ b/bus/utils.h @@ -0,0 +1,36 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* utils.h General utility functions + * + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_UTILS_H +#define BUS_UTILS_H + +#include + +extern const char bus_no_memory_message[]; +#define BUS_SET_OOM(error) dbus_set_error_const ((error), DBUS_ERROR_NO_MEMORY, bus_no_memory_message) + +void bus_connection_dispatch_all_messages (DBusConnection *connection); +dbus_bool_t bus_connection_dispatch_one_message (DBusConnection *connection); + +#endif /* BUS_UTILS_H */ diff --git a/cleanup-man-pages.sh b/cleanup-man-pages.sh new file mode 100755 index 00000000..23e98a66 --- /dev/null +++ b/cleanup-man-pages.sh @@ -0,0 +1,86 @@ +#! /bin/sh + +## This script cleans up private/internal API from the man pages +## generated by Doxygen. This brings the man pages down from 7 megs +## to 2 megs and avoids namespace-polluting man pages. It's probably +## pretty specific to GNU utilities. Patches gladly accepted to make +## it work without them. + +## You would run this after building dbus and after running "doxygen +## Doxyfile" + +die() { + echo "$*" 1>&2 + exit 1 +} + +MANDIR=$1 +if test x"$MANDIR" = x ; then + MANDIR=doc/api/man/man3dbus +fi + +cd "$MANDIR" || die "Could not cd to $MANDIR" + +test -d keep || mkdir keep || die "Could not create $MANDIR/keep directory" +test -d nuke || mkdir nuke || die "Could not create $MANDIR/nuke directory" + +## blacklist +(find . -maxdepth 1 -name "_*" | xargs -I ITEMS /bin/mv ITEMS nuke) || die "could not move all underscore-prefixed items" +(find . -maxdepth 1 -name "DBus*Internal*" | xargs -I ITEMS /bin/mv ITEMS nuke) || die "could not move all internal-containing items" +(find . -maxdepth 1 -name "dbus_*_internal_*" | xargs -I ITEMS /bin/mv ITEMS nuke) || die "could not move all internal-containing items" + +## this is kind of unmaintainable, but I guess it's no huge disaster if we miss something. +## this list should only contain man pages with >1 line, i.e. with real content; the +## one-line cross-references get cleaned up next. +for I in DBusCounter.* DBusCredentials.* DBusDataSlot.* DBusDataSlotAllocator.* DBusDataSlotList.* \ + DBusDirIter.* DBusFakeMutex.* DBusFreedElement.* DBusGroupInfo.* DBusGUID.* DBusHashEntry.* \ + DBusHashIter.* DBusHashTable.* DBusHeader.* DBusHeaderField.* DBusKey.* DBusKeyring.* DBusList.* \ + DBusMarshal.* DBusMD5* DBusMemBlock.* DBusMemPool.* DBusMessageGenerator.* DBusMessageLoader.* \ + DBusMessageRealIter.* DBusObjectSubtree.* DBusObjectTree.* DBusPollFD.* DBusReal* \ + DBusResources.* DBusServerDebugPipe.* DBusServerSocket.* DBusServerUnix.* \ + DBusServerVTable.* DBusSHA.* DBusSHAContext.* DBusSignatureRealIter.* DBusStat.* DBusString.* \ + DBusSysdeps.* DBusSysdepsUnix.* DBusTimeoutList.* DBusTransport* DBusTypeReader* DBusTypeWriter* \ + DBusUserInfo.* DBusWatchList.* ; do + if test -f "$I" ; then + /bin/mv "$I" nuke || die "could not move $I to $MANDIR/nuke" + fi +done + +## many files just contain ".so man3dbus/DBusStringInternals.3dbus" or the like, +## if these point to something we nuked, we want to also nuke the pointer. +for I in * ; do + if test -f "$I" ; then + LINES=`wc -l "$I" | cut -d ' ' -f 1` + if test x"$LINES" = x1 ; then + REF_TO=`cat "$I" | sed -e 's/\.so man3dbus\///g'` + ## echo "$I points to $REF_TO" + if ! test -f "$REF_TO" ; then + /bin/mv "$I" nuke || die "could not move $I to $MANDIR/nuke" + fi + fi + fi +done + +## whitelist +(find . -maxdepth 1 -name "dbus_*" | xargs -I ITEMS /bin/mv ITEMS keep) || die "could not move all dbus-prefixed items" +(find . -maxdepth 1 -name "DBUS_*" | xargs -I ITEMS /bin/mv ITEMS keep) || die "could not move all DBUS_-prefixed items" +(find . -maxdepth 1 -name "DBus*" | xargs -I ITEMS /bin/mv ITEMS keep) || die "could not move all DBus-prefixed items" + +## everything else is assumed irrelevant, this is mostly struct fields +## from the public headers +(find . -maxdepth 1 -type f | xargs -I ITEMS /bin/mv ITEMS nuke) || die "could not move remaining items" + +NUKE_COUNT=`find nuke -type f -name "*" | wc -l` +KEEP_COUNT=`find keep -type f -name "*" | wc -l` +MISSING_COUNT=`find . -maxdepth 1 -type f -name "*" | wc -l` + +echo "$KEEP_COUNT man pages kept and $NUKE_COUNT man pages to remove" +echo "$MISSING_COUNT not handled" + +(find keep -type f -name "*" | xargs -I ITEMS /bin/mv ITEMS .) || die "could not move kept items back" + +rmdir keep || die "could not remove $MANDIR/keep" + +echo "Man pages to be installed are in $MANDIR and man pages to ignore are in $MANDIR/nuke" + +exit 0 diff --git a/compile b/compile new file mode 100755 index 00000000..c0096a7b --- /dev/null +++ b/compile @@ -0,0 +1,143 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2009-10-06.20; # UTC + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009 Free Software +# Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, 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. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/config.guess b/config.guess new file mode 100755 index 00000000..dc84c68e --- /dev/null +++ b/config.guess @@ -0,0 +1,1501 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-20' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a 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. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +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, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* 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:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #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 -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + 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 ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# 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/config.h.in b/config.h.in new file mode 100644 index 00000000..4d2384ac --- /dev/null +++ b/config.h.in @@ -0,0 +1,380 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* poll doesn't work on devices */ +#undef BROKEN_POLL + +/* Directory for installing the binaries */ +#undef DBUS_BINDIR + +/* Build test code */ +#undef DBUS_BUILD_TESTS + +/* Build X11-dependent code */ +#undef DBUS_BUILD_X11 + +/* whether -export-dynamic was passed to libtool */ +#undef DBUS_BUILT_R_DYNAMIC + +/* Use dnotify on Linux */ +#undef DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX + +/* Use inotify */ +#undef DBUS_BUS_ENABLE_INOTIFY + +/* Use kqueue */ +#undef DBUS_BUS_ENABLE_KQUEUE + +/* Directory to check for console ownerhip */ +#undef DBUS_CONSOLE_AUTH_DIR + +/* File to check for console ownerhip */ +#undef DBUS_CONSOLE_OWNER_FILE + +/* Directory for installing the DBUS daemon */ +#undef DBUS_DAEMONDIR + +/* Directory for installing DBUS data files */ +#undef DBUS_DATADIR + +/* Disable assertion checking */ +#undef DBUS_DISABLE_ASSERT + +/* Disable public API sanity checking */ +#undef DBUS_DISABLE_CHECKS + +/* Build with caching of user data */ +#undef DBUS_ENABLE_USERDB_CACHE + +/* Support a verbose mode */ +#undef DBUS_ENABLE_VERBOSE_MODE + +/* Defined if gcov is enabled to force a rebuild due to config.h changing */ +#undef DBUS_GCOV_ENABLED + +/* Always defined; expands to 1 if we have an atomic integer implementation, + else 0 */ +#undef DBUS_HAVE_ATOMIC_INT_COND + +/* Defined if we have gcc 3.3 and thus the new gcov format */ +#undef DBUS_HAVE_GCC33_GCOV + +/* Define to printf modifier for 64 bit integer type */ +#undef DBUS_INT64_PRINTF_MODIFIER + +/* Directory for installing the libexec binaries */ +#undef DBUS_LIBEXECDIR + +/* Where per-session bus puts its sockets */ +#undef DBUS_SESSION_SOCKET_DIR + +/* The default D-Bus address of the system bus */ +#undef DBUS_SYSTEM_BUS_DEFAULT_ADDRESS + +/* The name of the socket the system bus listens on by default */ +#undef DBUS_SYSTEM_SOCKET + +/* Full path to the launch helper test program in the builddir */ +#undef DBUS_TEST_LAUNCH_HELPER_BINARY + +/* Where to put test sockets */ +#undef DBUS_TEST_SOCKET_DIR + +/* Defined on UNIX and Linux systems and not on Windows */ +#undef DBUS_UNIX + +/* User for running the system BUS daemon */ +#undef DBUS_USER + +/* Always defined; expands to 1 if we should use atomic integer implementation + for 486, else 0 */ +#undef DBUS_USE_ATOMIC_INT_486_COND + +/* A 'va_copy' style function */ +#undef DBUS_VA_COPY + +/* 'va_lists' cannot be copies as values */ +#undef DBUS_VA_COPY_AS_ARRAY + +/* The name of the gettext domain */ +#undef GETTEXT_PACKAGE + +/* Disable GLib assertion macros */ +#undef G_DISABLE_ASSERT + +/* Disable GLib public API sanity checking */ +#undef G_DISABLE_CHECKS + +/* Have abstract socket namespace */ +#undef HAVE_ABSTRACT_SOCKETS + +/* Adt audit API */ +#undef HAVE_ADT + +/* Define to 1 if you have the `backtrace' function. */ +#undef HAVE_BACKTRACE + +/* Define to 1 if you have the `clearenv' function. */ +#undef HAVE_CLEARENV + +/* Have cmsgcred structure */ +#undef HAVE_CMSGCRED + +/* Have console owner file */ +#undef HAVE_CONSOLE_OWNER_FILE + +/* Define to 1 if you have the header file. */ +#undef HAVE_CRT_EXTERNS_H + +/* Have the ddfd member of DIR */ +#undef HAVE_DDFD + +/* Have dirfd function */ +#undef HAVE_DIRFD + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_EXECINFO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_EXPAT_H + +/* Define to 1 if you have the `fpathconf' function. */ +#undef HAVE_FPATHCONF + +/* Define to 1 if you have the `getgrouplist' function. */ +#undef HAVE_GETGROUPLIST + +/* Define to 1 if you have the `getpeereid' function. */ +#undef HAVE_GETPEEREID + +/* Define to 1 if you have the `getpeerucred' function. */ +#undef HAVE_GETPEERUCRED + +/* Have GNU-style varargs macros */ +#undef HAVE_GNUC_VARARGS + +/* Define to 1 if you have the `inotify_init1' function. */ +#undef HAVE_INOTIFY_INIT1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Have ISO C99 varargs macros */ +#undef HAVE_ISO_VARARGS + +/* audit daemon SELinux support */ +#undef HAVE_LIBAUDIT + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define if we have CLOCK_MONOTONIC */ +#undef HAVE_MONOTONIC_CLOCK + +/* Define to 1 if you have the `nanosleep' function. */ +#undef HAVE_NANOSLEEP + +/* Have non-POSIX function getpwnam_r */ +#undef HAVE_NONPOSIX_GETPWNAM_R + +/* Define if your system needs _NSGetEnviron to set up the environment */ +#undef HAVE_NSGETENVIRON + +/* Define to 1 if you have the `poll' function. */ +#undef HAVE_POLL + +/* Have POSIX function getpwnam_r */ +#undef HAVE_POSIX_GETPWNAM_R + +/* SELinux support */ +#undef HAVE_SELINUX + +/* Define to 1 if you have the `setenv' function. */ +#undef HAVE_SETENV + +/* Define to 1 if you have the `setrlimit' function. */ +#undef HAVE_SETRLIMIT + +/* Define to 1 if you have the `socketpair' function. */ +#undef HAVE_SOCKETPAIR + +/* Have socklen_t type */ +#undef HAVE_SOCKLEN_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_INOTIFY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSLIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `unsetenv' function. */ +#undef HAVE_UNSETENV + +/* Define to 1 if you have the `usleep' function. */ +#undef HAVE_USLEEP + +/* Define to 1 if you have the `vasprintf' function. */ +#undef HAVE_VASPRINTF + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Define to 1 if you have the `writev' function. */ +#undef HAVE_WRITEV + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of `char', as computed by sizeof. */ +#undef SIZEOF_CHAR + +/* The size of `int', as computed by sizeof. */ +#undef SIZEOF_INT + +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `long long', as computed by sizeof. */ +#undef SIZEOF_LONG_LONG + +/* The size of `short', as computed by sizeof. */ +#undef SIZEOF_SHORT + +/* The size of `void *', as computed by sizeof. */ +#undef SIZEOF_VOID_P + +/* The size of `__int64', as computed by sizeof. */ +#undef SIZEOF___INT64 + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Full path to the daemon in the builddir */ +#undef TEST_BUS_BINARY + +/* Full path to test file test/test-exit in builddir */ +#undef TEST_EXIT_BINARY + +/* Full path to test file test/data/invalid-service-files in builddir */ +#undef TEST_INVALID_SERVICE_DIR + +/* Full path to test file test/data/invalid-service-files-system in builddir + */ +#undef TEST_INVALID_SERVICE_SYSTEM_DIR + +/* Full path to test file test/name-test/test-privserver in builddir */ +#undef TEST_PRIVSERVER_BINARY + +/* Full path to test file test/test-segfault in builddir */ +#undef TEST_SEGFAULT_BINARY + +/* Full path to test file test/test-service in builddir */ +#undef TEST_SERVICE_BINARY + +/* Full path to test file test/test-shell-service in builddir */ +#undef TEST_SHELL_SERVICE_BINARY + +/* Full path to test file test/test-sleep-forever in builddir */ +#undef TEST_SLEEP_FOREVER_BINARY + +/* Full path to test file test/data/valid-service-files in builddir */ +#undef TEST_VALID_SERVICE_DIR + +/* Full path to test file test/data/valid-service-files-system in builddir */ +#undef TEST_VALID_SERVICE_SYSTEM_DIR + +/* Version number of package */ +#undef VERSION + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + + + /* Use the compiler-provided endianness defines to allow universal compiling. */ + #if defined(__BIG_ENDIAN__) + #define WORDS_BIGENDIAN 1 + #endif + + +/* Define to 1 if the X Window System is missing or not being used. */ +#undef X_DISPLAY_MISSING + + +#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +# include +# include +# define environ (*_NSGetEnviron()) +#endif + + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif diff --git a/config.sub b/config.sub new file mode 100755 index 00000000..2a55a507 --- /dev/null +++ b/config.sub @@ -0,0 +1,1705 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-11-20' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted GNU 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. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# 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, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | picochip) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 00000000..75bdf1fd --- /dev/null +++ b/configure @@ -0,0 +1,29138 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.63 for dbus 1.2.24. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell bug-autoconf@gnu.org about your system, + echo including any error possibly output before this message. + echo This can help us improve future autoconf versions. + echo Configuration will now proceed without shell functions. +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$lt_ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +ECHO=${lt_ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<_LT_EOF +$* +_LT_EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test -z "$lt_ECHO"; then + if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if { echo_test_string=`eval $cmd`; } 2>/dev/null && + { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null + then + break + fi + done + fi + + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : + else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$ECHO" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + ECHO='print -r' + elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + ECHO='printf %s\n' + if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && + echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + ECHO="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi + fi + fi + fi + fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +lt_ECHO=$ECHO +if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME='dbus' +PACKAGE_TARNAME='dbus' +PACKAGE_VERSION='1.2.24' +PACKAGE_STRING='dbus 1.2.24' +PACKAGE_BUGREPORT='' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +DBUS_SESSION_SOCKET_DIR +TEST_SOCKET_DIR +TEST_LAUNCH_HELPER_BINARY +TEST_BUS_BINARY +TEST_PRIVSERVER_BINARY +TEST_SLEEP_FOREVER_BINARY +TEST_SEGFAULT_BINARY +TEST_EXIT_BINARY +TEST_SHELL_SERVICE_BINARY +TEST_SERVICE_BINARY +TEST_INVALID_SERVICE_SYSTEM_DIR +TEST_VALID_SERVICE_SYSTEM_DIR +TEST_INVALID_SERVICE_DIR +TEST_VALID_SERVICE_DIR +DBUS_LIBEXECDIR +DBUS_BINDIR +DBUS_DAEMONDIR +DBUS_DATADIR +DBUS_USER +DBUS_CONSOLE_OWNER_FILE +DBUS_CONSOLE_AUTH_DIR +DBUS_SYSTEM_PID_FILE +DBUS_SYSTEM_BUS_DEFAULT_ADDRESS +DBUS_SYSTEM_SOCKET +DBUS_INIT_SCRIPTS_SLACKWARE_FALSE +DBUS_INIT_SCRIPTS_SLACKWARE_TRUE +DBUS_INIT_SCRIPTS_RED_HAT_FALSE +DBUS_INIT_SCRIPTS_RED_HAT_TRUE +EXPANDED_DATADIR +EXPANDED_LIBEXECDIR +EXPANDED_LIBDIR +EXPANDED_BINDIR +EXPANDED_SYSCONFDIR +EXPANDED_LOCALSTATEDIR +DBUS_XML_DOCS_ENABLED_FALSE +DBUS_XML_DOCS_ENABLED_TRUE +XMLTO +DBUS_DOXYGEN_DOCS_ENABLED_FALSE +DBUS_DOXYGEN_DOCS_ENABLED_TRUE +DOXYGEN +SECTION_LDFLAGS +SECTION_FLAGS +PIE_LDFLAGS +PIE_CFLAGS +PIC_LDFLAGS +PIC_CFLAGS +DBUS_X_LIBS +DBUS_X_CFLAGS +X_EXTRA_LIBS +X_LIBS +X_PRE_LIBS +X_CFLAGS +XMKMF +DBUS_TEST_LIBS +DBUS_TEST_CFLAGS +DBUS_LAUNCHER_LIBS +DBUS_LAUNCHER_CFLAGS +DBUS_BUS_LIBS +DBUS_BUS_CFLAGS +DBUS_CLIENT_LIBS +DBUS_CLIENT_CFLAGS +HAVE_LIBAUDIT_FALSE +HAVE_LIBAUDIT_TRUE +HAVE_CONSOLE_OWNER_FILE_FALSE +HAVE_CONSOLE_OWNER_FILE_TRUE +DBUS_BUS_ENABLE_KQUEUE_FALSE +DBUS_BUS_ENABLE_KQUEUE_TRUE +DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX_FALSE +DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX_TRUE +DBUS_BUS_ENABLE_INOTIFY_FALSE +DBUS_BUS_ENABLE_INOTIFY_TRUE +HAVE_SELINUX_FALSE +HAVE_SELINUX_TRUE +DBUS_USE_LIBXML_FALSE +DBUS_USE_LIBXML_TRUE +DBUS_USE_EXPAT_FALSE +DBUS_USE_EXPAT_TRUE +LIBXML_LIBS +LIBXML_CFLAGS +PKG_CONFIG +DBUS_PATH_OR_ABSTRACT +DBUS_INT16_TYPE +DBUS_INT32_TYPE +DBUS_HAVE_INT64 +DBUS_UINT64_CONSTANT +DBUS_INT64_CONSTANT +DBUS_INT64_TYPE +DBUS_GCOV_ENABLED_FALSE +DBUS_GCOV_ENABLED_TRUE +R_DYNAMIC_LDFLAG +DBUS_BUILD_TESTS_FALSE +DBUS_BUILD_TESTS_TRUE +CXXCPP +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +lt_ECHO +RANLIB +AR +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +SED +LIBTOOL +EGREP +GREP +CPP +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +DBUS_VERSION +DBUS_MICRO_VERSION +DBUS_MINOR_VERSION +DBUS_MAJOR_VERSION +LT_AGE +LT_REVISION +LT_CURRENT +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +GETTEXT_PACKAGE +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_maintainer_mode +enable_silent_rules +enable_dependency_tracking +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +enable_libtool_lock +enable_tests +enable_ansi +enable_verbose_mode +enable_asserts +enable_checks +enable_xml_docs +enable_doxygen_docs +enable_gcov +enable_abstract_sockets +enable_selinux +enable_libaudit +enable_dnotify +enable_inotify +enable_kqueue +enable_console_owner_file +enable_userdb_cache +with_xml +with_init_scripts +with_session_socket_dir +with_test_socket_dir +with_system_pid_file +with_system_socket +with_console_auth_dir +with_console_owner_file +with_dbus_user +with_dbus_daemondir +with_x +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CPP +CXXCPP +XMKMF' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { $as_echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { $as_echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2 + { (exit 1); exit 1; }; } ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { $as_echo "$as_me: error: working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { $as_echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures dbus 1.2.24 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/dbus] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +X features: + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of dbus 1.2.24:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer + --enable-silent-rules less verbose build output (undo: `make V=1') + --disable-silent-rules verbose build output (undo: `make V=0') + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --enable-tests enable unit test code + --enable-ansi enable -ansi -pedantic gcc flags + --enable-verbose-mode support verbose debug mode + --enable-asserts include assertion checks + --enable-checks include sanity checks on public API + --enable-xml-docs build XML documentation (requires xmlto) + --enable-doxygen-docs build DOXYGEN documentation (requires Doxygen) + --enable-gcov compile with coverage profiling instrumentation (gcc + only) + --enable-abstract-sockets + use abstract socket namespace (linux only) + --enable-selinux build with SELinux support + --enable-libaudit build audit daemon support for SELinux + --enable-dnotify build with dnotify support (linux only) + --enable-inotify build with inotify support (linux only) + --enable-kqueue build with kqueue support + --enable-console-owner-file + enable console owner file + --enable-userdb-cache build with userdb-cache support + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-xml=libxml/expat XML library to use + --with-init-scripts=redhat + Style of init scripts to install + --with-session-socket-dir=dirname + Where to put sockets for the per-login-session + message bus + --with-test-socket-dir=dirname + Where to put sockets for make check + --with-system-pid-file=pidfile + PID file for systemwide daemon + --with-system-socket=filename + UNIX domain socket for systemwide daemon + --with-console-auth-dir=dirname + directory to check for console ownerhip + --with-console-owner-file=filename + file whose owner determines current console owner + --with-dbus-user= User for running the DBUS daemon (messagebus) + --with-dbus-daemondir=dirname + Directory for installing the DBUS daemon + --with-x use the X Window System + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CPP C preprocessor + CXXCPP C++ preprocessor + XMKMF Path to xmkmf, Makefile generator for X Window System + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +dbus configure 1.2.24 +generated by GNU Autoconf 2.63 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by dbus $as_me 1.2.24, which was +generated by GNU Autoconf 2.63. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + ac_site_file1=$CONFIG_SITE +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test -r "$ac_site_file"; then + { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:$LINENO: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:$LINENO: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +$as_echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 +$as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} + { (exit 1); exit 1; }; } + +{ $as_echo "$as_me:$LINENO: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +$as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 +$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 +$as_echo "$as_me: error: invalid value of canonical build" >&2;} + { (exit 1); exit 1; }; };; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:$LINENO: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 +$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} + { (exit 1); exit 1; }; } +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 +$as_echo "$as_me: error: invalid value of canonical host" >&2;} + { (exit 1); exit 1; }; };; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + + +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + +done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + { { $as_echo "$as_me:$LINENO: error: unsafe absolute working directory name" >&5 +$as_echo "$as_me: error: unsafe absolute working directory name" >&2;} + { (exit 1); exit 1; }; };; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + { { $as_echo "$as_me:$LINENO: error: unsafe srcdir value: \`$srcdir'" >&5 +$as_echo "$as_me: error: unsafe srcdir value: \`$srcdir'" >&2;} + { (exit 1); exit 1; }; };; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { $as_echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +$as_echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { $as_echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +$as_echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +{ $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:$LINENO: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done +done +IFS=$as_save_IFS + +fi + + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + test -d ./--version && rmdir ./--version + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:$LINENO: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:$LINENO: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + { { $as_echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +$as_echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='dbus' + VERSION='1.2.24' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + + +{ $as_echo "$as_me:$LINENO: checking how to create a ustar tar archive" >&5 +$as_echo_n "checking how to create a ustar tar archive... " >&6; } +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar plaintar pax cpio none' +_am_tools=${am_cv_prog_tar_ustar-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + { echo "$as_me:$LINENO: $_am_tar --version" >&5 + ($_am_tar --version) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && break + done + am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x ustar -w "$$tardir"' + am__tar_='pax -L -x ustar -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H ustar -L' + am__tar_='find "$tardir" -print | cpio -o -H ustar -L' + am__untar='cpio -i -H ustar -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_ustar}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5 + (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + rm -rf conftest.dir + if test -s conftest.tar; then + { echo "$as_me:$LINENO: $am__untar &5 + ($am__untar &5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +if test "${am_cv_prog_tar_ustar+set}" = set; then + $as_echo_n "(cached) " >&6 +else + am_cv_prog_tar_ustar=$_am_tool +fi + +{ $as_echo "$as_me:$LINENO: result: $am_cv_prog_tar_ustar" >&5 +$as_echo "$am_cv_prog_tar_ustar" >&6; } + + + + + +ac_config_headers="$ac_config_headers config.h" + + +# Honor aclocal flags +ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS" + +GETTEXT_PACKAGE=dbus-1 + + +cat >>confdefs.h <<_ACEOF +#define GETTEXT_PACKAGE "$GETTEXT_PACKAGE" +_ACEOF + + + ## must come before we use the $USE_MAINTAINER_MODE variable later + +{ $as_echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { $as_echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in +yes) AM_DEFAULT_VERBOSITY=0;; +no) AM_DEFAULT_VERBOSITY=1;; +*) AM_DEFAULT_VERBOSITY=0;; +esac +AM_BACKSLASH='\' + + +# libtool versioning - this applies to libdbus +# +# See http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 for details +# + +## increment if the interface has additions, changes, removals. +LT_CURRENT=7 + +## increment any time the source changes; set to +## 0 if you increment CURRENT +LT_REVISION=0 + +## increment if any interfaces have been added; set to 0 +## if any interfaces have been changed or removed. removal has +## precedence over adding, so set to 0 if both happened. +LT_AGE=4 + + + + + +DBUS_MAJOR_VERSION=1 +DBUS_MINOR_VERSION=2 +DBUS_MICRO_VERSION=24 +DBUS_VERSION=1.2.24 + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:$LINENO: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:$LINENO: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:$LINENO: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:$LINENO: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } + +# Provide some information about the compiler. +$as_echo "$as_me:$LINENO: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +if test -z "$ac_file"; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } + fi + fi +fi +{ $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } +fi + +rm -f conftest$ac_cv_exeext +{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:$LINENO: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:$LINENO: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:$LINENO: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +if test "x$CC" != xcc; then + { $as_echo "$as_me:$LINENO: checking whether $CC and cc understand -c and -o together" >&5 +$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } +else + { $as_echo "$as_me:$LINENO: checking whether cc understands -c and -o together" >&5 +$as_echo_n "checking whether cc understands -c and -o together... " >&6; } +fi +set dummy $CC; ac_cc=`$as_echo "$2" | + sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +if { as_var=ac_cv_prog_cc_${ac_cc}_c_o; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +# Make sure it works both with $CC and with simple cc. +# We do the test twice because some compilers refuse to overwrite an +# existing .o file with -o, though they will create one. +ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' +rm -f conftest2.* +if { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + test -f conftest2.$ac_objext && { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; +then + eval ac_cv_prog_cc_${ac_cc}_c_o=yes + if test "x$CC" != xcc; then + # Test first that cc exists at all. + if { ac_try='cc -c conftest.$ac_ext >&5' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' + rm -f conftest2.* + if { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + test -f conftest2.$ac_objext && { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; + then + # cc works too. + : + else + # cc exists but doesn't like -o. + eval ac_cv_prog_cc_${ac_cc}_c_o=no + fi + fi + fi +else + eval ac_cv_prog_cc_${ac_cc}_c_o=no +fi +rm -f core conftest* + +fi +if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + +cat >>confdefs.h <<\_ACEOF +#define NO_MINUS_C_MINUS_O 1 +_ACEOF + +fi + +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:$LINENO: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:$LINENO: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CXXFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + +{ $as_echo "$as_me:$LINENO: checking for library containing strerror" >&5 +$as_echo_n "checking for library containing strerror... " >&6; } +if test "${ac_cv_search_strerror+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char strerror (); +int +main () +{ +return strerror (); + ; + return 0; +} +_ACEOF +for ac_lib in '' cposix; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_search_strerror=$ac_res +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext + if test "${ac_cv_search_strerror+set}" = set; then + break +fi +done +if test "${ac_cv_search_strerror+set}" = set; then + : +else + ac_cv_search_strerror=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_strerror" >&5 +$as_echo "$ac_cv_search_strerror" >&6; } +ac_res=$ac_cv_search_strerror +if test "$ac_res" != no; then + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:$LINENO: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done +done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:$LINENO: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done +done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +{ $as_echo "$as_me:$LINENO: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if test "${ac_cv_c_inline+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_inline=$ac_kw +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:$LINENO: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.2.6b' +macro_revision='1.3017' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +{ $as_echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if test "${ac_cv_path_SED+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + $as_unset ac_script || ac_script= + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done +done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + { { $as_echo "$as_me:$LINENO: error: no acceptable sed could be found in \$PATH" >&5 +$as_echo "$as_me: error: no acceptable sed could be found in \$PATH" >&2;} + { (exit 1); exit 1; }; } + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:$LINENO: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if test "${ac_cv_path_FGREP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done +done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + { { $as_echo "$as_me:$LINENO: error: no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +$as_echo "$as_me: error: no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:$LINENO: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:$LINENO: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && { { $as_echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +$as_echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +{ $as_echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:$LINENO: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if test "${lt_cv_path_NM+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$ac_tool_prefix"; then + for ac_prog in "dumpbin -symbols" "link -dump -symbols" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DUMPBIN+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:$LINENO: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in "dumpbin -symbols" "link -dump -symbols" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:$LINENO: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if test "${lt_cv_nm_interface+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:5928: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:5931: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:5934: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:$LINENO: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if test "${lt_cv_sys_max_cmd_len+set}" = set; then + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ + = "XX$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:$LINENO: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:$LINENO: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:$LINENO: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:$LINENO: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:$LINENO: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if test "${lt_cv_ld_reload_flag+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OBJDUMP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:$LINENO: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:$LINENO: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if test "${lt_cv_deplibs_check_method+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AR+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:$LINENO: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:$LINENO: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:$LINENO: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:$LINENO: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:$LINENO: result: ok" >&5 +$as_echo "ok" >&6; } +fi + + + + + + + + + + + + + + + + + + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 7139 "configure"' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if test "${lt_cv_cc_needs_belf+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + lt_cv_cc_needs_belf=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + lt_cv_cc_needs_belf=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DSYMUTIL+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:$LINENO: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_NMEDIT+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:$LINENO: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_LIPO+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:$LINENO: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:$LINENO: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL64+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:$LINENO: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:$LINENO: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if test "${lt_cv_apple_cc_single_mod+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + { $as_echo "$as_me:$LINENO: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if test "${lt_cv_ld_exported_symbols_list+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + lt_cv_ld_exported_symbols_list=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + lt_cv_ld_exported_symbols_list=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in dlfcn.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:$LINENO: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:$LINENO: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CXXFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:$LINENO: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +_lt_caught_CXX_error=yes; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + + + + + +# Set options + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then + withval=$with_pic; pic_mode="$withval" +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:$LINENO: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if test "${lt_cv_objdir+set}" = set; then + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + + + + + + + + + + + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:$LINENO: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag=' -fno-builtin' + + { $as_echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:9315: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:9319: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +{ $as_echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl*) + # IBM XL C 8.0/Fortran 10.1 on PPC + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Sun\ F*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac +{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5 +$as_echo "$lt_prog_compiler_pic" >&6; } + + + + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if test "${lt_cv_prog_compiler_pic_works+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:9654: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:9658: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test "${lt_cv_prog_compiler_static_works+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:9759: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:9763: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:9814: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:9818: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:$LINENO: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag= + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld='-rpath $libdir' + archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + whole_archive_flag_spec='' + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat >conftest.$ac_ext <<_ACEOF +int foo(void) {} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:$LINENO: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc=no + else + archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + { $as_echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5 +$as_echo "$archive_cmds_need_lc" >&6; } + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` + else + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then + shlibpath_overrides_runpath=yes +fi + +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:$LINENO: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_dl_dlopen=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dl_dlopen=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + { $as_echo "$as_me:$LINENO: checking for shl_load" >&5 +$as_echo_n "checking for shl_load... " >&6; } +if test "${ac_cv_func_shl_load+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define shl_load to an innocuous variant, in case declares shl_load. + For example, HP-UX 11i declares gettimeofday. */ +#define shl_load innocuous_shl_load + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shl_load (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef shl_load + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_shl_load || defined __stub___shl_load +choke me +#endif + +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_shl_load=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_shl_load=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 +$as_echo "$ac_cv_func_shl_load" >&6; } +if test "x$ac_cv_func_shl_load" = x""yes; then + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if test "${ac_cv_lib_dld_shl_load+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_dld_shl_load=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dld_shl_load=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = x""yes; then + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + { $as_echo "$as_me:$LINENO: checking for dlopen" >&5 +$as_echo_n "checking for dlopen... " >&6; } +if test "${ac_cv_func_dlopen+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define dlopen to an innocuous variant, in case declares dlopen. + For example, HP-UX 11i declares gettimeofday. */ +#define dlopen innocuous_dlopen + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char dlopen (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef dlopen + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_dlopen || defined __stub___dlopen +choke me +#endif + +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_dlopen=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_dlopen=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 +$as_echo "$ac_cv_func_dlopen" >&6; } +if test "x$ac_cv_func_dlopen" = x""yes; then + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_dl_dlopen=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dl_dlopen=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if test "${ac_cv_lib_svld_dlopen+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_svld_dlopen=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_svld_dlopen=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = x""yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if test "${ac_cv_lib_dld_dld_link+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_dld_dld_link=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dld_dld_link=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = x""yes; then + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 12617 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self_static+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 12713 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:$LINENO: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:$LINENO: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:$LINENO: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:$LINENO: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_flag_spec_ld_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + + # save warnings/boilerplate of simple test code + ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + + ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + compiler=$CC + compiler_CXX=$CC + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:$LINENO: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:$LINENO: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && { { $as_echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +$as_echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +{ $as_echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec_CXX='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + whole_archive_flag_spec_CXX='' + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=echo + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + + else + ld_shlibs_CXX=no + fi + + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + gnu*) + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5]* | *pgcpp\ [1-5]*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + old_archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 will use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + xl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object_CXX=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + ld_shlibs_CXX=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=echo + else + ld_shlibs_CXX=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test "$ld_shlibs_CXX" = no && can_build_shared=no + + GCC_CXX="$GXX" + LD_CXX="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + +{ $as_echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC*) + # IBM XL 8.0 on PPC + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac +{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_prog_compiler_pic_CXX" >&6; } + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if test "${lt_cv_prog_compiler_pic_works_CXX+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:14733: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:14737: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $as_echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test "${lt_cv_prog_compiler_static_works_CXX+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + + + + { $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:14832: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:14836: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + { $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:14884: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:14888: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:$LINENO: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + { $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + +{ $as_echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_CXX=no + else + archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + { $as_echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5 +$as_echo "$archive_cmds_need_lc_CXX" >&6; } + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then + shlibpath_overrides_runpath=yes +fi + +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink || + test "$inherit_rpath_CXX" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + +# Check whether --enable-tests was given. +if test "${enable_tests+set}" = set; then + enableval=$enable_tests; enable_tests=$enableval +else + enable_tests=$USE_MAINTAINER_MODE +fi + +# Check whether --enable-ansi was given. +if test "${enable_ansi+set}" = set; then + enableval=$enable_ansi; enable_ansi=$enableval +else + enable_ansi=no +fi + +# Check whether --enable-verbose-mode was given. +if test "${enable_verbose_mode+set}" = set; then + enableval=$enable_verbose_mode; enable_verbose_mode=$enableval +else + enable_verbose_mode=$USE_MAINTAINER_MODE +fi + +# Check whether --enable-asserts was given. +if test "${enable_asserts+set}" = set; then + enableval=$enable_asserts; enable_asserts=$enableval +else + enable_asserts=$USE_MAINTAINER_MODE +fi + +# Check whether --enable-checks was given. +if test "${enable_checks+set}" = set; then + enableval=$enable_checks; enable_checks=$enableval +else + enable_checks=yes +fi + +# Check whether --enable-xml-docs was given. +if test "${enable_xml_docs+set}" = set; then + enableval=$enable_xml_docs; enable_xml_docs=$enableval +else + enable_xml_docs=auto +fi + +# Check whether --enable-doxygen-docs was given. +if test "${enable_doxygen_docs+set}" = set; then + enableval=$enable_doxygen_docs; enable_doxygen_docs=$enableval +else + enable_doxygen_docs=auto +fi + +# Check whether --enable-gcov was given. +if test "${enable_gcov+set}" = set; then + enableval=$enable_gcov; enable_gcov=$enableval +else + enable_gcov=no +fi + +# Check whether --enable-abstract-sockets was given. +if test "${enable_abstract_sockets+set}" = set; then + enableval=$enable_abstract_sockets; enable_abstract_sockets=$enableval +else + enable_abstract_sockets=auto +fi + +# Check whether --enable-selinux was given. +if test "${enable_selinux+set}" = set; then + enableval=$enable_selinux; enable_selinux=$enableval +else + enable_selinux=auto +fi + +# Check whether --enable-libaudit was given. +if test "${enable_libaudit+set}" = set; then + enableval=$enable_libaudit; enable_libaudit=$enableval +else + enable_libaudit=auto +fi + +# Check whether --enable-dnotify was given. +if test "${enable_dnotify+set}" = set; then + enableval=$enable_dnotify; enable_dnotify=$enableval +else + enable_dnotify=auto +fi + +# Check whether --enable-inotify was given. +if test "${enable_inotify+set}" = set; then + enableval=$enable_inotify; enable_inotify=$enableval +else + enable_inotify=auto +fi + +# Check whether --enable-kqueue was given. +if test "${enable_kqueue+set}" = set; then + enableval=$enable_kqueue; enable_kqueue=$enableval +else + enable_kqueue=auto +fi + +# Check whether --enable-console-owner-file was given. +if test "${enable_console_owner_file+set}" = set; then + enableval=$enable_console_owner_file; enable_console_owner_file=$enableval +else + enable_console_owner_file=auto +fi + +# Check whether --enable-userdb-cache was given. +if test "${enable_userdb_cache+set}" = set; then + enableval=$enable_userdb_cache; enable_userdb_cache=$enableval +else + enable_userdb_cache=yes +fi + + + +# Check whether --with-xml was given. +if test "${with_xml+set}" = set; then + withval=$with_xml; +fi + + +# Check whether --with-init-scripts was given. +if test "${with_init_scripts+set}" = set; then + withval=$with_init_scripts; +fi + + +# Check whether --with-session-socket-dir was given. +if test "${with_session_socket_dir+set}" = set; then + withval=$with_session_socket_dir; +fi + + +# Check whether --with-test-socket-dir was given. +if test "${with_test_socket_dir+set}" = set; then + withval=$with_test_socket_dir; +fi + + +# Check whether --with-system-pid-file was given. +if test "${with_system_pid_file+set}" = set; then + withval=$with_system_pid_file; +fi + + +# Check whether --with-system-socket was given. +if test "${with_system_socket+set}" = set; then + withval=$with_system_socket; +fi + + +# Check whether --with-console-auth-dir was given. +if test "${with_console_auth_dir+set}" = set; then + withval=$with_console_auth_dir; +fi + + +# Check whether --with-console-owner-file was given. +if test "${with_console_owner_file+set}" = set; then + withval=$with_console_owner_file; +fi + + +# Check whether --with-dbus_user was given. +if test "${with_dbus_user+set}" = set; then + withval=$with_dbus_user; +fi + + +# Check whether --with-dbus_daemondir was given. +if test "${with_dbus_daemondir+set}" = set; then + withval=$with_dbus_daemondir; +fi + + + +cat >>confdefs.h <<\_ACEOF +#define DBUS_UNIX 1 +_ACEOF + + + if test x$enable_tests = xyes; then + DBUS_BUILD_TESTS_TRUE= + DBUS_BUILD_TESTS_FALSE='#' +else + DBUS_BUILD_TESTS_TRUE='#' + DBUS_BUILD_TESTS_FALSE= +fi + +if test x$enable_tests = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define DBUS_BUILD_TESTS 1 +_ACEOF + +fi + +if test x$enable_verbose_mode = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define DBUS_ENABLE_VERBOSE_MODE 1 +_ACEOF + +fi + +if test x$enable_asserts = xno; then + +cat >>confdefs.h <<\_ACEOF +#define DBUS_DISABLE_ASSERT 1 +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define G_DISABLE_ASSERT 1 +_ACEOF + + R_DYNAMIC_LDFLAG="" +else + # -rdynamic is needed for glibc's backtrace_symbols to work. + # No clue how much overhead this adds, but it's useful + # to do this on any assertion failure, + # so for now it's enabled anytime asserts are (currently not + # in production builds). + + # To get -rdynamic you pass -export-dynamic to libtool. + +cat >>confdefs.h <<\_ACEOF +#define DBUS_BUILT_R_DYNAMIC 1 +_ACEOF + + R_DYNAMIC_LDFLAG=-export-dynamic +fi + + +if test x$enable_checks = xno; then + +cat >>confdefs.h <<\_ACEOF +#define DBUS_DISABLE_CHECKS 1 +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define G_DISABLE_CHECKS 1 +_ACEOF + +fi + +if test x$enable_userdb_cache = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define DBUS_ENABLE_USERDB_CACHE 1 +_ACEOF + +fi + +if test x$enable_gcov = xyes; then + ## so that config.h changes when you toggle gcov support + +cat >>confdefs.h <<_ACEOF +#define DBUS_GCOV_ENABLED 1 +_ACEOF + + + { $as_echo "$as_me:$LINENO: checking for gcc 3.3 version of gcov file format" >&5 +$as_echo_n "checking for gcc 3.3 version of gcov file format... " >&6; } + have_gcc33_gcov=no + if test "$cross_compiling" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot run test program while cross compiling +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot run test program while cross compiling +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + if (__GNUC__ >=3 && __GNUC_MINOR__ >= 3) exit (0); else exit (1); + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + have_gcc33_gcov=yes +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + + if test x$have_gcc33_gcov = xyes ; then + +cat >>confdefs.h <<_ACEOF +#define DBUS_HAVE_GCC33_GCOV 1 +_ACEOF + + fi + { $as_echo "$as_me:$LINENO: result: $have_gcc33_gcov" >&5 +$as_echo "$have_gcc33_gcov" >&6; } +fi + if test x$enable_gcov = xyes; then + DBUS_GCOV_ENABLED_TRUE= + DBUS_GCOV_ENABLED_FALSE='#' +else + DBUS_GCOV_ENABLED_TRUE='#' + DBUS_GCOV_ENABLED_FALSE= +fi + + +# glibc21.m4 serial 3 + +# Test for the GNU C Library, version 2.1 or newer. +# From Bruno Haible. + +{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C Library 2.1 or newer" >&5 +$as_echo_n "checking whether we are using the GNU C Library 2.1 or newer... " >&6; } +if test "${ac_cv_gnu_library_2_1+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) + Lucky GNU user + #endif +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "Lucky GNU user" >/dev/null 2>&1; then + ac_cv_gnu_library_2_1=yes +else + ac_cv_gnu_library_2_1=no +fi +rm -f conftest* + + + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_gnu_library_2_1" >&5 +$as_echo "$ac_cv_gnu_library_2_1" >&6; } + +#### Integer sizes + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:$LINENO: checking size of char" >&5 +$as_echo_n "checking size of char... " >&6; } +if test "${ac_cv_sizeof_char+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (char))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (char))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (char))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (char))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (char))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_char=$ac_lo;; +'') if test "$ac_cv_type_char" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (char) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (char) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof_char=0 + fi ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +static long int longval () { return (long int) (sizeof (char)); } +static unsigned long int ulongval () { return (long int) (sizeof (char)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (char))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (char)))) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (char)))) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_char=`cat conftest.val` +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +if test "$ac_cv_type_char" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (char) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (char) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof_char=0 + fi +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_sizeof_char" >&5 +$as_echo "$ac_cv_sizeof_char" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_CHAR $ac_cv_sizeof_char +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:$LINENO: checking size of short" >&5 +$as_echo_n "checking size of short... " >&6; } +if test "${ac_cv_sizeof_short+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (short))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (short))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (short))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (short))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (short))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_short=$ac_lo;; +'') if test "$ac_cv_type_short" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (short) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (short) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof_short=0 + fi ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +static long int longval () { return (long int) (sizeof (short)); } +static unsigned long int ulongval () { return (long int) (sizeof (short)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (short))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (short)))) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (short)))) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_short=`cat conftest.val` +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +if test "$ac_cv_type_short" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (short) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (short) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof_short=0 + fi +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_sizeof_short" >&5 +$as_echo "$ac_cv_sizeof_short" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_SHORT $ac_cv_sizeof_short +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:$LINENO: checking size of long" >&5 +$as_echo_n "checking size of long... " >&6; } +if test "${ac_cv_sizeof_long+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (long))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (long))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (long))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (long))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (long))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_long=$ac_lo;; +'') if test "$ac_cv_type_long" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (long) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (long) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof_long=0 + fi ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +static long int longval () { return (long int) (sizeof (long)); } +static unsigned long int ulongval () { return (long int) (sizeof (long)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (long))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (long)))) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (long)))) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_long=`cat conftest.val` +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +if test "$ac_cv_type_long" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (long) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (long) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof_long=0 + fi +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5 +$as_echo "$ac_cv_sizeof_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG $ac_cv_sizeof_long +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:$LINENO: checking size of int" >&5 +$as_echo_n "checking size of int... " >&6; } +if test "${ac_cv_sizeof_int+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (int))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (int))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (int))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (int))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (int))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_int=$ac_lo;; +'') if test "$ac_cv_type_int" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (int) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (int) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof_int=0 + fi ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +static long int longval () { return (long int) (sizeof (int)); } +static unsigned long int ulongval () { return (long int) (sizeof (int)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (int))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (int)))) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (int)))) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_int=`cat conftest.val` +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +if test "$ac_cv_type_int" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (int) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (int) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof_int=0 + fi +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5 +$as_echo "$ac_cv_sizeof_int" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_INT $ac_cv_sizeof_int +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:$LINENO: checking size of void *" >&5 +$as_echo_n "checking size of void *... " >&6; } +if test "${ac_cv_sizeof_void_p+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (void *))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (void *))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (void *))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (void *))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (void *))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_void_p=$ac_lo;; +'') if test "$ac_cv_type_void_p" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (void *) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (void *) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof_void_p=0 + fi ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +static long int longval () { return (long int) (sizeof (void *)); } +static unsigned long int ulongval () { return (long int) (sizeof (void *)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (void *))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (void *)))) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (void *)))) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_void_p=`cat conftest.val` +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +if test "$ac_cv_type_void_p" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (void *) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (void *) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof_void_p=0 + fi +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_sizeof_void_p" >&5 +$as_echo "$ac_cv_sizeof_void_p" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_VOID_P $ac_cv_sizeof_void_p +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:$LINENO: checking size of long long" >&5 +$as_echo_n "checking size of long long... " >&6; } +if test "${ac_cv_sizeof_long_long+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (long long))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (long long))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (long long))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (long long))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (long long))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_long_long=$ac_lo;; +'') if test "$ac_cv_type_long_long" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (long long) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (long long) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof_long_long=0 + fi ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +static long int longval () { return (long int) (sizeof (long long)); } +static unsigned long int ulongval () { return (long int) (sizeof (long long)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (long long))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (long long)))) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (long long)))) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_long_long=`cat conftest.val` +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +if test "$ac_cv_type_long_long" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (long long) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (long long) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof_long_long=0 + fi +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_long" >&5 +$as_echo "$ac_cv_sizeof_long_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long +_ACEOF + + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:$LINENO: checking size of __int64" >&5 +$as_echo_n "checking size of __int64... " >&6; } +if test "${ac_cv_sizeof___int64+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (__int64))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (__int64))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (__int64))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (__int64))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=$ac_mid; break +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (__int64))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof___int64=$ac_lo;; +'') if test "$ac_cv_type___int64" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (__int64) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (__int64) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof___int64=0 + fi ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +static long int longval () { return (long int) (sizeof (__int64)); } +static unsigned long int ulongval () { return (long int) (sizeof (__int64)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (__int64))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (__int64)))) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (__int64)))) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof___int64=`cat conftest.val` +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +if test "$ac_cv_type___int64" = yes; then + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute sizeof (__int64) +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute sizeof (__int64) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } + else + ac_cv_sizeof___int64=0 + fi +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_sizeof___int64" >&5 +$as_echo "$ac_cv_sizeof___int64" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF___INT64 $ac_cv_sizeof___int64 +_ACEOF + + + +### See what our 64 bit type is called +{ $as_echo "$as_me:$LINENO: checking 64-bit integer type" >&5 +$as_echo_n "checking 64-bit integer type... " >&6; } + +case 8 in +$ac_cv_sizeof_int) + dbusint64=int + dbusint64_constant='(val)' + dbusuint64_constant='(val)' + dbusint64_printf_modifier='""' + ;; +$ac_cv_sizeof_long) + dbusint64=long + dbusint64_constant='(val##L)' + dbusuint64_constant='(val##UL)' + dbusint64_printf_modifier='"l"' + ;; +$ac_cv_sizeof_long_long) + dbusint64='long long' + dbusint64_constant='(val##LL)' + dbusuint64_constant='(val##ULL)' + # Ideally we discover what the format is, but this is + # only used in verbose mode, so eh... + if test x"$ac_cv_gnu_library_2_1" = xyes; then + dbusint64_printf_modifier='"ll"' + fi + ;; +$ac_cv_sizeof___int64) + dbusint64=__int64 + dbusint64_constant='(val##i64)' + dbusuint64_constant='(val##ui64)' + # See above case + if test x"$ac_cv_gnu_library_2_1" = xyes; then + dbusint64_printf_modifier='"ll"' + fi + ;; +esac + +if test -z "$dbusint64" ; then + DBUS_INT64_TYPE="no_int64_type_detected" + DBUS_HAVE_INT64=0 + DBUS_INT64_CONSTANT= + DBUS_UINT64_CONSTANT= + { $as_echo "$as_me:$LINENO: result: none found" >&5 +$as_echo "none found" >&6; } +else + DBUS_INT64_TYPE="$dbusint64" + DBUS_HAVE_INT64=1 + DBUS_INT64_CONSTANT="$dbusint64_constant" + DBUS_UINT64_CONSTANT="$dbusuint64_constant" + if test x"$dbusint64_printf_modifier" != x; then + +cat >>confdefs.h <<_ACEOF +#define DBUS_INT64_PRINTF_MODIFIER $dbusint64_printf_modifier +_ACEOF + + fi + { $as_echo "$as_me:$LINENO: result: $DBUS_INT64_TYPE" >&5 +$as_echo "$DBUS_INT64_TYPE" >&6; } +fi + + + + + + +### see what 32-bit int is called +{ $as_echo "$as_me:$LINENO: checking 32-bit integer type" >&5 +$as_echo_n "checking 32-bit integer type... " >&6; } + +case 4 in +$ac_cv_sizeof_short) + dbusint32=int + ;; +$ac_cv_sizeof_int) + dbusint32=int + ;; +$ac_cv_sizeof_long) + dbusint32=long + ;; +esac + +if test -z "$dbusint32" ; then + DBUS_INT32_TYPE="no_int32_type_detected" + { { $as_echo "$as_me:$LINENO: error: No 32-bit integer type found" >&5 +$as_echo "$as_me: error: No 32-bit integer type found" >&2;} + { (exit 1); exit 1; }; } +else + DBUS_INT32_TYPE="$dbusint32" + { $as_echo "$as_me:$LINENO: result: $DBUS_INT32_TYPE" >&5 +$as_echo "$DBUS_INT32_TYPE" >&6; } +fi + + + +### see what 16-bit int is called +{ $as_echo "$as_me:$LINENO: checking 16-bit integer type" >&5 +$as_echo_n "checking 16-bit integer type... " >&6; } + +case 2 in +$ac_cv_sizeof_short) + dbusint16=short + ;; +$ac_cv_sizeof_int) + dbusint16=int + ;; +esac + +if test -z "$dbusint16" ; then + DBUS_INT16_TYPE="no_int16_type_detected" + { { $as_echo "$as_me:$LINENO: error: No 16-bit integer type found" >&5 +$as_echo "$as_me: error: No 16-bit integer type found" >&2;} + { (exit 1); exit 1; }; } +else + DBUS_INT16_TYPE="$dbusint16" + { $as_echo "$as_me:$LINENO: result: $DBUS_INT16_TYPE" >&5 +$as_echo "$DBUS_INT16_TYPE" >&6; } +fi + + + +## byte order +case $host_os in + darwin*) + # check at compile-time, so that it is possible to build universal + # (with multiple architectures at once on the compile line) + + + ;; + *) + + { $as_echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if test "${ac_cv_c_bigendian+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + + # Check for potential -arch flags. It is not universal unless + # there are some -arch flags. Note that *ppc* also matches + # ppc64. This check is also rather less than ideal. + case "${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS}" in #( + *-arch*ppc*|*-arch*i386*|*-arch*x86_64*) ac_cv_c_bigendian=universal;; + esac +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + # It does; now see whether it defined to BIG_ENDIAN or not. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_bigendian=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_bigendian=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_bigendian=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_bigendian=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then + # Try to guess by grepping values from an object file. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=no +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_c_bigendian=yes +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + + fi +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + cat >>confdefs.h <<\_ACEOF +#define WORDS_BIGENDIAN 1 +_ACEOF +;; #( + no) + ;; #( + universal) + +cat >>confdefs.h <<\_ACEOF +#define AC_APPLE_UNIVERSAL_BUILD 1 +_ACEOF + + ;; #( + *) + { { $as_echo "$as_me:$LINENO: error: unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" >&5 +$as_echo "$as_me: error: unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} + { (exit 1); exit 1; }; } ;; + esac + + ;; +esac + +{ $as_echo "$as_me:$LINENO: checking for an implementation of va_copy()" >&5 +$as_echo_n "checking for an implementation of va_copy()... " >&6; } +if test "${dbus_cv_va_copy+set}" = set; then + $as_echo_n "(cached) " >&6 +else + + cat >conftest.$ac_ext <<_ACEOF +#include +#include + static void f (int i, ...) { + va_list args1, args2; + va_start (args1, i); + va_copy (args2, args1); + if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) + exit (1); + va_end (args1); va_end (args2); + } + int main() { + f (0, 42); + return 0; + } +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + dbus_cv_va_copy=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + dbus_cv_va_copy=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ $as_echo "$as_me:$LINENO: result: $dbus_cv_va_copy" >&5 +$as_echo "$dbus_cv_va_copy" >&6; } +{ $as_echo "$as_me:$LINENO: checking for an implementation of __va_copy()" >&5 +$as_echo_n "checking for an implementation of __va_copy()... " >&6; } +if test "${dbus_cv___va_copy+set}" = set; then + $as_echo_n "(cached) " >&6 +else + + cat >conftest.$ac_ext <<_ACEOF +#include +#include + static void f (int i, ...) { + va_list args1, args2; + va_start (args1, i); + __va_copy (args2, args1); + if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) + exit (1); + va_end (args1); va_end (args2); + } + int main() { + f (0, 42); + return 0; + } +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + dbus_cv___va_copy=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + dbus_cv___va_copy=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ $as_echo "$as_me:$LINENO: result: $dbus_cv___va_copy" >&5 +$as_echo "$dbus_cv___va_copy" >&6; } + +if test "x$dbus_cv_va_copy" = "xyes"; then + dbus_va_copy_func=va_copy +else if test "x$dbus_cv___va_copy" = "xyes"; then + dbus_va_copy_func=__va_copy +fi +fi + +if test -n "$dbus_va_copy_func"; then + +cat >>confdefs.h <<_ACEOF +#define DBUS_VA_COPY $dbus_va_copy_func +_ACEOF + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +{ $as_echo "$as_me:$LINENO: checking whether va_lists can be copied by value" >&5 +$as_echo_n "checking whether va_lists can be copied by value... " >&6; } +if test "${dbus_cv_va_val_copy+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then + dbus_cv_va_val_copy=yes +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + #include + #include + +int +main () +{ + + static void f (int i, ...) { + va_list args1, args2; + va_start (args1, i); + args2 = args1; + if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) + exit (1); + va_end (args1); va_end (args2); + } + int main() { + f (0, 42); + return 0; + } + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + dbus_cv_va_val_copy=yes +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +dbus_cv_va_val_copy=no +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + + +fi +{ $as_echo "$as_me:$LINENO: result: $dbus_cv_va_val_copy" >&5 +$as_echo "$dbus_cv_va_val_copy" >&6; } +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +if test "x$dbus_cv_va_val_copy" = "xno"; then + +cat >>confdefs.h <<\_ACEOF +#define DBUS_VA_COPY_AS_ARRAY 1 +_ACEOF + +fi + + +#### Atomic integers (checks by Sebastian Wilhelmi for GLib) +{ $as_echo "$as_me:$LINENO: checking whether to use inline assembler routines for atomic integers" >&5 +$as_echo_n "checking whether to use inline assembler routines for atomic integers... " >&6; } +have_atomic_inc_cond=0 +if test x"$GCC" = xyes; then + if test "x$enable_ansi" = "xyes"; then + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + else + case $host_cpu in + i386) + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + ;; + i?86) + case $host_os in + darwin*) + { $as_echo "$as_me:$LINENO: result: darwin" >&5 +$as_echo "darwin" >&6; } + # check at compile-time, so that it is possible to build universal + # (with multiple architectures at once on the compile line) + have_atomic_inc_cond="(defined(__i386__) || defined(__x86_64__))" + ;; + *) + { $as_echo "$as_me:$LINENO: result: i486" >&5 +$as_echo "i486" >&6; } + have_atomic_inc_cond=1 + ;; + esac + ;; + *) + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac + fi +fi + +cat >>confdefs.h <<_ACEOF +#define DBUS_USE_ATOMIC_INT_486_COND $have_atomic_inc_cond +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define DBUS_HAVE_ATOMIC_INT_COND $have_atomic_inc_cond +_ACEOF + + +#### Various functions +{ $as_echo "$as_me:$LINENO: checking for library containing socket" >&5 +$as_echo_n "checking for library containing socket... " >&6; } +if test "${ac_cv_search_socket+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char socket (); +int +main () +{ +return socket (); + ; + return 0; +} +_ACEOF +for ac_lib in '' socket network; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_search_socket=$ac_res +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext + if test "${ac_cv_search_socket+set}" = set; then + break +fi +done +if test "${ac_cv_search_socket+set}" = set; then + : +else + ac_cv_search_socket=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_socket" >&5 +$as_echo "$ac_cv_search_socket" >&6; } +ac_res=$ac_cv_search_socket +if test "$ac_res" != no; then + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +{ $as_echo "$as_me:$LINENO: checking for gethostbyname" >&5 +$as_echo_n "checking for gethostbyname... " >&6; } +if test "${ac_cv_func_gethostbyname+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define gethostbyname to an innocuous variant, in case declares gethostbyname. + For example, HP-UX 11i declares gettimeofday. */ +#define gethostbyname innocuous_gethostbyname + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char gethostbyname (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef gethostbyname + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_gethostbyname || defined __stub___gethostbyname +choke me +#endif + +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_gethostbyname=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_gethostbyname=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5 +$as_echo "$ac_cv_func_gethostbyname" >&6; } +if test "x$ac_cv_func_gethostbyname" = x""yes; then + : +else + +{ $as_echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5 +$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } +if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_nsl_gethostbyname=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_nsl_gethostbyname=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5 +$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } +if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNSL 1 +_ACEOF + + LIBS="-lnsl $LIBS" + +fi + +fi + + + + + + + + + + + + + + +for ac_func in vsnprintf vasprintf nanosleep usleep setenv clearenv unsetenv socketpair getgrouplist fpathconf setrlimit poll +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +#### Check for broken poll; taken from Glib's configure + +{ $as_echo "$as_me:$LINENO: checking for broken poll" >&5 +$as_echo_n "checking for broken poll... " >&6; } +if test "$cross_compiling" = yes; then + broken_poll="no (cross compiling)" +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + #include + #include + #include + #ifdef HAVE_SYS_POLL_H + #include + #endif + int main(void) { + struct pollfd fds[1]; + int fd; + fd = open("/dev/null", 1); + fds[0].fd = fd; + fds[0].events = POLLIN; + fds[0].revents = 0; + if (poll(fds, 1, 0) < 0 || (fds[0].revents & POLLNVAL) != 0) { + exit(1); /* Does not work for devices -- fail */ + } + exit(0); + } +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + broken_poll=no +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +broken_poll=yes + +cat >>confdefs.h <<\_ACEOF +#define BROKEN_POLL 1 +_ACEOF + +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +{ $as_echo "$as_me:$LINENO: result: $broken_poll" >&5 +$as_echo "$broken_poll" >&6; } + +{ $as_echo "$as_me:$LINENO: checking for dirfd" >&5 +$as_echo_n "checking for dirfd... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include + +int +main () +{ + +DIR *dirp; +dirp = opendir("."); +dirfd(dirp); +closedir(dirp); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + dbus_have_dirfd=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + dbus_have_dirfd=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $dbus_have_dirfd" >&5 +$as_echo "$dbus_have_dirfd" >&6; } +if test "$dbus_have_dirfd" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DIRFD 1 +_ACEOF + +else + { $as_echo "$as_me:$LINENO: checking for DIR *dirp->dd_fd" >&5 +$as_echo_n "checking for DIR *dirp->dd_fd... " >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include + +int +main () +{ + +DIR *dirp; +int fd; +dirp = opendir("."); +fd = dirp->dd_fd; +closedir(dirp); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + dbus_have_ddfd=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + dbus_have_ddfd=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + { $as_echo "$as_me:$LINENO: result: $dbus_have_ddfd" >&5 +$as_echo "$dbus_have_ddfd" >&6; } + if test "$dbus_have_ddfd" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DDFD 1 +_ACEOF + + fi +fi + + +for ac_header in execinfo.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +for ac_func in backtrace +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +fi + +done + + + +for ac_header in errno.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in unistd.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Add -D_POSIX_PTHREAD_SEMANTICS if on Solaris +# +case $host_os in + solaris*) + CFLAGS="$CFLAGS -D_POSIX_PTHREAD_SEMANTICS" ;; +esac + +# checking for a posix version of getpwnam_r +# if we are cross compiling and can not run the test +# assume getpwnam_r is the posix version +# it is up to the person cross compiling to change +# this behavior if desired +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +{ $as_echo "$as_me:$LINENO: checking for posix getpwnam_r" >&5 +$as_echo_n "checking for posix getpwnam_r... " >&6; } +if test "${ac_cv_func_posix_getpwnam_r+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_posix_getpwnam_r=yes + +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include + +int +main () +{ + + char buffer[10000]; + struct passwd pwd, *pwptr = &pwd; + int error; + errno = 0; + error = getpwnam_r ("", &pwd, buffer, + sizeof (buffer), &pwptr); + return (error < 0 && errno == ENOSYS) + || error == ENOSYS; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_posix_getpwnam_r=yes +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_posix_getpwnam_r=no +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_posix_getpwnam_r" >&5 +$as_echo "$ac_cv_func_posix_getpwnam_r" >&6; } +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +if test "$ac_cv_func_posix_getpwnam_r" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_POSIX_GETPWNAM_R 1 +_ACEOF + +else + { $as_echo "$as_me:$LINENO: checking for nonposix getpwnam_r" >&5 +$as_echo_n "checking for nonposix getpwnam_r... " >&6; } +if test "${ac_cv_func_nonposix_getpwnam_r+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +char buffer[10000]; + struct passwd pwd; + getpwnam_r ("", &pwd, buffer, + sizeof (buffer)); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_nonposix_getpwnam_r=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_nonposix_getpwnam_r=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_nonposix_getpwnam_r" >&5 +$as_echo "$ac_cv_func_nonposix_getpwnam_r" >&6; } + if test "$ac_cv_func_nonposix_getpwnam_r" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_NONPOSIX_GETPWNAM_R 1 +_ACEOF + + fi +fi + +{ $as_echo "$as_me:$LINENO: checking whether socklen_t is defined" >&5 +$as_echo_n "checking whether socklen_t is defined... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include +#include + +int +main () +{ + +socklen_t foo; +foo = 1; + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + dbus_have_socklen_t=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + dbus_have_socklen_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $dbus_have_socklen_t" >&5 +$as_echo "$dbus_have_socklen_t" >&6; } + +if test "x$dbus_have_socklen_t" = "xyes"; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SOCKLEN_T 1 +_ACEOF + +fi + + +for ac_header in sys/uio.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +for ac_func in writev +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +fi + +done + + + +for ac_header in sys/syslimits.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ $as_echo "$as_me:$LINENO: checking for ISO C99 varargs macros in C" >&5 +$as_echo_n "checking for ISO C99 varargs macros in C... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + +int a(int p1, int p2, int p3); +#define call_a(...) a(1,__VA_ARGS__) +call_a(2,3); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + dbus_have_iso_c_varargs=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + dbus_have_iso_c_varargs=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $dbus_have_iso_c_varargs" >&5 +$as_echo "$dbus_have_iso_c_varargs" >&6; } + +{ $as_echo "$as_me:$LINENO: checking for GNUC varargs macros" >&5 +$as_echo_n "checking for GNUC varargs macros... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + +int a(int p1, int p2, int p3); +#define call_a(params...) a(1,params) +call_a(2,3); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + dbus_have_gnuc_varargs=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + dbus_have_gnuc_varargs=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $dbus_have_gnuc_varargs" >&5 +$as_echo "$dbus_have_gnuc_varargs" >&6; } + +if test x$dbus_have_iso_c_varargs = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_ISO_VARARGS 1 +_ACEOF + +fi +if test x$dbus_have_gnuc_varargs = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_GNUC_VARARGS 1 +_ACEOF + +fi + +{ $as_echo "$as_me:$LINENO: checking for struct cmsgcred" >&5 +$as_echo_n "checking for struct cmsgcred... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include + +int +main () +{ + +struct cmsgcred cred; + +cred.cmcred_pid = 0; + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + dbus_have_struct_cmsgcred=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + dbus_have_struct_cmsgcred=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $dbus_have_struct_cmsgcred" >&5 +$as_echo "$dbus_have_struct_cmsgcred" >&6; } + +if test x$dbus_have_struct_cmsgcred = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_CMSGCRED 1 +_ACEOF + +fi + + + +for ac_func in getpeerucred getpeereid +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +#### Abstract sockets + +if test x$enable_abstract_sockets = xauto; then +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +warn_on_xcompile=no +{ $as_echo "$as_me:$LINENO: checking abstract socket namespace" >&5 +$as_echo_n "checking abstract socket namespace... " >&6; } +if test "${ac_cv_have_abstract_sockets+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then + + ac_cv_have_abstract_sockets=no + warn_on_xcompile=yes + + +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include +#include +#include +#include +#include +#include + +int +main () +{ + + int listen_fd; + struct sockaddr_un addr; + + listen_fd = socket (PF_UNIX, SOCK_STREAM, 0); + + if (listen_fd < 0) + { + fprintf (stderr, "socket() failed: %s\n", strerror (errno)); + exit (1); + } + + memset (&addr, '\0', sizeof (addr)); + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, "X/tmp/dbus-fake-socket-path-used-in-configure-test"); + addr.sun_path[0] = '\0'; /* this is what makes it abstract */ + + if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0) + { + fprintf (stderr, "Abstract socket namespace bind() failed: %s\n", + strerror (errno)); + exit (1); + } + else + exit (0); + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_have_abstract_sockets=yes +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_have_abstract_sockets=no +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_have_abstract_sockets" >&5 +$as_echo "$ac_cv_have_abstract_sockets" >&6; } +if test x$warn_on_xcompile = xyes ; then + { $as_echo "$as_me:$LINENO: WARNING: Cannot check for abstract sockets when cross-compiling, please use --enable-abstract-sockets" >&5 +$as_echo "$as_me: WARNING: Cannot check for abstract sockets when cross-compiling, please use --enable-abstract-sockets" >&2;} +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi + +if test x$enable_abstract_sockets = xyes; then + if test x$ac_cv_have_abstract_sockets = xno; then + { { $as_echo "$as_me:$LINENO: error: Abstract sockets explicitly required, and support not detected." >&5 +$as_echo "$as_me: error: Abstract sockets explicitly required, and support not detected." >&2;} + { (exit 1); exit 1; }; } + fi +fi + +if test x$enable_abstract_sockets = xno; then + ac_cv_have_abstract_sockets=no; +fi + +if test x$ac_cv_have_abstract_sockets = xyes ; then + DBUS_PATH_OR_ABSTRACT=abstract + +cat >>confdefs.h <<\_ACEOF +#define HAVE_ABSTRACT_SOCKETS 1 +_ACEOF + +else + DBUS_PATH_OR_ABSTRACT=path +fi + +# this is used in addresses to prefer abstract, e.g. +# unix:path=/foo or unix:abstract=/foo + + +#### Sort out XML library + +# see what we have +{ $as_echo "$as_me:$LINENO: checking for XML_ParserCreate_MM in -lexpat" >&5 +$as_echo_n "checking for XML_ParserCreate_MM in -lexpat... " >&6; } +if test "${ac_cv_lib_expat_XML_ParserCreate_MM+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lexpat $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XML_ParserCreate_MM (); +int +main () +{ +return XML_ParserCreate_MM (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_expat_XML_ParserCreate_MM=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_expat_XML_ParserCreate_MM=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_expat_XML_ParserCreate_MM" >&5 +$as_echo "$ac_cv_lib_expat_XML_ParserCreate_MM" >&6; } +if test "x$ac_cv_lib_expat_XML_ParserCreate_MM" = x""yes; then + +for ac_header in expat.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + have_expat=true +else + have_expat=false +fi + +done + +else + have_expat=false +fi + + +# see what we want to use +dbus_use_libxml=false +dbus_use_expat=false +if test x$with_xml = xexpat; then + if ! $have_expat ; then + { { $as_echo "$as_me:$LINENO: error: Explicitly requested expat but expat not found" >&5 +$as_echo "$as_me: error: Explicitly requested expat but expat not found" >&2;} + { (exit 1); exit 1; }; } + fi + dbus_use_expat=true +elif test x$with_xml = xlibxml; then + + succeeded=no + + if test -z "$PKG_CONFIG"; then + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_PKG_CONFIG+set}" = set; then + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no" + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + + if test "$PKG_CONFIG" = "no" ; then + echo "*** The pkg-config script could not be found. Make sure it is" + echo "*** in your path, or set the PKG_CONFIG environment variable" + echo "*** to the full path to pkg-config." + echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config." + else + PKG_CONFIG_MIN_VERSION=0.9.0 + if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then + { $as_echo "$as_me:$LINENO: checking for libxml-2.0 >= 2.6.0" >&5 +$as_echo_n "checking for libxml-2.0 >= 2.6.0... " >&6; } + + if $PKG_CONFIG --exists "libxml-2.0 >= 2.6.0" ; then + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + succeeded=yes + + { $as_echo "$as_me:$LINENO: checking LIBXML_CFLAGS" >&5 +$as_echo_n "checking LIBXML_CFLAGS... " >&6; } + LIBXML_CFLAGS=`$PKG_CONFIG --cflags "libxml-2.0 >= 2.6.0"` + { $as_echo "$as_me:$LINENO: result: $LIBXML_CFLAGS" >&5 +$as_echo "$LIBXML_CFLAGS" >&6; } + + { $as_echo "$as_me:$LINENO: checking LIBXML_LIBS" >&5 +$as_echo_n "checking LIBXML_LIBS... " >&6; } + LIBXML_LIBS=`$PKG_CONFIG --libs "libxml-2.0 >= 2.6.0"` + { $as_echo "$as_me:$LINENO: result: $LIBXML_LIBS" >&5 +$as_echo "$LIBXML_LIBS" >&6; } + else + LIBXML_CFLAGS="" + LIBXML_LIBS="" + ## If we have a custom action on failure, don't print errors, but + ## do set a variable so people can do so. + LIBXML_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "libxml-2.0 >= 2.6.0"` + + fi + + + + else + echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer." + echo "*** See http://www.freedesktop.org/software/pkgconfig" + fi + fi + + if test $succeeded = yes; then + have_libxml=true + else + have_libxml=false + fi + + if ! $have_libxml ; then + { { $as_echo "$as_me:$LINENO: error: Explicitly requested libxml but libxml not found" >&5 +$as_echo "$as_me: error: Explicitly requested libxml but libxml not found" >&2;} + { (exit 1); exit 1; }; } + fi + dbus_use_libxml=true +else + ### expat is the default because libxml can't currently survive + ### our brutal OOM-handling unit test setup. + ### http://bugzilla.gnome.org/show_bug.cgi?id=109368 + if test x$have_expat = xfalse; then + { { $as_echo "$as_me:$LINENO: error: Could not find expat.h, check config.log for failed attempts" >&5 +$as_echo "$as_me: error: Could not find expat.h, check config.log for failed attempts" >&2;} + { (exit 1); exit 1; }; } + fi + ### By default, only use Expat since it's tested and known to work. If you're a + ### general-purpose OS vendor, please don't enable libxml. For embedded use + ### if your OS is built around libxml, that's another case. + dbus_use_expat=true +fi + + if $dbus_use_expat; then + DBUS_USE_EXPAT_TRUE= + DBUS_USE_EXPAT_FALSE='#' +else + DBUS_USE_EXPAT_TRUE='#' + DBUS_USE_EXPAT_FALSE= +fi + + if $dbus_use_libxml; then + DBUS_USE_LIBXML_TRUE= + DBUS_USE_LIBXML_FALSE='#' +else + DBUS_USE_LIBXML_TRUE='#' + DBUS_USE_LIBXML_FALSE= +fi + + +if $dbus_use_expat; then + XML_LIBS=-lexpat + XML_CFLAGS= +fi +if $dbus_use_libxml; then + XML_LIBS=$LIBXML_LIBS + XML_CFLAGS=$LIBXML_CFLAGS +fi + +# Thread lib detection +{ $as_echo "$as_me:$LINENO: checking for pthread_cond_timedwait" >&5 +$as_echo_n "checking for pthread_cond_timedwait... " >&6; } +if test "${ac_cv_func_pthread_cond_timedwait+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define pthread_cond_timedwait to an innocuous variant, in case declares pthread_cond_timedwait. + For example, HP-UX 11i declares gettimeofday. */ +#define pthread_cond_timedwait innocuous_pthread_cond_timedwait + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char pthread_cond_timedwait (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef pthread_cond_timedwait + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_cond_timedwait (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_pthread_cond_timedwait || defined __stub___pthread_cond_timedwait +choke me +#endif + +int +main () +{ +return pthread_cond_timedwait (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_pthread_cond_timedwait=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_pthread_cond_timedwait=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_pthread_cond_timedwait" >&5 +$as_echo "$ac_cv_func_pthread_cond_timedwait" >&6; } +if test "x$ac_cv_func_pthread_cond_timedwait" = x""yes; then + { $as_echo "$as_me:$LINENO: checking for pthread_cond_timedwait in -lpthread" >&5 +$as_echo_n "checking for pthread_cond_timedwait in -lpthread... " >&6; } +if test "${ac_cv_lib_pthread_pthread_cond_timedwait+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_cond_timedwait (); +int +main () +{ +return pthread_cond_timedwait (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_pthread_pthread_cond_timedwait=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_pthread_pthread_cond_timedwait=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_cond_timedwait" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_cond_timedwait" >&6; } +if test "x$ac_cv_lib_pthread_pthread_cond_timedwait" = x""yes; then + THREAD_LIBS="-lpthread" +fi + +fi + +save_libs="$LIBS" +LIBS="$LIBS $THREAD_LIBS" +{ $as_echo "$as_me:$LINENO: checking for pthread_condattr_setclock" >&5 +$as_echo_n "checking for pthread_condattr_setclock... " >&6; } +if test "${ac_cv_func_pthread_condattr_setclock+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define pthread_condattr_setclock to an innocuous variant, in case declares pthread_condattr_setclock. + For example, HP-UX 11i declares gettimeofday. */ +#define pthread_condattr_setclock innocuous_pthread_condattr_setclock + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char pthread_condattr_setclock (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef pthread_condattr_setclock + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_condattr_setclock (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_pthread_condattr_setclock || defined __stub___pthread_condattr_setclock +choke me +#endif + +int +main () +{ +return pthread_condattr_setclock (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_pthread_condattr_setclock=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_pthread_condattr_setclock=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_pthread_condattr_setclock" >&5 +$as_echo "$ac_cv_func_pthread_condattr_setclock" >&6; } +if test "x$ac_cv_func_pthread_condattr_setclock" = x""yes; then + have_pthread_condattr_setclock=true +else + have_pthread_condattr_setclock=false +fi + +if test x$have_pthread_condattr_setclock = xtrue; then + { $as_echo "$as_me:$LINENO: checking for library containing clock_getres" >&5 +$as_echo_n "checking for library containing clock_getres... " >&6; } +if test "${ac_cv_search_clock_getres+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_getres (); +int +main () +{ +return clock_getres (); + ; + return 0; +} +_ACEOF +for ac_lib in '' rt; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_search_clock_getres=$ac_res +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext + if test "${ac_cv_search_clock_getres+set}" = set; then + break +fi +done +if test "${ac_cv_search_clock_getres+set}" = set; then + : +else + ac_cv_search_clock_getres=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_search_clock_getres" >&5 +$as_echo "$ac_cv_search_clock_getres" >&6; } +ac_res=$ac_cv_search_clock_getres +if test "$ac_res" != no; then + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + THREAD_LIBS="$THREAD_LIBS -lrt" +fi + + { $as_echo "$as_me:$LINENO: checking for CLOCK_MONOTONIC" >&5 +$as_echo_n "checking for CLOCK_MONOTONIC... " >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ + +struct timespec monotonic_timer; +pthread_condattr_t attr; +pthread_condattr_init (&attr); +pthread_condattr_setclock (&attr, CLOCK_MONOTONIC); +clock_getres (CLOCK_MONOTONIC,&monotonic_timer); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + have_clock_monotonic=true +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + have_clock_monotonic=false +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +if test x$have_clock_monotonic = xtrue; then + { $as_echo "$as_me:$LINENO: result: found" >&5 +$as_echo "found" >&6; } + +cat >>confdefs.h <<\_ACEOF +#define HAVE_MONOTONIC_CLOCK 1 +_ACEOF + +else + { $as_echo "$as_me:$LINENO: result: not found" >&5 +$as_echo "not found" >&6; } +fi +fi +LIBS="$save_libs" + +# SELinux detection +if test x$enable_selinux = xno ; then + have_selinux=no; +else + # See if we have SELinux library + { $as_echo "$as_me:$LINENO: checking for is_selinux_enabled in -lselinux" >&5 +$as_echo_n "checking for is_selinux_enabled in -lselinux... " >&6; } +if test "${ac_cv_lib_selinux_is_selinux_enabled+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lselinux $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char is_selinux_enabled (); +int +main () +{ +return is_selinux_enabled (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_selinux_is_selinux_enabled=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_selinux_is_selinux_enabled=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_is_selinux_enabled" >&5 +$as_echo "$ac_cv_lib_selinux_is_selinux_enabled" >&6; } +if test "x$ac_cv_lib_selinux_is_selinux_enabled" = x""yes; then + have_selinux=yes +else + have_selinux=no +fi + + + # see if we have the SELinux header with the new D-Bus stuff in it + if test x$have_selinux = xyes ; then + { $as_echo "$as_me:$LINENO: checking for DBUS Flask permissions in selinux/av_permissions.h" >&5 +$as_echo_n "checking for DBUS Flask permissions in selinux/av_permissions.h... " >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +#ifdef DBUS__ACQUIRE_SVC return 0; + #else + #error DBUS__ACQUIRE_SVC not defined + #endif + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + have_selinux=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + have_selinux=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:$LINENO: result: $have_selinux" >&5 +$as_echo "$have_selinux" >&6; } + fi + + if test x$enable_selinux = xauto ; then + if test x$have_selinux = xno ; then + { $as_echo "$as_me:$LINENO: WARNING: Sufficiently new SELinux library not found" >&5 +$as_echo "$as_me: WARNING: Sufficiently new SELinux library not found" >&2;} + fi + else + if test x$have_selinux = xno ; then + { { $as_echo "$as_me:$LINENO: error: SElinux explicitly required, and SELinux library not found" >&5 +$as_echo "$as_me: error: SElinux explicitly required, and SELinux library not found" >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi + + if test x$have_selinux = xyes; then + HAVE_SELINUX_TRUE= + HAVE_SELINUX_FALSE='#' +else + HAVE_SELINUX_TRUE='#' + HAVE_SELINUX_FALSE= +fi + + +if test x$have_selinux = xyes ; then + # the selinux code creates threads + # which requires libpthread even on linux + { $as_echo "$as_me:$LINENO: checking for pthread_create" >&5 +$as_echo_n "checking for pthread_create... " >&6; } +if test "${ac_cv_func_pthread_create+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define pthread_create to an innocuous variant, in case declares pthread_create. + For example, HP-UX 11i declares gettimeofday. */ +#define pthread_create innocuous_pthread_create + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char pthread_create (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef pthread_create + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_create (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_pthread_create || defined __stub___pthread_create +choke me +#endif + +int +main () +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_pthread_create=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_pthread_create=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_pthread_create" >&5 +$as_echo "$ac_cv_func_pthread_create" >&6; } +if test "x$ac_cv_func_pthread_create" = x""yes; then + : +else + { $as_echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5 +$as_echo_n "checking for pthread_create in -lpthread... " >&6; } +if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_create (); +int +main () +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_pthread_pthread_create=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_pthread_pthread_create=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_create" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = x""yes; then + SELINUX_THREAD_LIBS="-lpthread" +fi + +fi + + + SELINUX_LIBS="-lselinux $SELINUX_THREAD_LIBS" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SELINUX 1 +_ACEOF + +else + SELINUX_LIBS= +fi + +# inotify checks +if test x$enable_inotify = xno ; then + have_inotify=no; +else + +for ac_header in sys/inotify.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + have_inotify=yes +else + have_inotify=no +fi + +done + +fi + +if test x$have_inotify = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define DBUS_BUS_ENABLE_INOTIFY 1 +_ACEOF + + +for ac_func in inotify_init1 +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +fi + + if test x$have_inotify = xyes; then + DBUS_BUS_ENABLE_INOTIFY_TRUE= + DBUS_BUS_ENABLE_INOTIFY_FALSE='#' +else + DBUS_BUS_ENABLE_INOTIFY_TRUE='#' + DBUS_BUS_ENABLE_INOTIFY_FALSE= +fi + + +# dnotify checks +if test x$enable_dnotify = xno ; then + have_dnotify=no; +else + if test x$have_inotify = xno -a x$host_os = xlinux-gnu -o x$host_os = xlinux; then + have_dnotify=yes; + else + have_dnotify=no; + fi +fi + +if test x$have_dnotify = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX 1 +_ACEOF + +fi + + if test x$have_dnotify = xyes; then + DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX_TRUE= + DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX_FALSE='#' +else + DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX_TRUE='#' + DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX_FALSE= +fi + + +# kqueue checks +if test x$enable_kqueue = xno ; then + have_kqueue=no +else + have_kqueue=yes + if test "${ac_cv_header_sys_event_h+set}" = set; then + { $as_echo "$as_me:$LINENO: checking for sys/event.h" >&5 +$as_echo_n "checking for sys/event.h... " >&6; } +if test "${ac_cv_header_sys_event_h+set}" = set; then + $as_echo_n "(cached) " >&6 +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_event_h" >&5 +$as_echo "$ac_cv_header_sys_event_h" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking sys/event.h usability" >&5 +$as_echo_n "checking sys/event.h usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking sys/event.h presence" >&5 +$as_echo_n "checking sys/event.h presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: sys/event.h: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: sys/event.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: sys/event.h: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: sys/event.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: sys/event.h: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: sys/event.h: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: sys/event.h: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: sys/event.h: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: sys/event.h: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: sys/event.h: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: sys/event.h: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: sys/event.h: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: sys/event.h: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: sys/event.h: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: sys/event.h: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: sys/event.h: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for sys/event.h" >&5 +$as_echo_n "checking for sys/event.h... " >&6; } +if test "${ac_cv_header_sys_event_h+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_cv_header_sys_event_h=$ac_header_preproc +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_event_h" >&5 +$as_echo "$ac_cv_header_sys_event_h" >&6; } + +fi +if test "x$ac_cv_header_sys_event_h" = x""yes; then + : +else + have_kqueue=no +fi + + + { $as_echo "$as_me:$LINENO: checking for kqueue" >&5 +$as_echo_n "checking for kqueue... " >&6; } +if test "${ac_cv_func_kqueue+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define kqueue to an innocuous variant, in case declares kqueue. + For example, HP-UX 11i declares gettimeofday. */ +#define kqueue innocuous_kqueue + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char kqueue (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef kqueue + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char kqueue (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_kqueue || defined __stub___kqueue +choke me +#endif + +int +main () +{ +return kqueue (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_kqueue=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_kqueue=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_kqueue" >&5 +$as_echo "$ac_cv_func_kqueue" >&6; } +if test "x$ac_cv_func_kqueue" = x""yes; then + : +else + have_kqueue=no +fi + + + if test x$enable_kqueue = xyes -a x$have_kqueue = xno; then + { { $as_echo "$as_me:$LINENO: error: kqueue support explicitly enabled but not available" >&5 +$as_echo "$as_me: error: kqueue support explicitly enabled but not available" >&2;} + { (exit 1); exit 1; }; } + fi +fi + +if test x$have_kqueue = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define DBUS_BUS_ENABLE_KQUEUE 1 +_ACEOF + +fi + + if test x$have_kqueue = xyes; then + DBUS_BUS_ENABLE_KQUEUE_TRUE= + DBUS_BUS_ENABLE_KQUEUE_FALSE='#' +else + DBUS_BUS_ENABLE_KQUEUE_TRUE='#' + DBUS_BUS_ENABLE_KQUEUE_FALSE= +fi + + +if test x$enable_console_owner_file = xno ; then + have_console_owner_file=no; +else + case $host_os in + solaris*) + have_console_owner_file=yes; + +cat >>confdefs.h <<\_ACEOF +#define HAVE_CONSOLE_OWNER_FILE 1 +_ACEOF + + ;; + *) + have_console_owner_file=no;; + esac +fi + + if test x$have_console_owner_file = xyes; then + HAVE_CONSOLE_OWNER_FILE_TRUE= + HAVE_CONSOLE_OWNER_FILE_FALSE='#' +else + HAVE_CONSOLE_OWNER_FILE_TRUE='#' + HAVE_CONSOLE_OWNER_FILE_FALSE= +fi + + +# libaudit detection +if test x$enable_libaudit = xno ; then + have_libaudit=no; +else + # See if we have audit daemon & capabilities library + { $as_echo "$as_me:$LINENO: checking for audit_log_user_avc_message in -laudit" >&5 +$as_echo_n "checking for audit_log_user_avc_message in -laudit... " >&6; } +if test "${ac_cv_lib_audit_audit_log_user_avc_message+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-laudit $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char audit_log_user_avc_message (); +int +main () +{ +return audit_log_user_avc_message (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_audit_audit_log_user_avc_message=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_audit_audit_log_user_avc_message=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_audit_audit_log_user_avc_message" >&5 +$as_echo "$ac_cv_lib_audit_audit_log_user_avc_message" >&6; } +if test "x$ac_cv_lib_audit_audit_log_user_avc_message" = x""yes; then + have_libaudit=yes +else + have_libaudit=no +fi + + if test x$have_libaudit = xyes ; then + { $as_echo "$as_me:$LINENO: checking for capng_clear in -lcap-ng" >&5 +$as_echo_n "checking for capng_clear in -lcap-ng... " >&6; } +if test "${ac_cv_lib_cap_ng_capng_clear+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcap-ng $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char capng_clear (); +int +main () +{ +return capng_clear (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_cap_ng_capng_clear=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_cap_ng_capng_clear=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_cap_ng_capng_clear" >&5 +$as_echo "$ac_cv_lib_cap_ng_capng_clear" >&6; } +if test "x$ac_cv_lib_cap_ng_capng_clear" = x""yes; then + have_libaudit=yes +else + have_libaudit=no +fi + + fi +fi + + if test x$have_libaudit = xyes; then + HAVE_LIBAUDIT_TRUE= + HAVE_LIBAUDIT_FALSE='#' +else + HAVE_LIBAUDIT_TRUE='#' + HAVE_LIBAUDIT_FALSE= +fi + + +if test x$have_libaudit = xyes ; then + SELINUX_LIBS="$SELINUX_LIBS -laudit -lcap-ng" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBAUDIT 1 +_ACEOF + +fi + +# Check for ADT API +{ $as_echo "$as_me:$LINENO: checking for ADT API" >&5 +$as_echo_n "checking for ADT API... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +adt_user_context = ADT_USER; + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + check_adt_audit=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + check_adt_audit=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test ${check_adt_audit} = yes +then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_ADT /**/ +_ACEOF + + ADT_LIBS="-lbsm" + LIBS="-lbsm $LIBS" + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +#### Set up final flags +DBUS_CLIENT_CFLAGS= +DBUS_CLIENT_LIBS="$THREAD_LIBS" + + + +DBUS_BUS_CFLAGS="$XML_CFLAGS" +DBUS_BUS_LIBS="$XML_LIBS $SELINUX_LIBS $INTLLIBS $THREAD_LIBS $ADT_LIBS" + + + +DBUS_LAUNCHER_CFLAGS="$XML_CFLAGS" +DBUS_LAUNCHER_LIBS="$XML_LIBS $THREAD_LIBS" + + + +DBUS_TEST_CFLAGS= +DBUS_TEST_LIBS="$THREAD_LIBS" + + + +### X11 detection +{ $as_echo "$as_me:$LINENO: checking for X" >&5 +$as_echo_n "checking for X... " >&6; } + + +# Check whether --with-x was given. +if test "${with_x+set}" = set; then + withval=$with_x; +fi + +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + case $x_includes,$x_libraries in #( + *\'*) { { $as_echo "$as_me:$LINENO: error: cannot use X directory names containing '" >&5 +$as_echo "$as_me: error: cannot use X directory names containing '" >&2;} + { (exit 1); exit 1; }; };; #( + *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then + $as_echo_n "(cached) " >&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=no ac_x_libraries=no +rm -f -r conftest.dir +if mkdir conftest.dir; then + cd conftest.dir + cat >Imakefile <<'_ACEOF' +incroot: + @echo incroot='${INCROOT}' +usrlibdir: + @echo usrlibdir='${USRLIBDIR}' +libdir: + @echo libdir='${LIBDIR}' +_ACEOF + if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering...", which would confuse us. + for ac_var in incroot usrlibdir libdir; do + eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" + done + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl dylib la dll; do + if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && + test -f "$ac_im_libdir/libX11.$ac_extension"; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case $ac_im_incroot in + /usr/include) ac_x_includes= ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; + esac + case $ac_im_usrlibdir in + /usr/lib | /usr/lib64 | /lib | /lib64) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; + esac + fi + cd .. + rm -f -r conftest.dir +fi + +# Standard set of common directories for X headers. +# Check X11 before X11Rn because it is often a symlink to the current release. +ac_x_header_dirs=' +/usr/X11/include +/usr/X11R6/include +/usr/X11R5/include +/usr/X11R4/include + +/usr/include/X11 +/usr/include/X11R6 +/usr/include/X11R5 +/usr/include/X11R4 + +/usr/local/X11/include +/usr/local/X11R6/include +/usr/local/X11R5/include +/usr/local/X11R4/include + +/usr/local/include/X11 +/usr/local/include/X11R6 +/usr/local/include/X11R5 +/usr/local/include/X11R4 + +/usr/X386/include +/usr/x386/include +/usr/XFree86/include/X11 + +/usr/include +/usr/local/include +/usr/unsupported/include +/usr/athena/include +/usr/local/x11r5/include +/usr/lpp/Xamples/include + +/usr/openwin/include +/usr/openwin/share/include' + +if test "$ac_x_includes" = no; then + # Guess where to find include files, by looking for Xlib.h. + # First, try using that file with no special directory specified. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # We can compile using X headers with no special include directory. +ac_x_includes= +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + for ac_dir in $ac_x_header_dirs; do + if test -r "$ac_dir/X11/Xlib.h"; then + ac_x_includes=$ac_dir + break + fi +done +fi + +rm -f conftest.err conftest.$ac_ext +fi # $ac_x_includes = no + +if test "$ac_x_libraries" = no; then + # Check for the libraries. + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS=$LIBS + LIBS="-lX11 $LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +XrmInitialize () + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + LIBS=$ac_save_LIBS +# We can link X programs with no special library path. +ac_x_libraries= +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + LIBS=$ac_save_LIBS +for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` +do + # Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl dylib la dll; do + if test -r "$ac_dir/libX11.$ac_extension"; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi # $ac_x_libraries = no + +case $ac_x_includes,$ac_x_libraries in #( + no,* | *,no | *\'*) + # Didn't find X, or a directory has "'" in its name. + ac_cv_have_x="have_x=no";; #( + *) + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$ac_x_includes'\ + ac_x_libraries='$ac_x_libraries'" +esac +fi +;; #( + *) have_x=yes;; + esac + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + { $as_echo "$as_me:$LINENO: result: $have_x" >&5 +$as_echo "$have_x" >&6; } + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$x_includes'\ + ac_x_libraries='$x_libraries'" + { $as_echo "$as_me:$LINENO: result: libraries $x_libraries, headers $x_includes" >&5 +$as_echo "libraries $x_libraries, headers $x_includes" >&6; } +fi + +if test "$no_x" = yes; then + # Not all programs may use this symbol, but it does not hurt to define it. + +cat >>confdefs.h <<\_ACEOF +#define X_DISPLAY_MISSING 1 +_ACEOF + + X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= +else + if test -n "$x_includes"; then + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + # It would also be nice to do this for all -L options, not just this one. + if test -n "$x_libraries"; then + X_LIBS="$X_LIBS -L$x_libraries" + # For Solaris; some versions of Sun CC require a space after -R and + # others require no space. Words are not sufficient . . . . + { $as_echo "$as_me:$LINENO: checking whether -R must be followed by a space" >&5 +$as_echo_n "checking whether -R must be followed by a space... " >&6; } + ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" + ac_xsave_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + X_LIBS="$X_LIBS -R$x_libraries" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + LIBS="$ac_xsave_LIBS -R $x_libraries" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + X_LIBS="$X_LIBS -R $x_libraries" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { $as_echo "$as_me:$LINENO: result: neither works" >&5 +$as_echo "neither works" >&6; } +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + ac_c_werror_flag=$ac_xsave_c_werror_flag + LIBS=$ac_xsave_LIBS + fi + + # Check for system-dependent libraries X programs must link with. + # Do this before checking for the system-independent R6 libraries + # (-lICE), since we may need -lsocket or whatever for X linking. + + if test "$ISC" = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" + else + # Martyn Johnson says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And Karl Berry says + # the Alpha needs dnet_stub (dnet does not exist). + ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XOpenDisplay (); +int +main () +{ +return XOpenDisplay (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { $as_echo "$as_me:$LINENO: checking for dnet_ntoa in -ldnet" >&5 +$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } +if test "${ac_cv_lib_dnet_dnet_ntoa+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dnet_ntoa (); +int +main () +{ +return dnet_ntoa (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_dnet_dnet_ntoa=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dnet_dnet_ntoa=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 +$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } +if test "x$ac_cv_lib_dnet_dnet_ntoa" = x""yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" +fi + + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + { $as_echo "$as_me:$LINENO: checking for dnet_ntoa in -ldnet_stub" >&5 +$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } +if test "${ac_cv_lib_dnet_stub_dnet_ntoa+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet_stub $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dnet_ntoa (); +int +main () +{ +return dnet_ntoa (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_dnet_stub_dnet_ntoa=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dnet_stub_dnet_ntoa=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 +$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } +if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = x""yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" +fi + + fi +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_xsave_LIBS" + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to T.E. Dickey. + # The functions gethostbyname, getservbyname, and inet_addr are + # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. + { $as_echo "$as_me:$LINENO: checking for gethostbyname" >&5 +$as_echo_n "checking for gethostbyname... " >&6; } +if test "${ac_cv_func_gethostbyname+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define gethostbyname to an innocuous variant, in case declares gethostbyname. + For example, HP-UX 11i declares gettimeofday. */ +#define gethostbyname innocuous_gethostbyname + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char gethostbyname (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef gethostbyname + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_gethostbyname || defined __stub___gethostbyname +choke me +#endif + +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_gethostbyname=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_gethostbyname=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5 +$as_echo "$ac_cv_func_gethostbyname" >&6; } + + if test $ac_cv_func_gethostbyname = no; then + { $as_echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5 +$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } +if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_nsl_gethostbyname=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_nsl_gethostbyname=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5 +$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } +if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" +fi + + if test $ac_cv_lib_nsl_gethostbyname = no; then + { $as_echo "$as_me:$LINENO: checking for gethostbyname in -lbsd" >&5 +$as_echo_n "checking for gethostbyname in -lbsd... " >&6; } +if test "${ac_cv_lib_bsd_gethostbyname+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbsd $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_bsd_gethostbyname=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_bsd_gethostbyname=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_gethostbyname" >&5 +$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } +if test "x$ac_cv_lib_bsd_gethostbyname" = x""yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" +fi + + fi + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says Simon Leinen: it contains gethostby* + # variants that don't use the name server (or something). -lsocket + # must be given before -lnsl if both are needed. We assume that + # if connect needs -lnsl, so does gethostbyname. + { $as_echo "$as_me:$LINENO: checking for connect" >&5 +$as_echo_n "checking for connect... " >&6; } +if test "${ac_cv_func_connect+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define connect to an innocuous variant, in case declares connect. + For example, HP-UX 11i declares gettimeofday. */ +#define connect innocuous_connect + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char connect (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef connect + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char connect (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_connect || defined __stub___connect +choke me +#endif + +int +main () +{ +return connect (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_connect=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_connect=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_connect" >&5 +$as_echo "$ac_cv_func_connect" >&6; } + + if test $ac_cv_func_connect = no; then + { $as_echo "$as_me:$LINENO: checking for connect in -lsocket" >&5 +$as_echo_n "checking for connect in -lsocket... " >&6; } +if test "${ac_cv_lib_socket_connect+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $X_EXTRA_LIBS $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char connect (); +int +main () +{ +return connect (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_socket_connect=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_socket_connect=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_socket_connect" >&5 +$as_echo "$ac_cv_lib_socket_connect" >&6; } +if test "x$ac_cv_lib_socket_connect" = x""yes; then + X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" +fi + + fi + + # Guillermo Gomez says -lposix is necessary on A/UX. + { $as_echo "$as_me:$LINENO: checking for remove" >&5 +$as_echo_n "checking for remove... " >&6; } +if test "${ac_cv_func_remove+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define remove to an innocuous variant, in case declares remove. + For example, HP-UX 11i declares gettimeofday. */ +#define remove innocuous_remove + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char remove (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef remove + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char remove (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_remove || defined __stub___remove +choke me +#endif + +int +main () +{ +return remove (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_remove=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_remove=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_remove" >&5 +$as_echo "$ac_cv_func_remove" >&6; } + + if test $ac_cv_func_remove = no; then + { $as_echo "$as_me:$LINENO: checking for remove in -lposix" >&5 +$as_echo_n "checking for remove in -lposix... " >&6; } +if test "${ac_cv_lib_posix_remove+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lposix $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char remove (); +int +main () +{ +return remove (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_posix_remove=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_posix_remove=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_posix_remove" >&5 +$as_echo "$ac_cv_lib_posix_remove" >&6; } +if test "x$ac_cv_lib_posix_remove" = x""yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" +fi + + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + { $as_echo "$as_me:$LINENO: checking for shmat" >&5 +$as_echo_n "checking for shmat... " >&6; } +if test "${ac_cv_func_shmat+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define shmat to an innocuous variant, in case declares shmat. + For example, HP-UX 11i declares gettimeofday. */ +#define shmat innocuous_shmat + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shmat (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef shmat + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shmat (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_shmat || defined __stub___shmat +choke me +#endif + +int +main () +{ +return shmat (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_shmat=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_shmat=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_shmat" >&5 +$as_echo "$ac_cv_func_shmat" >&6; } + + if test $ac_cv_func_shmat = no; then + { $as_echo "$as_me:$LINENO: checking for shmat in -lipc" >&5 +$as_echo_n "checking for shmat in -lipc... " >&6; } +if test "${ac_cv_lib_ipc_shmat+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lipc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shmat (); +int +main () +{ +return shmat (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_ipc_shmat=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_ipc_shmat=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_ipc_shmat" >&5 +$as_echo "$ac_cv_lib_ipc_shmat" >&6; } +if test "x$ac_cv_lib_ipc_shmat" = x""yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" +fi + + fi + fi + + # Check for libraries that X11R6 Xt/Xaw programs need. + ac_save_LDFLAGS=$LDFLAGS + test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" + # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to + # check for ICE first), but we must link in the order -lSM -lICE or + # we get undefined symbols. So assume we have SM if we have ICE. + # These have to be linked with before -lX11, unlike the other + # libraries we check for below, so use a different variable. + # John Interrante, Karl Berry + { $as_echo "$as_me:$LINENO: checking for IceConnectionNumber in -lICE" >&5 +$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } +if test "${ac_cv_lib_ICE_IceConnectionNumber+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lICE $X_EXTRA_LIBS $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char IceConnectionNumber (); +int +main () +{ +return IceConnectionNumber (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_ICE_IceConnectionNumber=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_ICE_IceConnectionNumber=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 +$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } +if test "x$ac_cv_lib_ICE_IceConnectionNumber" = x""yes; then + X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" +fi + + LDFLAGS=$ac_save_LDFLAGS + +fi + + +## for now enable_x11 just tracks have_x11, +## there's no --enable-x11 +if test x$no_x = xyes ; then + have_x11=no + enable_x11=no +else + have_x11=yes + enable_x11=yes +fi + +if test x$enable_x11 = xyes ; then + +cat >>confdefs.h <<\_ACEOF +#define DBUS_BUILD_X11 1 +_ACEOF + + DBUS_X_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" + DBUS_X_CFLAGS="$X_CFLAGS" +else + DBUS_X_LIBS= + DBUS_X_CFLAGS= +fi + + + + + +#### gcc warning flags + +cc_supports_flag() { + { $as_echo "$as_me:$LINENO: checking whether $CC supports \"$@\"" >&5 +$as_echo_n "checking whether $CC supports \"$@\"... " >&6; } + Cfile=/tmp/foo${$} + touch ${Cfile}.c + $CC -c "$@" ${Cfile}.c -o ${Cfile}.o >/dev/null 2>&1 + rc=$? + rm -f ${Cfile}.c ${Cfile}.o + case $rc in + 0) { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; };; + *) { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; };; + esac + return $rc +} + +ld_supports_flag() { + { $as_echo "$as_me:$LINENO: checking whether $LD supports \"$@\"" >&5 +$as_echo_n "checking whether $LD supports \"$@\"... " >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + int one(void) { return 1; } + int two(void) { return 2; } + +int +main () +{ + two(); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + _ac_ld_flag_supported=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + _ac_ld_flag_supported=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + + if test "$_ac_ld_flag_supported" = "yes"; then + rm -f conftest.c + touch conftest.c + if $CC -c conftest.c; then + ld_out=`$LD $@ -o conftest conftest.o 2>&1` + ld_ret=$? + if test $ld_ret -ne 0 ; then + _ac_ld_flag_supported=no + elif echo "$ld_out" | egrep 'option ignored|^usage:|unrecognized option|illegal option' >/dev/null ; then + _ac_ld_flag_supported=no + fi + fi + rm -f conftest.c conftest.o conftest + fi + + { $as_echo "$as_me:$LINENO: result: $_ac_ld_flag_supported" >&5 +$as_echo "$_ac_ld_flag_supported" >&6; } + if test "$_ac_ld_flag_supported" = "yes" ; then + return 0 + else + return 1 + fi +} + +if test x$USE_MAINTAINER_MODE = xyes; then + if cc_supports_flag "-Werror"; then + CFLAGS="$CFLAGS -Werror" + fi +fi + +if test "x$GCC" = "xyes"; then + case " $CFLAGS " in + *[\ \ ]-Wall[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wall" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wchar-subscripts[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wchar-subscripts" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wmissing-declarations[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wmissing-declarations" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wmissing-prototypes[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wmissing-prototypes" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wnested-externs[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wnested-externs" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wpointer-arith[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wpointer-arith" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wcast-align[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wcast-align" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wfloat-equal[\ \ ]*) ;; + *) if cc_supports_flag -Wfloat-equals; then + CFLAGS="$CFLAGS -Wfloat-equal" + fi + ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wdeclaration-after-statement[\ \ ]*) ;; + *) if cc_supports_flag -Wdeclaration-after-statement; then + CFLAGS="$CFLAGS -Wdeclaration-after-statement" + fi + ;; + esac + + case " $CFLAGS " in + *[\ \ ]-fno-common[\ \ ]*) ;; + *) if cc_supports_flag -fno-common; then + CFLAGS="$CFLAGS -fno-common" + fi + ;; + esac + + case " $CFLAGS " in + *[\ \ ]-fPIC[\ \ ]*) ;; + *) if cc_supports_flag -fPIC; then + PIC_CFLAGS="-fPIC" + if ld_supports_flag -z,relro; then + PIC_LDFLAGS="-Wl,-z,relro" + fi + fi + ;; + esac + + case " $CFLAGS " in + *[\ \ ]-fPIE[\ \ ]*) ;; + *) if cc_supports_flag -fPIE; then + PIE_CFLAGS="-fPIE" + if ld_supports_flag -z,relro; then + PIE_LDFLAGS="-pie -Wl,-z,relro" + else + PIE_LDFLAGS="-pie" + fi + fi + ;; + esac + + ### Disabled warnings, and compiler flag overrides + + # Let's just ignore unused for now + case " $CFLAGS " in + *[\ \ ]-Wno-unused[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wno-unused" ;; + esac + + # This group is for warnings we currently don't pass. + # We would like to, however. Please fix. + + # http://bugs.freedesktop.org/show_bug.cgi?id=17433 + case " $CFLAGS " in + *[\ \ ]-Wno-sign-compare[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wno-sign-compare" ;; + esac + case " $CFLAGS " in + *[\ \ ]-Wno-pointer-sign[\ \ ]*) ;; + *) if cc_supports_flag -Wno-pointer-sign; then + CFLAGS="$CFLAGS -Wno-pointer-sign" + fi + ;; + esac + + # This one is special - it's not a warning override. + # http://bugs.freedesktop.org/show_bug.cgi?id=10599 + case " $CFLAGS " in + *[\ \ ]-fno-strict-aliasing[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -fno-strict-aliasing" ;; + esac + ### End disabled warnings + + if test "x$enable_ansi" = "xyes"; then + case " $CFLAGS " in + *[\ \ ]-ansi[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -ansi" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-D_POSIX_C_SOURCE*) ;; + *) CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=199309L" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-D_BSD_SOURCE[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -D_BSD_SOURCE" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-pedantic[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -pedantic" ;; + esac + fi + if test x$enable_gcov = xyes; then + case " $CFLAGS " in + *[\ \ ]-fprofile-arcs[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -fprofile-arcs" ;; + esac + case " $CFLAGS " in + *[\ \ ]-ftest-coverage[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -ftest-coverage" ;; + esac + + ## remove optimization + CFLAGS=`echo "$CFLAGS" | sed -e 's/-O[0-9]*//g'` + fi + else + if test x$enable_gcov = xyes; then + { { $as_echo "$as_me:$LINENO: error: --enable-gcov can only be used with gcc" >&5 +$as_echo "$as_me: error: --enable-gcov can only be used with gcc" >&2;} + { (exit 1); exit 1; }; } + fi +fi + + + + + + +if ld_supports_flag --gc-sections; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + CFLAGS="-ffunction-sections -fdata-sections $CFLAGS" +fi + + +{ $as_echo "$as_me:$LINENO: result: $ac_gcsections" >&5 +$as_echo "$ac_gcsections" >&6; } + +# compress spaces in flags +CFLAGS=`echo "$CFLAGS" | sed -e 's/ +/ /g'` +CXXFLAGS=`echo "$CXXFLAGS" | sed -e 's/ +/ /g'` +CPPFLAGS=`echo "$CPPFLAGS" | sed -e 's/ +/ /g'` + +### Doxygen Documentation + +# Extract the first word of "doxygen", so it can be a program name with args. +set dummy doxygen; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_DOXYGEN+set}" = set; then + $as_echo_n "(cached) " >&6 +else + case $DOXYGEN in + [\\/]* | ?:[\\/]*) + ac_cv_path_DOXYGEN="$DOXYGEN" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_DOXYGEN="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_path_DOXYGEN" && ac_cv_path_DOXYGEN="no" + ;; +esac +fi +DOXYGEN=$ac_cv_path_DOXYGEN +if test -n "$DOXYGEN"; then + { $as_echo "$as_me:$LINENO: result: $DOXYGEN" >&5 +$as_echo "$DOXYGEN" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + +{ $as_echo "$as_me:$LINENO: checking whether to build Doxygen documentation" >&5 +$as_echo_n "checking whether to build Doxygen documentation... " >&6; } + +if test x$DOXYGEN = xno ; then + have_doxygen=no +else + have_doxygen=yes +fi + +if test x$enable_doxygen_docs = xauto ; then + if test x$have_doxygen = xno ; then + enable_doxygen_docs=no + else + enable_doxygen_docs=yes + fi +fi + +if test x$enable_doxygen_docs = xyes; then + if test x$have_doxygen = xno; then + { { $as_echo "$as_me:$LINENO: error: Building Doxygen docs explicitly required, but Doxygen not found" >&5 +$as_echo "$as_me: error: Building Doxygen docs explicitly required, but Doxygen not found" >&2;} + { (exit 1); exit 1; }; } + fi +fi + + if test x$enable_doxygen_docs = xyes; then + DBUS_DOXYGEN_DOCS_ENABLED_TRUE= + DBUS_DOXYGEN_DOCS_ENABLED_FALSE='#' +else + DBUS_DOXYGEN_DOCS_ENABLED_TRUE='#' + DBUS_DOXYGEN_DOCS_ENABLED_FALSE= +fi + +{ $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + +### XML Documentation + +# Extract the first word of "xmlto", so it can be a program name with args. +set dummy xmlto; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_XMLTO+set}" = set; then + $as_echo_n "(cached) " >&6 +else + case $XMLTO in + [\\/]* | ?:[\\/]*) + ac_cv_path_XMLTO="$XMLTO" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_XMLTO="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_path_XMLTO" && ac_cv_path_XMLTO="no" + ;; +esac +fi +XMLTO=$ac_cv_path_XMLTO +if test -n "$XMLTO"; then + { $as_echo "$as_me:$LINENO: result: $XMLTO" >&5 +$as_echo "$XMLTO" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + +{ $as_echo "$as_me:$LINENO: checking whether to build XML documentation" >&5 +$as_echo_n "checking whether to build XML documentation... " >&6; } + +if test x$XMLTO = xno ; then + have_xmlto=no +else + have_xmlto=yes +fi + +if test x$enable_xml_docs = xauto ; then + if test x$have_xmlto = xno ; then + enable_xml_docs=no + else + enable_xml_docs=yes + fi +fi + +if test x$enable_xml_docs = xyes; then + if test x$have_xmlto = xno; then + { { $as_echo "$as_me:$LINENO: error: Building XML docs explicitly required, but xmlto not found" >&5 +$as_echo "$as_me: error: Building XML docs explicitly required, but xmlto not found" >&2;} + { (exit 1); exit 1; }; } + fi +fi + + if test x$enable_xml_docs = xyes; then + DBUS_XML_DOCS_ENABLED_TRUE= + DBUS_XML_DOCS_ENABLED_FALSE='#' +else + DBUS_XML_DOCS_ENABLED_TRUE='#' + DBUS_XML_DOCS_ENABLED_FALSE= +fi + +{ $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + +#### Have to go $localstatedir->$prefix/var->/usr/local/var + +#### find the actual value for $prefix that we'll end up with +## (I know this is broken and should be done in the Makefile, but +## that's a major pain and almost nobody actually seems to care) + + EXP_VAR=EXPANDED_LOCALSTATEDIR + FROM_VAR="$localstatedir" + + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + full_var=$new_full_var + EXPANDED_LOCALSTATEDIR="$full_var" + + + prefix=$prefix_save + exec_prefix=$exec_prefix_save + + + EXP_VAR=EXPANDED_SYSCONFDIR + FROM_VAR="$sysconfdir" + + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + full_var=$new_full_var + EXPANDED_SYSCONFDIR="$full_var" + + + prefix=$prefix_save + exec_prefix=$exec_prefix_save + + + EXP_VAR=EXPANDED_BINDIR + FROM_VAR="$bindir" + + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + full_var=$new_full_var + EXPANDED_BINDIR="$full_var" + + + prefix=$prefix_save + exec_prefix=$exec_prefix_save + + + EXP_VAR=EXPANDED_LIBDIR + FROM_VAR="$libdir" + + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + full_var=$new_full_var + EXPANDED_LIBDIR="$full_var" + + + prefix=$prefix_save + exec_prefix=$exec_prefix_save + + + EXP_VAR=EXPANDED_LIBEXECDIR + FROM_VAR="$libexecdir" + + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + full_var=$new_full_var + EXPANDED_LIBEXECDIR="$full_var" + + + prefix=$prefix_save + exec_prefix=$exec_prefix_save + + + EXP_VAR=EXPANDED_DATADIR + FROM_VAR="$datadir" + + prefix_save=$prefix + exec_prefix_save=$exec_prefix + + if test "x$prefix" = "xNONE"; then + prefix="$ac_default_prefix" + fi + if test "x$exec_prefix" = "xNONE"; then + exec_prefix=$prefix + fi + + full_var="$FROM_VAR" + while true; do + new_full_var="`eval echo $full_var`" + if test "x$new_full_var" = "x$full_var"; then break; fi + full_var=$new_full_var + done + + full_var=$new_full_var + EXPANDED_DATADIR="$full_var" + + + prefix=$prefix_save + exec_prefix=$exec_prefix_save + + +#### Check our operating system +operating_system=unknown +if test -f /etc/redhat-release || test -f $EXPANDED_SYSCONFDIR/redhat-release ; then + operating_system=redhat +fi + +if test -f /etc/slackware-version || test -f $EXPANDED_SYSCONFDIR/slackware-version ; then + operating_system=slackware +fi + +#### Sort out init scripts + +if test x$with_init_scripts = x; then + if test xredhat = x$operating_system ; then + with_init_scripts=redhat + else + if test xslackware = x$operating_system ; then + with_init_scripts=slackware + else + with_init_scripts=none + fi + fi +fi + + if test x$with_init_scripts = xredhat; then + DBUS_INIT_SCRIPTS_RED_HAT_TRUE= + DBUS_INIT_SCRIPTS_RED_HAT_FALSE='#' +else + DBUS_INIT_SCRIPTS_RED_HAT_TRUE='#' + DBUS_INIT_SCRIPTS_RED_HAT_FALSE= +fi + + + if test x$with_init_scripts = xslackware; then + DBUS_INIT_SCRIPTS_SLACKWARE_TRUE= + DBUS_INIT_SCRIPTS_SLACKWARE_FALSE='#' +else + DBUS_INIT_SCRIPTS_SLACKWARE_TRUE='#' + DBUS_INIT_SCRIPTS_SLACKWARE_FALSE= +fi + + +##### Set up location for system bus socket +if ! test -z "$with_system_socket"; then + DBUS_SYSTEM_SOCKET=$with_system_socket +else + DBUS_SYSTEM_SOCKET=${EXPANDED_LOCALSTATEDIR}/run/dbus/system_bus_socket +fi + + + +cat >>confdefs.h <<_ACEOF +#define DBUS_SYSTEM_SOCKET "$DBUS_SYSTEM_SOCKET" +_ACEOF + + +## system bus only listens on local domain sockets, and never +## on an abstract socket (so only root can create the socket) +DBUS_SYSTEM_BUS_DEFAULT_ADDRESS="unix:path=$DBUS_SYSTEM_SOCKET" + + +cat >>confdefs.h <<_ACEOF +#define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "$DBUS_SYSTEM_BUS_DEFAULT_ADDRESS" +_ACEOF + + +#### Set up the pid file +if ! test -z "$with_system_pid_file"; then + DBUS_SYSTEM_PID_FILE=$with_system_pid_file +elif test x$with_init_scripts = xredhat ; then + DBUS_SYSTEM_PID_FILE=${EXPANDED_LOCALSTATEDIR}/run/messagebus.pid +else + DBUS_SYSTEM_PID_FILE=${EXPANDED_LOCALSTATEDIR}/run/dbus/pid +fi + + + +#### Directory to check for console ownership +if ! test -z "$with_console_auth_dir"; then + DBUS_CONSOLE_AUTH_DIR=$with_console_auth_dir +else + DBUS_CONSOLE_AUTH_DIR=/var/run/console/ +fi + + + +cat >>confdefs.h <<_ACEOF +#define DBUS_CONSOLE_AUTH_DIR "$DBUS_CONSOLE_AUTH_DIR" +_ACEOF + + +#### File to check for console ownership +if test x$have_console_owner_file = xyes; then + if ! test -z "$with_console_owner_file"; then + DBUS_CONSOLE_OWNER_FILE=$with_console_owner_file + else + DBUS_CONSOLE_OWNER_FILE=/dev/console + fi +else + DBUS_CONSOLE_OWNER_FILE= +fi + + + +cat >>confdefs.h <<_ACEOF +#define DBUS_CONSOLE_OWNER_FILE "$DBUS_CONSOLE_OWNER_FILE" +_ACEOF + + +#### User to start the system bus as +if test -z "$with_dbus_user" ; then + DBUS_USER=messagebus +else + DBUS_USER=$with_dbus_user +fi + + +cat >>confdefs.h <<_ACEOF +#define DBUS_USER "$DBUS_USER" +_ACEOF + + +#### Direcotry to install data files into +DBUS_DATADIR=$EXPANDED_DATADIR + + +cat >>confdefs.h <<_ACEOF +#define DBUS_DATADIR "$DBUS_DATADIR" +_ACEOF + + +#### Directory to install dbus-daemon +if test -z "$with_dbus_daemondir" ; then + DBUS_DAEMONDIR=$EXPANDED_BINDIR +else + DBUS_DAEMONDIR=$with_dbus_daemondir +fi + + +cat >>confdefs.h <<_ACEOF +#define DBUS_DAEMONDIR "$DBUS_DAEMONDIR" +_ACEOF + + +#### Directory to install the other binaries +DBUS_BINDIR="$EXPANDED_BINDIR" + + +cat >>confdefs.h <<_ACEOF +#define DBUS_BINDIR "$DBUS_BINDIR" +_ACEOF + + +#### Directory to install the libexec binaries +DBUS_LIBEXECDIR="$EXPANDED_LIBEXECDIR" + + +cat >>confdefs.h <<_ACEOF +#define DBUS_LIBEXECDIR "$DBUS_LIBEXECDIR" +_ACEOF + + +#### Tell tests where to find certain stuff in builddir + +DBUS_PWD=`pwd` + + + +TEST_VALID_SERVICE_DIR=${DBUS_PWD}/test/data/valid-service-files + +cat >>confdefs.h <<_ACEOF +#define TEST_VALID_SERVICE_DIR "$TEST_VALID_SERVICE_DIR" +_ACEOF + + + + +TEST_INVALID_SERVICE_DIR=${DBUS_PWD}/test/data/invalid-service-files + +cat >>confdefs.h <<_ACEOF +#define TEST_INVALID_SERVICE_DIR "$TEST_INVALID_SERVICE_DIR" +_ACEOF + + + + +TEST_VALID_SERVICE_SYSTEM_DIR=${DBUS_PWD}/test/data/valid-service-files-system + +cat >>confdefs.h <<_ACEOF +#define TEST_VALID_SERVICE_SYSTEM_DIR "$TEST_VALID_SERVICE_SYSTEM_DIR" +_ACEOF + + + + +TEST_INVALID_SERVICE_SYSTEM_DIR=${DBUS_PWD}/test/data/invalid-service-files-system + +cat >>confdefs.h <<_ACEOF +#define TEST_INVALID_SERVICE_SYSTEM_DIR "$TEST_INVALID_SERVICE_SYSTEM_DIR" +_ACEOF + + + + +TEST_SERVICE_BINARY=${DBUS_PWD}/test/test-service + +cat >>confdefs.h <<_ACEOF +#define TEST_SERVICE_BINARY "$TEST_SERVICE_BINARY" +_ACEOF + + + + +TEST_SHELL_SERVICE_BINARY=${DBUS_PWD}/test/test-shell-service + +cat >>confdefs.h <<_ACEOF +#define TEST_SHELL_SERVICE_BINARY "$TEST_SHELL_SERVICE_BINARY" +_ACEOF + + + + +TEST_EXIT_BINARY=${DBUS_PWD}/test/test-exit + +cat >>confdefs.h <<_ACEOF +#define TEST_EXIT_BINARY "$TEST_EXIT_BINARY" +_ACEOF + + + + +TEST_SEGFAULT_BINARY=${DBUS_PWD}/test/test-segfault + +cat >>confdefs.h <<_ACEOF +#define TEST_SEGFAULT_BINARY "$TEST_SEGFAULT_BINARY" +_ACEOF + + + + +TEST_SLEEP_FOREVER_BINARY=${DBUS_PWD}/test/test-sleep-forever + +cat >>confdefs.h <<_ACEOF +#define TEST_SLEEP_FOREVER_BINARY "$TEST_SLEEP_FOREVER_BINARY" +_ACEOF + + + + +TEST_PRIVSERVER_BINARY=${DBUS_PWD}/test/name-test/test-privserver + +cat >>confdefs.h <<_ACEOF +#define TEST_PRIVSERVER_BINARY "$TEST_PRIVSERVER_BINARY" +_ACEOF + + + + + +cat >>confdefs.h <<_ACEOF +#define TEST_BUS_BINARY "$DBUS_PWD/bus/dbus-daemon" +_ACEOF + + + +## Export the non-setuid external helper +TEST_LAUNCH_HELPER_BINARY="$DBUS_PWD/bus/dbus-daemon-launch-helper-test" + + +cat >>confdefs.h <<_ACEOF +#define DBUS_TEST_LAUNCH_HELPER_BINARY "$TEST_LAUNCH_HELPER_BINARY" +_ACEOF + + +#### Find socket directories +if ! test -z "$TMPDIR" ; then + DEFAULT_SOCKET_DIR=$TMPDIR +elif ! test -z "$TEMP" ; then + DEFAULT_SOCKET_DIR=$TEMP +elif ! test -z "$TMP" ; then + DEFAULT_SOCKET_DIR=$TMP +else + DEFAULT_SOCKET_DIR=/tmp +fi + +if ! test -z "$with_test_socket_dir" ; then + TEST_SOCKET_DIR="$with_test_socket_dir" +else + TEST_SOCKET_DIR=$DEFAULT_SOCKET_DIR +fi + + +cat >>confdefs.h <<_ACEOF +#define DBUS_TEST_SOCKET_DIR "$TEST_SOCKET_DIR" +_ACEOF + + +if ! test -z "$with_session_socket_dir" ; then + DBUS_SESSION_SOCKET_DIR="$with_session_socket_dir" +else + DBUS_SESSION_SOCKET_DIR=$DEFAULT_SOCKET_DIR +fi + +cat >>confdefs.h <<_ACEOF +#define DBUS_SESSION_SOCKET_DIR "$DBUS_SESSION_SOCKET_DIR" +_ACEOF + + + + +cat >>confdefs.h <<_ACEOF +#define DBUS_UNIX "1" +_ACEOF + + +# darwin needs this to initialize the environment + +for ac_header in crt_externs.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:$LINENO: checking for _NSGetEnviron" >&5 +$as_echo_n "checking for _NSGetEnviron... " >&6; } +if test "${ac_cv_func__NSGetEnviron+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define _NSGetEnviron to an innocuous variant, in case declares _NSGetEnviron. + For example, HP-UX 11i declares gettimeofday. */ +#define _NSGetEnviron innocuous__NSGetEnviron + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _NSGetEnviron (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef _NSGetEnviron + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char _NSGetEnviron (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub__NSGetEnviron || defined __stub____NSGetEnviron +choke me +#endif + +int +main () +{ +return _NSGetEnviron (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func__NSGetEnviron=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func__NSGetEnviron=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func__NSGetEnviron" >&5 +$as_echo "$ac_cv_func__NSGetEnviron" >&6; } +if test "x$ac_cv_func__NSGetEnviron" = x""yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_NSGETENVIRON 1 +_ACEOF + +fi + + + + +ac_config_files="$ac_config_files Doxyfile dbus/dbus-arch-deps.h bus/system.conf bus/session.conf bus/messagebus bus/rc.messagebus bus/dbus-daemon.1 Makefile dbus/Makefile bus/Makefile tools/Makefile test/Makefile test/name-test/Makefile doc/Makefile dbus-1.pc test/data/valid-config-files/debug-allow-all.conf test/data/valid-config-files/debug-allow-all-sha1.conf test/data/valid-config-files-system/debug-allow-all-pass.conf test/data/valid-config-files-system/debug-allow-all-fail.conf test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${DBUS_BUILD_TESTS_TRUE}" && test -z "${DBUS_BUILD_TESTS_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"DBUS_BUILD_TESTS\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"DBUS_BUILD_TESTS\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${DBUS_GCOV_ENABLED_TRUE}" && test -z "${DBUS_GCOV_ENABLED_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"DBUS_GCOV_ENABLED\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"DBUS_GCOV_ENABLED\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +if test -z "${DBUS_USE_EXPAT_TRUE}" && test -z "${DBUS_USE_EXPAT_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"DBUS_USE_EXPAT\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"DBUS_USE_EXPAT\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${DBUS_USE_LIBXML_TRUE}" && test -z "${DBUS_USE_LIBXML_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"DBUS_USE_LIBXML\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"DBUS_USE_LIBXML\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${HAVE_SELINUX_TRUE}" && test -z "${HAVE_SELINUX_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"HAVE_SELINUX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"HAVE_SELINUX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${DBUS_BUS_ENABLE_INOTIFY_TRUE}" && test -z "${DBUS_BUS_ENABLE_INOTIFY_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"DBUS_BUS_ENABLE_INOTIFY\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"DBUS_BUS_ENABLE_INOTIFY\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX_TRUE}" && test -z "${DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${DBUS_BUS_ENABLE_KQUEUE_TRUE}" && test -z "${DBUS_BUS_ENABLE_KQUEUE_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"DBUS_BUS_ENABLE_KQUEUE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"DBUS_BUS_ENABLE_KQUEUE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${HAVE_CONSOLE_OWNER_FILE_TRUE}" && test -z "${HAVE_CONSOLE_OWNER_FILE_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"HAVE_CONSOLE_OWNER_FILE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"HAVE_CONSOLE_OWNER_FILE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${HAVE_LIBAUDIT_TRUE}" && test -z "${HAVE_LIBAUDIT_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"HAVE_LIBAUDIT\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"HAVE_LIBAUDIT\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${DBUS_DOXYGEN_DOCS_ENABLED_TRUE}" && test -z "${DBUS_DOXYGEN_DOCS_ENABLED_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"DBUS_DOXYGEN_DOCS_ENABLED\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"DBUS_DOXYGEN_DOCS_ENABLED\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${DBUS_XML_DOCS_ENABLED_TRUE}" && test -z "${DBUS_XML_DOCS_ENABLED_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"DBUS_XML_DOCS_ENABLED\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"DBUS_XML_DOCS_ENABLED\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${DBUS_INIT_SCRIPTS_RED_HAT_TRUE}" && test -z "${DBUS_INIT_SCRIPTS_RED_HAT_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"DBUS_INIT_SCRIPTS_RED_HAT\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"DBUS_INIT_SCRIPTS_RED_HAT\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${DBUS_INIT_SCRIPTS_SLACKWARE_TRUE}" && test -z "${DBUS_INIT_SCRIPTS_SLACKWARE_FALSE}"; then + { { $as_echo "$as_me:$LINENO: error: conditional \"DBUS_INIT_SCRIPTS_SLACKWARE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +$as_echo "$as_me: error: conditional \"DBUS_INIT_SCRIPTS_SLACKWARE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by dbus $as_me 1.2.24, which was +generated by GNU Autoconf 2.63. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTION]... [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_version="\\ +dbus config.status 1.2.24 +configured by $0, generated by GNU Autoconf 2.63, + with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + CONFIG_FILES="$CONFIG_FILES '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { $as_echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { $as_echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`' +macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`' +enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`' +pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`' +host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`' +host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`' +host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`' +build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`' +build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`' +build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`' +SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`' +Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`' +GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`' +EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`' +FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`' +LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`' +NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`' +LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`' +ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`' +exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`' +lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`' +reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`' +AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`' +STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`' +RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' +CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`' +compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`' +GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' +objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`' +SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`' +ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`' +need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`' +LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`' +OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`' +libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' +module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`' +fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' +need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`' +version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`' +runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`' +libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`' +soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`' +finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`' +old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`' +striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "X$compiler_lib_search_dirs" | $Xsed -e "$delay_single_quote_subst"`' +predep_objects='`$ECHO "X$predep_objects" | $Xsed -e "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "X$postdep_objects" | $Xsed -e "$delay_single_quote_subst"`' +predeps='`$ECHO "X$predeps" | $Xsed -e "$delay_single_quote_subst"`' +postdeps='`$ECHO "X$postdeps" | $Xsed -e "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "X$compiler_lib_search_path" | $Xsed -e "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "X$LD_CXX" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "X$old_archive_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "X$compiler_CXX" | $Xsed -e "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "X$GCC_CXX" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "X$lt_prog_compiler_no_builtin_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "X$lt_prog_compiler_wl_CXX" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "X$lt_prog_compiler_pic_CXX" | $Xsed -e "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "X$lt_prog_compiler_static_CXX" | $Xsed -e "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "X$lt_cv_prog_compiler_c_o_CXX" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "X$archive_cmds_need_lc_CXX" | $Xsed -e "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "X$enable_shared_with_static_runtimes_CXX" | $Xsed -e "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "X$export_dynamic_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "X$whole_archive_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "X$compiler_needs_object_CXX" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "X$old_archive_from_new_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "X$old_archive_from_expsyms_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "X$archive_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "X$archive_expsym_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "X$module_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "X$module_expsym_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "X$with_gnu_ld_CXX" | $Xsed -e "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "X$allow_undefined_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "X$no_undefined_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "X$hardcode_libdir_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld_CXX='`$ECHO "X$hardcode_libdir_flag_spec_ld_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "X$hardcode_libdir_separator_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "X$hardcode_direct_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "X$hardcode_direct_absolute_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "X$hardcode_minus_L_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "X$hardcode_shlibpath_var_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "X$hardcode_automatic_CXX" | $Xsed -e "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "X$inherit_rpath_CXX" | $Xsed -e "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "X$link_all_deplibs_CXX" | $Xsed -e "$delay_single_quote_subst"`' +fix_srcfile_path_CXX='`$ECHO "X$fix_srcfile_path_CXX" | $Xsed -e "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "X$always_export_symbols_CXX" | $Xsed -e "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "X$export_symbols_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "X$exclude_expsyms_CXX" | $Xsed -e "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "X$include_expsyms_CXX" | $Xsed -e "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "X$prelink_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "X$file_list_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "X$hardcode_action_CXX" | $Xsed -e "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "X$compiler_lib_search_dirs_CXX" | $Xsed -e "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "X$predep_objects_CXX" | $Xsed -e "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "X$postdep_objects_CXX" | $Xsed -e "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "X$predeps_CXX" | $Xsed -e "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "X$postdeps_CXX" | $Xsed -e "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "X$compiler_lib_search_path_CXX" | $Xsed -e "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# Quote evaled strings. +for var in SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +AR \ +AR_FLAGS \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +SHELL \ +ECHO \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_wl \ +lt_prog_compiler_pic \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_flag_spec_ld \ +hardcode_libdir_separator \ +fix_srcfile_path \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +finish_eval \ +old_striplib \ +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_flag_spec_ld_CXX \ +hardcode_libdir_separator_CXX \ +fix_srcfile_path_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX; do + case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Fix-up fallback echo if it was mangled by the above quoting rules. +case \$lt_ECHO in +*'\\\$0 --fallback-echo"') lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\` + ;; +esac + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Doxyfile") CONFIG_FILES="$CONFIG_FILES Doxyfile" ;; + "dbus/dbus-arch-deps.h") CONFIG_FILES="$CONFIG_FILES dbus/dbus-arch-deps.h" ;; + "bus/system.conf") CONFIG_FILES="$CONFIG_FILES bus/system.conf" ;; + "bus/session.conf") CONFIG_FILES="$CONFIG_FILES bus/session.conf" ;; + "bus/messagebus") CONFIG_FILES="$CONFIG_FILES bus/messagebus" ;; + "bus/rc.messagebus") CONFIG_FILES="$CONFIG_FILES bus/rc.messagebus" ;; + "bus/dbus-daemon.1") CONFIG_FILES="$CONFIG_FILES bus/dbus-daemon.1" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "dbus/Makefile") CONFIG_FILES="$CONFIG_FILES dbus/Makefile" ;; + "bus/Makefile") CONFIG_FILES="$CONFIG_FILES bus/Makefile" ;; + "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;; + "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; + "test/name-test/Makefile") CONFIG_FILES="$CONFIG_FILES test/name-test/Makefile" ;; + "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "dbus-1.pc") CONFIG_FILES="$CONFIG_FILES dbus-1.pc" ;; + "test/data/valid-config-files/debug-allow-all.conf") CONFIG_FILES="$CONFIG_FILES test/data/valid-config-files/debug-allow-all.conf" ;; + "test/data/valid-config-files/debug-allow-all-sha1.conf") CONFIG_FILES="$CONFIG_FILES test/data/valid-config-files/debug-allow-all-sha1.conf" ;; + "test/data/valid-config-files-system/debug-allow-all-pass.conf") CONFIG_FILES="$CONFIG_FILES test/data/valid-config-files-system/debug-allow-all-pass.conf" ;; + "test/data/valid-config-files-system/debug-allow-all-fail.conf") CONFIG_FILES="$CONFIG_FILES test/data/valid-config-files-system/debug-allow-all-fail.conf" ;; + "test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service") CONFIG_FILES="$CONFIG_FILES test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service" ;; + "test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service") CONFIG_FILES="$CONFIG_FILES test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service" ;; + "test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service") CONFIG_FILES="$CONFIG_FILES test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service" ;; + "test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service") CONFIG_FILES="$CONFIG_FILES test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service" ;; + "test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service") CONFIG_FILES="$CONFIG_FILES test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service" ;; + "test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service") CONFIG_FILES="$CONFIG_FILES test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service" ;; + "test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service") CONFIG_FILES="$CONFIG_FILES test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service" ;; + "test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service") CONFIG_FILES="$CONFIG_FILES test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service" ;; + "test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service") CONFIG_FILES="$CONFIG_FILES test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service" ;; + "test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service") CONFIG_FILES="$CONFIG_FILES test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service" ;; + "test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service") CONFIG_FILES="$CONFIG_FILES test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service" ;; + "test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service") CONFIG_FILES="$CONFIG_FILES test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service" ;; + "test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service") CONFIG_FILES="$CONFIG_FILES test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service" ;; + + *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + $as_echo "$as_me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=' ' +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\).*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\).*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5 +$as_echo "$as_me: error: could not setup config files machinery" >&2;} + { (exit 1); exit 1; }; } +_ACEOF + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_t"; then + break + elif $ac_last_try; then + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5 +$as_echo "$as_me: error: could not setup config headers machinery" >&2;} + { (exit 1); exit 1; }; } +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5 +$as_echo "$as_me: error: invalid tag $ac_tag" >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + ac_file_inputs="$ac_file_inputs '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:$LINENO: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +$as_echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } + if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$tmp/config.h" "$ac_file" \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5 +$as_echo "$as_me: error: could not create -" >&2;} + { (exit 1); exit 1; }; } + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:$LINENO: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir=$dirpart/$fdir + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +$as_echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that 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 GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="CXX " + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that does not interpret backslashes. +ECHO=$lt_ECHO + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $* )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "X${3}" \ + | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[^=]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$@"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1+=\$2" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1=\$$1\$2" +} + +_LT_EOF + ;; + esac + + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + + esac +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + +echo " + D-Bus $VERSION + ============== + + prefix: ${prefix} + exec_prefix: ${exec_prefix} + libdir: ${EXPANDED_LIBDIR} + libexecdir: ${EXPANDED_LIBEXECDIR} + bindir: ${EXPANDED_BINDIR} + sysconfdir: ${EXPANDED_SYSCONFDIR} + localstatedir: ${EXPANDED_LOCALSTATEDIR} + datadir: ${EXPANDED_DATADIR} + source code location: ${srcdir} + compiler: ${CC} + cflags: ${CFLAGS} + cppflags: ${CPPFLAGS} + cxxflags: ${CXXFLAGS} + 64-bit int: ${DBUS_INT64_TYPE} + 32-bit int: ${DBUS_INT32_TYPE} + 16-bit int: ${DBUS_INT16_TYPE} + Doxygen: ${DOXYGEN} + xmlto: ${XMLTO}" + +echo " + Maintainer mode: ${USE_MAINTAINER_MODE} + gcc coverage profiling: ${enable_gcov} + Building unit tests: ${enable_tests} + Building verbose mode: ${enable_verbose_mode} + Building assertions: ${enable_asserts} + Building checks: ${enable_checks} + Building SELinux support: ${have_selinux} + Building inotify support: ${have_inotify} + Building dnotify support: ${have_dnotify} + Building kqueue support: ${have_kqueue} + Building X11 code: ${enable_x11} + Building Doxygen docs: ${enable_doxygen_docs} + Building XML docs: ${enable_xml_docs} + Building cache support: ${enable_userdb_cache} + Gettext libs (empty OK): ${INTLLIBS} + Using XML parser: ${with_xml} + Init scripts style: ${with_init_scripts} + Abstract socket names: ${ac_cv_have_abstract_sockets} + System bus socket: ${DBUS_SYSTEM_SOCKET} + System bus address: ${DBUS_SYSTEM_BUS_DEFAULT_ADDRESS} + System bus PID file: ${DBUS_SYSTEM_PID_FILE} + Session bus socket dir: ${DBUS_SESSION_SOCKET_DIR} + Console auth dir: ${DBUS_CONSOLE_AUTH_DIR} + Console owner file: ${have_console_owner_file} + Console owner file path: ${DBUS_CONSOLE_OWNER_FILE} + System bus user: ${DBUS_USER} + Session bus services dir: ${EXPANDED_DATADIR}/dbus-1/services + 'make check' socket dir: ${TEST_SOCKET_DIR} +" + +if test x$enable_tests = xyes; then + echo "NOTE: building with unit tests increases the size of the installed library and renders it insecure." +fi +if test x$enable_tests = xyes -a x$enable_asserts = xno; then + echo "NOTE: building with unit tests but without assertions means tests may not properly report failures (this configuration is only useful when doing something like profiling the tests)" +fi +if test x$enable_gcov = xyes; then + echo "NOTE: building with coverage profiling is definitely for developers only." +fi +if test x$enable_verbose_mode = xyes; then + echo "NOTE: building with verbose mode increases library size, may slightly increase security risk, and decreases performance." +fi +if test x$enable_asserts = xyes; then + echo "NOTE: building with assertions increases library size and decreases performance." +fi +if test x$enable_checks = xno; then + echo "NOTE: building without checks for arguments passed to public API makes it harder to debug apps using D-Bus, but will slightly decrease D-Bus library size and _very_ slightly improve performance." +fi +if test x$dbus_use_libxml = xtrue; then + echo + echo "WARNING: You have chosen to use libxml as your xml parser however this code path is not maintained by the D-Bus developers and if it breaks you get to keep the pieces. If you have selected this option in err please reconfigure with expat (e.g. --with-xml=expat)." +fi diff --git a/configure.in b/configure.in new file mode 100644 index 00000000..486c612d --- /dev/null +++ b/configure.in @@ -0,0 +1,1567 @@ +dnl -*- mode: m4 -*- +AC_PREREQ(2.52) + +m4_define([dbus_major_version], [1]) +m4_define([dbus_minor_version], [2]) +m4_define([dbus_micro_version], [24]) +m4_define([dbus_version], + [dbus_major_version.dbus_minor_version.dbus_micro_version]) +AC_INIT(dbus, [dbus_version]) + +AC_CANONICAL_HOST + +AM_INIT_AUTOMAKE([1.9 tar-ustar]) +AM_CONFIG_HEADER(config.h) + +# Honor aclocal flags +ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS" + +GETTEXT_PACKAGE=dbus-1 +AC_SUBST(GETTEXT_PACKAGE) +AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[The name of the gettext domain]) + + ## must come before we use the $USE_MAINTAINER_MODE variable later +AM_MAINTAINER_MODE + +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +# libtool versioning - this applies to libdbus +# +# See http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 for details +# + +## increment if the interface has additions, changes, removals. +LT_CURRENT=7 + +## increment any time the source changes; set to +## 0 if you increment CURRENT +LT_REVISION=0 + +## increment if any interfaces have been added; set to 0 +## if any interfaces have been changed or removed. removal has +## precedence over adding, so set to 0 if both happened. +LT_AGE=4 + +AC_SUBST(LT_CURRENT) +AC_SUBST(LT_REVISION) +AC_SUBST(LT_AGE) + +DBUS_MAJOR_VERSION=dbus_major_version +DBUS_MINOR_VERSION=dbus_minor_version +DBUS_MICRO_VERSION=dbus_micro_version +DBUS_VERSION=dbus_major_version.dbus_minor_version.dbus_micro_version + +AC_SUBST(DBUS_MAJOR_VERSION) +AC_SUBST(DBUS_MINOR_VERSION) +AC_SUBST(DBUS_MICRO_VERSION) +AC_SUBST(DBUS_VERSION) + +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_CXX +AC_ISC_POSIX +AC_HEADER_STDC +AC_C_INLINE +AM_PROG_LIBTOOL + +AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[enable unit test code]),enable_tests=$enableval,enable_tests=$USE_MAINTAINER_MODE) +AC_ARG_ENABLE(ansi, AS_HELP_STRING([--enable-ansi],[enable -ansi -pedantic gcc flags]),enable_ansi=$enableval,enable_ansi=no) +AC_ARG_ENABLE(verbose-mode, AS_HELP_STRING([--enable-verbose-mode],[support verbose debug mode]),enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE) +AC_ARG_ENABLE(asserts, AS_HELP_STRING([--enable-asserts],[include assertion checks]),enable_asserts=$enableval,enable_asserts=$USE_MAINTAINER_MODE) +AC_ARG_ENABLE(checks, AS_HELP_STRING([--enable-checks],[include sanity checks on public API]),enable_checks=$enableval,enable_checks=yes) +AC_ARG_ENABLE(xml-docs, AS_HELP_STRING([--enable-xml-docs],[build XML documentation (requires xmlto)]),enable_xml_docs=$enableval,enable_xml_docs=auto) +AC_ARG_ENABLE(doxygen-docs, AS_HELP_STRING([--enable-doxygen-docs],[build DOXYGEN documentation (requires Doxygen)]),enable_doxygen_docs=$enableval,enable_doxygen_docs=auto) +AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov],[compile with coverage profiling instrumentation (gcc only)]),enable_gcov=$enableval,enable_gcov=no) +AC_ARG_ENABLE(abstract-sockets, AS_HELP_STRING([--enable-abstract-sockets],[use abstract socket namespace (linux only)]),enable_abstract_sockets=$enableval,enable_abstract_sockets=auto) +AC_ARG_ENABLE(selinux, AS_HELP_STRING([--enable-selinux],[build with SELinux support]),enable_selinux=$enableval,enable_selinux=auto) +AC_ARG_ENABLE(libaudit,AS_HELP_STRING([--enable-libaudit],[build audit daemon support for SELinux]),enable_libaudit=$enableval,enable_libaudit=auto) +AC_ARG_ENABLE(dnotify, AS_HELP_STRING([--enable-dnotify],[build with dnotify support (linux only)]),enable_dnotify=$enableval,enable_dnotify=auto) +AC_ARG_ENABLE(inotify, AS_HELP_STRING([--enable-inotify],[build with inotify support (linux only)]),enable_inotify=$enableval,enable_inotify=auto) +AC_ARG_ENABLE(kqueue, AS_HELP_STRING([--enable-kqueue],[build with kqueue support]),enable_kqueue=$enableval,enable_kqueue=auto) +AC_ARG_ENABLE(console-owner-file, AS_HELP_STRING([--enable-console-owner-file],[enable console owner file]),enable_console_owner_file=$enableval,enable_console_owner_file=auto) +AC_ARG_ENABLE(userdb-cache, AS_HELP_STRING([--enable-userdb-cache],[build with userdb-cache support]),enable_userdb_cache=$enableval,enable_userdb_cache=yes) + +AC_ARG_WITH(xml, AS_HELP_STRING([--with-xml=[libxml/expat]],[XML library to use])) +AC_ARG_WITH(init-scripts, AS_HELP_STRING([--with-init-scripts=[redhat]],[Style of init scripts to install])) +AC_ARG_WITH(session-socket-dir, AS_HELP_STRING([--with-session-socket-dir=[dirname]],[Where to put sockets for the per-login-session message bus])) +AC_ARG_WITH(test-socket-dir, AS_HELP_STRING([--with-test-socket-dir=[dirname]],[Where to put sockets for make check])) +AC_ARG_WITH(system-pid-file, AS_HELP_STRING([--with-system-pid-file=[pidfile]],[PID file for systemwide daemon])) +AC_ARG_WITH(system-socket, AS_HELP_STRING([--with-system-socket=[filename]],[UNIX domain socket for systemwide daemon])) +AC_ARG_WITH(console-auth-dir, AS_HELP_STRING([--with-console-auth-dir=[dirname]],[directory to check for console ownerhip])) +AC_ARG_WITH(console-owner-file, AS_HELP_STRING([--with-console-owner-file=[filename]],[file whose owner determines current console owner])) +AC_ARG_WITH(dbus_user, AS_HELP_STRING([--with-dbus-user=],[User for running the DBUS daemon (messagebus)])) +AC_ARG_WITH(dbus_daemondir, AS_HELP_STRING([--with-dbus-daemondir=[dirname]],[Directory for installing the DBUS daemon])) + +AC_DEFINE(DBUS_UNIX,1,[dbus on unix]) + +dnl DBUS_BUILD_TESTS controls unit tests built in to .c files +dnl and also some stuff in the test/ subdir +AM_CONDITIONAL(DBUS_BUILD_TESTS, test x$enable_tests = xyes) +if test x$enable_tests = xyes; then + AC_DEFINE(DBUS_BUILD_TESTS,1,[Build test code]) +fi + +if test x$enable_verbose_mode = xyes; then + AC_DEFINE(DBUS_ENABLE_VERBOSE_MODE,1,[Support a verbose mode]) +fi + +if test x$enable_asserts = xno; then + AC_DEFINE(DBUS_DISABLE_ASSERT,1,[Disable assertion checking]) + AC_DEFINE(G_DISABLE_ASSERT,1,[Disable GLib assertion macros]) + R_DYNAMIC_LDFLAG="" +else + # -rdynamic is needed for glibc's backtrace_symbols to work. + # No clue how much overhead this adds, but it's useful + # to do this on any assertion failure, + # so for now it's enabled anytime asserts are (currently not + # in production builds). + + # To get -rdynamic you pass -export-dynamic to libtool. + AC_DEFINE(DBUS_BUILT_R_DYNAMIC,1,[whether -export-dynamic was passed to libtool]) + R_DYNAMIC_LDFLAG=-export-dynamic +fi +AC_SUBST(R_DYNAMIC_LDFLAG) + +if test x$enable_checks = xno; then + AC_DEFINE(DBUS_DISABLE_CHECKS,1,[Disable public API sanity checking]) + AC_DEFINE(G_DISABLE_CHECKS,1,[Disable GLib public API sanity checking]) +fi + +if test x$enable_userdb_cache = xyes; then + AC_DEFINE(DBUS_ENABLE_USERDB_CACHE,1,[Build with caching of user data]) +fi + +if test x$enable_gcov = xyes; then + ## so that config.h changes when you toggle gcov support + AC_DEFINE_UNQUOTED(DBUS_GCOV_ENABLED, 1, [Defined if gcov is enabled to force a rebuild due to config.h changing]) + + AC_MSG_CHECKING([for gcc 3.3 version of gcov file format]) + have_gcc33_gcov=no + AC_RUN_IFELSE( [AC_LANG_PROGRAM( , [[ if (__GNUC__ >=3 && __GNUC_MINOR__ >= 3) exit (0); else exit (1); ]])], + have_gcc33_gcov=yes) + if test x$have_gcc33_gcov = xyes ; then + AC_DEFINE_UNQUOTED(DBUS_HAVE_GCC33_GCOV, 1, [Defined if we have gcc 3.3 and thus the new gcov format]) + fi + AC_MSG_RESULT($have_gcc33_gcov) +fi +AM_CONDITIONAL(DBUS_GCOV_ENABLED, test x$enable_gcov = xyes) + +# glibc21.m4 serial 3 +dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +# Test for the GNU C Library, version 2.1 or newer. +# From Bruno Haible. + +AC_CACHE_CHECK(whether we are using the GNU C Library 2.1 or newer, + ac_cv_gnu_library_2_1, + [AC_EGREP_CPP([Lucky GNU user], + [ +#include +#ifdef __GNU_LIBRARY__ + #if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || (__GLIBC__ > 2) + Lucky GNU user + #endif +#endif + ], + ac_cv_gnu_library_2_1=yes, + ac_cv_gnu_library_2_1=no) + ] +) + +#### Integer sizes + +AC_CHECK_SIZEOF(char) +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(void *) +AC_CHECK_SIZEOF(long long) +AC_CHECK_SIZEOF(__int64) + +### See what our 64 bit type is called +AC_MSG_CHECKING([64-bit integer type]) + +case 8 in +$ac_cv_sizeof_int) + dbusint64=int + dbusint64_constant='(val)' + dbusuint64_constant='(val)' + dbusint64_printf_modifier='""' + ;; +$ac_cv_sizeof_long) + dbusint64=long + dbusint64_constant='(val##L)' + dbusuint64_constant='(val##UL)' + dbusint64_printf_modifier='"l"' + ;; +$ac_cv_sizeof_long_long) + dbusint64='long long' + dbusint64_constant='(val##LL)' + dbusuint64_constant='(val##ULL)' + # Ideally we discover what the format is, but this is + # only used in verbose mode, so eh... + if test x"$ac_cv_gnu_library_2_1" = xyes; then + dbusint64_printf_modifier='"ll"' + fi + ;; +$ac_cv_sizeof___int64) + dbusint64=__int64 + dbusint64_constant='(val##i64)' + dbusuint64_constant='(val##ui64)' + # See above case + if test x"$ac_cv_gnu_library_2_1" = xyes; then + dbusint64_printf_modifier='"ll"' + fi + ;; +esac + +if test -z "$dbusint64" ; then + DBUS_INT64_TYPE="no_int64_type_detected" + DBUS_HAVE_INT64=0 + DBUS_INT64_CONSTANT= + DBUS_UINT64_CONSTANT= + AC_MSG_RESULT([none found]) +else + DBUS_INT64_TYPE="$dbusint64" + DBUS_HAVE_INT64=1 + DBUS_INT64_CONSTANT="$dbusint64_constant" + DBUS_UINT64_CONSTANT="$dbusuint64_constant" + if test x"$dbusint64_printf_modifier" != x; then + AC_DEFINE_UNQUOTED(DBUS_INT64_PRINTF_MODIFIER, [$dbusint64_printf_modifier], [Define to printf modifier for 64 bit integer type]) + fi + AC_MSG_RESULT($DBUS_INT64_TYPE) +fi + +AC_SUBST(DBUS_INT64_TYPE) +AC_SUBST(DBUS_INT64_CONSTANT) +AC_SUBST(DBUS_UINT64_CONSTANT) +AC_SUBST(DBUS_HAVE_INT64) + +### see what 32-bit int is called +AC_MSG_CHECKING([32-bit integer type]) + +case 4 in +$ac_cv_sizeof_short) + dbusint32=int + ;; +$ac_cv_sizeof_int) + dbusint32=int + ;; +$ac_cv_sizeof_long) + dbusint32=long + ;; +esac + +if test -z "$dbusint32" ; then + DBUS_INT32_TYPE="no_int32_type_detected" + AC_MSG_ERROR([No 32-bit integer type found]) +else + DBUS_INT32_TYPE="$dbusint32" + AC_MSG_RESULT($DBUS_INT32_TYPE) +fi + +AC_SUBST(DBUS_INT32_TYPE) + +### see what 16-bit int is called +AC_MSG_CHECKING([16-bit integer type]) + +case 2 in +$ac_cv_sizeof_short) + dbusint16=short + ;; +$ac_cv_sizeof_int) + dbusint16=int + ;; +esac + +if test -z "$dbusint16" ; then + DBUS_INT16_TYPE="no_int16_type_detected" + AC_MSG_ERROR([No 16-bit integer type found]) +else + DBUS_INT16_TYPE="$dbusint16" + AC_MSG_RESULT($DBUS_INT16_TYPE) +fi + +AC_SUBST(DBUS_INT16_TYPE) + +## byte order +case $host_os in + darwin*) + # check at compile-time, so that it is possible to build universal + # (with multiple architectures at once on the compile line) + AH_VERBATIM([WORDS_BIGENDIAN_DARWIN], [ + /* Use the compiler-provided endianness defines to allow universal compiling. */ + #if defined(__BIG_ENDIAN__) + #define WORDS_BIGENDIAN 1 + #endif + ]) + ;; + *) + AC_C_BIGENDIAN + ;; +esac + +dnl ********************************** +dnl *** va_copy checks (from GLib) *** +dnl ********************************** +dnl we currently check for all three va_copy possibilities, so we get +dnl all results in config.log for bug reports. +AC_CACHE_CHECK([for an implementation of va_copy()],dbus_cv_va_copy,[ + AC_LINK_IFELSE([#include +#include + static void f (int i, ...) { + va_list args1, args2; + va_start (args1, i); + va_copy (args2, args1); + if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) + exit (1); + va_end (args1); va_end (args2); + } + int main() { + f (0, 42); + return 0; + }], + [dbus_cv_va_copy=yes], + [dbus_cv_va_copy=no]) +]) +AC_CACHE_CHECK([for an implementation of __va_copy()],dbus_cv___va_copy,[ + AC_LINK_IFELSE([#include +#include + static void f (int i, ...) { + va_list args1, args2; + va_start (args1, i); + __va_copy (args2, args1); + if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) + exit (1); + va_end (args1); va_end (args2); + } + int main() { + f (0, 42); + return 0; + }], + [dbus_cv___va_copy=yes], + [dbus_cv___va_copy=no]) +]) + +if test "x$dbus_cv_va_copy" = "xyes"; then + dbus_va_copy_func=va_copy +else if test "x$dbus_cv___va_copy" = "xyes"; then + dbus_va_copy_func=__va_copy +fi +fi + +if test -n "$dbus_va_copy_func"; then + AC_DEFINE_UNQUOTED(DBUS_VA_COPY,$dbus_va_copy_func,[A 'va_copy' style function]) +fi + +AC_LANG_PUSH(C) +AC_CACHE_CHECK([whether va_lists can be copied by value], + dbus_cv_va_val_copy, + [AC_RUN_IFELSE([AC_LANG_PROGRAM( +[[ + #include + #include +]], +[[ + static void f (int i, ...) { + va_list args1, args2; + va_start (args1, i); + args2 = args1; + if (va_arg (args2, int) != 42 || va_arg (args1, int) != 42) + exit (1); + va_end (args1); va_end (args2); + } + int main() { + f (0, 42); + return 0; + } +]])], + [dbus_cv_va_val_copy=yes], + [dbus_cv_va_val_copy=no], + [dbus_cv_va_val_copy=yes]) +]) +AC_LANG_POP(C) + +if test "x$dbus_cv_va_val_copy" = "xno"; then + AC_DEFINE(DBUS_VA_COPY_AS_ARRAY,1, ['va_lists' cannot be copies as values]) +fi + + +#### Atomic integers (checks by Sebastian Wilhelmi for GLib) +AC_MSG_CHECKING([whether to use inline assembler routines for atomic integers]) +have_atomic_inc_cond=0 +if test x"$GCC" = xyes; then + if test "x$enable_ansi" = "xyes"; then + AC_MSG_RESULT([no]) + else + case $host_cpu in + i386) + AC_MSG_RESULT([no]) + ;; + i?86) + case $host_os in + darwin*) + AC_MSG_RESULT([darwin]) + # check at compile-time, so that it is possible to build universal + # (with multiple architectures at once on the compile line) + have_atomic_inc_cond="(defined(__i386__) || defined(__x86_64__))" + ;; + *) + AC_MSG_RESULT([i486]) + have_atomic_inc_cond=1 + ;; + esac + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac + fi +fi +AC_DEFINE_UNQUOTED([DBUS_USE_ATOMIC_INT_486_COND], [$have_atomic_inc_cond], + [Always defined; expands to 1 if we should use atomic integer implementation for 486, else 0]) +AC_DEFINE_UNQUOTED(DBUS_HAVE_ATOMIC_INT_COND, [$have_atomic_inc_cond], + [Always defined; expands to 1 if we have an atomic integer implementation, else 0]) + +#### Various functions +AC_SEARCH_LIBS(socket,[socket network]) +AC_CHECK_FUNC(gethostbyname,,[AC_CHECK_LIB(nsl,gethostbyname)]) + +AC_CHECK_FUNCS(vsnprintf vasprintf nanosleep usleep setenv clearenv unsetenv socketpair getgrouplist fpathconf setrlimit poll) + +#### Check for broken poll; taken from Glib's configure + +AC_MSG_CHECKING([for broken poll]) +AC_RUN_IFELSE([AC_LANG_SOURCE([[ + #include + #include + #include + #ifdef HAVE_SYS_POLL_H + #include + #endif + int main(void) { + struct pollfd fds[1]; + int fd; + fd = open("/dev/null", 1); + fds[0].fd = fd; + fds[0].events = POLLIN; + fds[0].revents = 0; + if (poll(fds, 1, 0) < 0 || (fds[0].revents & POLLNVAL) != 0) { + exit(1); /* Does not work for devices -- fail */ + } + exit(0); + }]])], + [broken_poll=no], + [broken_poll=yes + AC_DEFINE(BROKEN_POLL,1,[poll doesn't work on devices])], + [broken_poll="no (cross compiling)"]) +AC_MSG_RESULT($broken_poll) + +AC_MSG_CHECKING(for dirfd) +AC_TRY_LINK([ +#include +#include +],[ +DIR *dirp; +dirp = opendir("."); +dirfd(dirp); +closedir(dirp); +], +dbus_have_dirfd=yes, dbus_have_dirfd=no) +AC_MSG_RESULT($dbus_have_dirfd) +if test "$dbus_have_dirfd" = yes; then + AC_DEFINE(HAVE_DIRFD,1,[Have dirfd function]) +else + AC_MSG_CHECKING(for DIR *dirp->dd_fd) + AC_TRY_LINK([ +#include +#include + ],[ +DIR *dirp; +int fd; +dirp = opendir("."); +fd = dirp->dd_fd; +closedir(dirp); + ], + dbus_have_ddfd=yes, dbus_have_ddfd=no) + AC_MSG_RESULT($dbus_have_ddfd) + if test "$dbus_have_ddfd" = yes; then + AC_DEFINE(HAVE_DDFD,1,[Have the ddfd member of DIR]) + fi +fi + +AC_CHECK_HEADERS(execinfo.h, [AC_CHECK_FUNCS(backtrace)]) + +AC_CHECK_HEADERS(errno.h) + +AC_CHECK_HEADERS(unistd.h) + +# Add -D_POSIX_PTHREAD_SEMANTICS if on Solaris +# +case $host_os in + solaris*) + CFLAGS="$CFLAGS -D_POSIX_PTHREAD_SEMANTICS" ;; +esac + +# checking for a posix version of getpwnam_r +# if we are cross compiling and can not run the test +# assume getpwnam_r is the posix version +# it is up to the person cross compiling to change +# this behavior if desired +AC_LANG_PUSH(C) +AC_CACHE_CHECK([for posix getpwnam_r], + ac_cv_func_posix_getpwnam_r, + [AC_RUN_IFELSE([AC_LANG_PROGRAM( +[[ +#include +#include +]], +[[ + char buffer[10000]; + struct passwd pwd, *pwptr = &pwd; + int error; + errno = 0; + error = getpwnam_r ("", &pwd, buffer, + sizeof (buffer), &pwptr); + return (error < 0 && errno == ENOSYS) + || error == ENOSYS; +]])], + [ac_cv_func_posix_getpwnam_r=yes], + [ac_cv_func_posix_getpwnam_r=no], + [ac_cv_func_posix_getpwnam_r=yes] +)]) +AC_LANG_POP(C) + +if test "$ac_cv_func_posix_getpwnam_r" = yes; then + AC_DEFINE(HAVE_POSIX_GETPWNAM_R,1, + [Have POSIX function getpwnam_r]) +else + AC_CACHE_CHECK([for nonposix getpwnam_r], + ac_cv_func_nonposix_getpwnam_r, + [AC_TRY_LINK([#include ], + [char buffer[10000]; + struct passwd pwd; + getpwnam_r ("", &pwd, buffer, + sizeof (buffer));], + [ac_cv_func_nonposix_getpwnam_r=yes], + [ac_cv_func_nonposix_getpwnam_r=no])]) + if test "$ac_cv_func_nonposix_getpwnam_r" = yes; then + AC_DEFINE(HAVE_NONPOSIX_GETPWNAM_R,1, + [Have non-POSIX function getpwnam_r]) + fi +fi + +dnl check for socklen_t +AC_MSG_CHECKING(whether socklen_t is defined) +AC_TRY_COMPILE([ +#include +#include +#include +],[ +socklen_t foo; +foo = 1; +],dbus_have_socklen_t=yes,dbus_have_socklen_t=no) +AC_MSG_RESULT($dbus_have_socklen_t) + +if test "x$dbus_have_socklen_t" = "xyes"; then + AC_DEFINE(HAVE_SOCKLEN_T,1,[Have socklen_t type]) +fi + +dnl check for writev header and writev function so we're +dnl good to go if HAVE_WRITEV gets defined. +AC_CHECK_HEADERS(sys/uio.h, [AC_CHECK_FUNCS(writev)]) + +dnl needed on darwin for NAME_MAX +AC_CHECK_HEADERS(sys/syslimits.h) + +dnl check for flavours of varargs macros (test from GLib) +AC_MSG_CHECKING(for ISO C99 varargs macros in C) +AC_TRY_COMPILE([],[ +int a(int p1, int p2, int p3); +#define call_a(...) a(1,__VA_ARGS__) +call_a(2,3); +],dbus_have_iso_c_varargs=yes,dbus_have_iso_c_varargs=no) +AC_MSG_RESULT($dbus_have_iso_c_varargs) + +AC_MSG_CHECKING(for GNUC varargs macros) +AC_TRY_COMPILE([],[ +int a(int p1, int p2, int p3); +#define call_a(params...) a(1,params) +call_a(2,3); +],dbus_have_gnuc_varargs=yes,dbus_have_gnuc_varargs=no) +AC_MSG_RESULT($dbus_have_gnuc_varargs) + +dnl Output varargs tests +if test x$dbus_have_iso_c_varargs = xyes; then + AC_DEFINE(HAVE_ISO_VARARGS,1,[Have ISO C99 varargs macros]) +fi +if test x$dbus_have_gnuc_varargs = xyes; then + AC_DEFINE(HAVE_GNUC_VARARGS,1,[Have GNU-style varargs macros]) +fi + +dnl Check for various credentials. +AC_MSG_CHECKING(for struct cmsgcred) +AC_TRY_COMPILE([ +#include +#include +],[ +struct cmsgcred cred; + +cred.cmcred_pid = 0; +],dbus_have_struct_cmsgcred=yes,dbus_have_struct_cmsgcred=no) +AC_MSG_RESULT($dbus_have_struct_cmsgcred) + +if test x$dbus_have_struct_cmsgcred = xyes; then + AC_DEFINE(HAVE_CMSGCRED,1,[Have cmsgcred structure]) +fi + +AC_CHECK_FUNCS(getpeerucred getpeereid) + +#### Abstract sockets + +if test x$enable_abstract_sockets = xauto; then +AC_LANG_PUSH(C) +warn_on_xcompile=no +AC_CACHE_CHECK([abstract socket namespace], + ac_cv_have_abstract_sockets, + [AC_RUN_IFELSE([AC_LANG_PROGRAM( +[[ +#include +#include +#include +#include +#include +#include +#include +]], +[[ + int listen_fd; + struct sockaddr_un addr; + + listen_fd = socket (PF_UNIX, SOCK_STREAM, 0); + + if (listen_fd < 0) + { + fprintf (stderr, "socket() failed: %s\n", strerror (errno)); + exit (1); + } + + memset (&addr, '\0', sizeof (addr)); + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, "X/tmp/dbus-fake-socket-path-used-in-configure-test"); + addr.sun_path[0] = '\0'; /* this is what makes it abstract */ + + if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0) + { + fprintf (stderr, "Abstract socket namespace bind() failed: %s\n", + strerror (errno)); + exit (1); + } + else + exit (0); +]])], + [ac_cv_have_abstract_sockets=yes], + [ac_cv_have_abstract_sockets=no], + [ + ac_cv_have_abstract_sockets=no + warn_on_xcompile=yes + ] +)]) +if test x$warn_on_xcompile = xyes ; then + AC_MSG_WARN([Cannot check for abstract sockets when cross-compiling, please use --enable-abstract-sockets]) +fi +AC_LANG_POP(C) +fi + +if test x$enable_abstract_sockets = xyes; then + if test x$ac_cv_have_abstract_sockets = xno; then + AC_MSG_ERROR([Abstract sockets explicitly required, and support not detected.]) + fi +fi + +if test x$enable_abstract_sockets = xno; then + ac_cv_have_abstract_sockets=no; +fi + +if test x$ac_cv_have_abstract_sockets = xyes ; then + DBUS_PATH_OR_ABSTRACT=abstract + AC_DEFINE(HAVE_ABSTRACT_SOCKETS,1,[Have abstract socket namespace]) +else + DBUS_PATH_OR_ABSTRACT=path +fi + +# this is used in addresses to prefer abstract, e.g. +# unix:path=/foo or unix:abstract=/foo +AC_SUBST(DBUS_PATH_OR_ABSTRACT) + +#### Sort out XML library + +# see what we have +AC_CHECK_LIB(expat, XML_ParserCreate_MM, + [ AC_CHECK_HEADERS(expat.h, have_expat=true, have_expat=false) ], + have_expat=false) + +# see what we want to use +dbus_use_libxml=false +dbus_use_expat=false +if test x$with_xml = xexpat; then + if ! $have_expat ; then + AC_MSG_ERROR([Explicitly requested expat but expat not found]) + fi + dbus_use_expat=true +elif test x$with_xml = xlibxml; then + PKG_CHECK_MODULES(LIBXML, libxml-2.0 >= 2.6.0, have_libxml=true, have_libxml=false) + if ! $have_libxml ; then + AC_MSG_ERROR([Explicitly requested libxml but libxml not found]) + fi + dbus_use_libxml=true +else + ### expat is the default because libxml can't currently survive + ### our brutal OOM-handling unit test setup. + ### http://bugzilla.gnome.org/show_bug.cgi?id=109368 + if test x$have_expat = xfalse; then + AC_MSG_ERROR([Could not find expat.h, check config.log for failed attempts]) + fi + ### By default, only use Expat since it's tested and known to work. If you're a + ### general-purpose OS vendor, please don't enable libxml. For embedded use + ### if your OS is built around libxml, that's another case. + dbus_use_expat=true +fi + +AM_CONDITIONAL(DBUS_USE_EXPAT, $dbus_use_expat) +AM_CONDITIONAL(DBUS_USE_LIBXML, $dbus_use_libxml) + +if $dbus_use_expat; then + XML_LIBS=-lexpat + XML_CFLAGS= +fi +if $dbus_use_libxml; then + XML_LIBS=$LIBXML_LIBS + XML_CFLAGS=$LIBXML_CFLAGS +fi + +# Thread lib detection +AC_CHECK_FUNC(pthread_cond_timedwait,[AC_CHECK_LIB(pthread,pthread_cond_timedwait, + [THREAD_LIBS="-lpthread"])]) +save_libs="$LIBS" +LIBS="$LIBS $THREAD_LIBS" +AC_CHECK_FUNC(pthread_condattr_setclock,have_pthread_condattr_setclock=true,have_pthread_condattr_setclock=false) +if test x$have_pthread_condattr_setclock = xtrue; then + AC_SEARCH_LIBS([clock_getres],[rt],[THREAD_LIBS="$THREAD_LIBS -lrt"]) + AC_MSG_CHECKING([for CLOCK_MONOTONIC]) + AC_TRY_COMPILE([#include +#include +], [ +struct timespec monotonic_timer; +pthread_condattr_t attr; +pthread_condattr_init (&attr); +pthread_condattr_setclock (&attr, CLOCK_MONOTONIC); +clock_getres (CLOCK_MONOTONIC,&monotonic_timer); +], have_clock_monotonic=true, have_clock_monotonic=false) +if test x$have_clock_monotonic = xtrue; then + AC_MSG_RESULT([found]) + AC_DEFINE(HAVE_MONOTONIC_CLOCK, 1, [Define if we have CLOCK_MONOTONIC]) +else + AC_MSG_RESULT([not found]) +fi +fi +LIBS="$save_libs" + +# SELinux detection +if test x$enable_selinux = xno ; then + have_selinux=no; +else + # See if we have SELinux library + AC_CHECK_LIB(selinux, is_selinux_enabled, + have_selinux=yes, have_selinux=no) + + # see if we have the SELinux header with the new D-Bus stuff in it + if test x$have_selinux = xyes ; then + AC_MSG_CHECKING([for DBUS Flask permissions in selinux/av_permissions.h]) + AC_TRY_COMPILE([#include ], + [#ifdef DBUS__ACQUIRE_SVC return 0; + #else + #error DBUS__ACQUIRE_SVC not defined + #endif], + have_selinux=yes, have_selinux=no) + AC_MSG_RESULT($have_selinux) + fi + + if test x$enable_selinux = xauto ; then + if test x$have_selinux = xno ; then + AC_MSG_WARN([Sufficiently new SELinux library not found]) + fi + else + if test x$have_selinux = xno ; then + AC_MSG_ERROR([SElinux explicitly required, and SELinux library not found]) + fi + fi +fi + +AM_CONDITIONAL(HAVE_SELINUX, test x$have_selinux = xyes) + +if test x$have_selinux = xyes ; then + # the selinux code creates threads + # which requires libpthread even on linux + AC_CHECK_FUNC(pthread_create,,[AC_CHECK_LIB(pthread,pthread_create, + [SELINUX_THREAD_LIBS="-lpthread"])]) + + SELINUX_LIBS="-lselinux $SELINUX_THREAD_LIBS" + AC_DEFINE(HAVE_SELINUX,1,[SELinux support]) +else + SELINUX_LIBS= +fi + +# inotify checks +if test x$enable_inotify = xno ; then + have_inotify=no; +else + AC_CHECK_HEADERS(sys/inotify.h, have_inotify=yes, have_inotify=no) +fi + +dnl check if inotify backend is enabled +if test x$have_inotify = xyes; then + AC_DEFINE(DBUS_BUS_ENABLE_INOTIFY,1,[Use inotify]) + AC_CHECK_FUNCS(inotify_init1) +fi + +AM_CONDITIONAL(DBUS_BUS_ENABLE_INOTIFY, test x$have_inotify = xyes) + +# dnotify checks +if test x$enable_dnotify = xno ; then + have_dnotify=no; +else + if test x$have_inotify = xno -a x$host_os = xlinux-gnu -o x$host_os = xlinux; then + have_dnotify=yes; + else + have_dnotify=no; + fi +fi + +dnl check if dnotify backend is enabled +if test x$have_dnotify = xyes; then + AC_DEFINE(DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX,1,[Use dnotify on Linux]) +fi + +AM_CONDITIONAL(DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX, test x$have_dnotify = xyes) + +# kqueue checks +if test x$enable_kqueue = xno ; then + have_kqueue=no +else + have_kqueue=yes + AC_CHECK_HEADER(sys/event.h, , have_kqueue=no) + AC_CHECK_FUNC(kqueue, , have_kqueue=no) + + if test x$enable_kqueue = xyes -a x$have_kqueue = xno; then + AC_MSG_ERROR(kqueue support explicitly enabled but not available) + fi +fi + +dnl check if kqueue backend is enabled +if test x$have_kqueue = xyes; then + AC_DEFINE(DBUS_BUS_ENABLE_KQUEUE,1,[Use kqueue]) +fi + +AM_CONDITIONAL(DBUS_BUS_ENABLE_KQUEUE, test x$have_kqueue = xyes) + +dnl console owner file +if test x$enable_console_owner_file = xno ; then + have_console_owner_file=no; +else + case $host_os in + solaris*) + have_console_owner_file=yes; + AC_DEFINE(HAVE_CONSOLE_OWNER_FILE,1,[Have console owner file]) + ;; + *) + have_console_owner_file=no;; + esac +fi + +AM_CONDITIONAL(HAVE_CONSOLE_OWNER_FILE, test x$have_console_owner_file = xyes) + +# libaudit detection +if test x$enable_libaudit = xno ; then + have_libaudit=no; +else + # See if we have audit daemon & capabilities library + AC_CHECK_LIB(audit, audit_log_user_avc_message, + have_libaudit=yes, have_libaudit=no) + if test x$have_libaudit = xyes ; then + AC_CHECK_LIB(cap-ng, capng_clear, + have_libaudit=yes, have_libaudit=no) + fi +fi + +AM_CONDITIONAL(HAVE_LIBAUDIT, test x$have_libaudit = xyes) + +if test x$have_libaudit = xyes ; then + SELINUX_LIBS="$SELINUX_LIBS -laudit -lcap-ng" + AC_DEFINE(HAVE_LIBAUDIT,1,[audit daemon SELinux support]) +fi + +# Check for ADT API +AC_MSG_CHECKING(for ADT API) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +adt_user_context = ADT_USER; +]], [[]])], [ check_adt_audit=yes ], [ check_adt_audit=no ]) + +if test ${check_adt_audit} = yes +then + AC_DEFINE([HAVE_ADT], [], [Adt audit API]) + ADT_LIBS="-lbsm" + LIBS="-lbsm $LIBS" + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + + +#### Set up final flags +DBUS_CLIENT_CFLAGS= +DBUS_CLIENT_LIBS="$THREAD_LIBS" +AC_SUBST(DBUS_CLIENT_CFLAGS) +AC_SUBST(DBUS_CLIENT_LIBS) + +DBUS_BUS_CFLAGS="$XML_CFLAGS" +DBUS_BUS_LIBS="$XML_LIBS $SELINUX_LIBS $INTLLIBS $THREAD_LIBS $ADT_LIBS" +AC_SUBST(DBUS_BUS_CFLAGS) +AC_SUBST(DBUS_BUS_LIBS) + +DBUS_LAUNCHER_CFLAGS="$XML_CFLAGS" +DBUS_LAUNCHER_LIBS="$XML_LIBS $THREAD_LIBS" +AC_SUBST(DBUS_LAUNCHER_CFLAGS) +AC_SUBST(DBUS_LAUNCHER_LIBS) + +DBUS_TEST_CFLAGS= +DBUS_TEST_LIBS="$THREAD_LIBS" +AC_SUBST(DBUS_TEST_CFLAGS) +AC_SUBST(DBUS_TEST_LIBS) + +### X11 detection +AC_PATH_XTRA + +## for now enable_x11 just tracks have_x11, +## there's no --enable-x11 +if test x$no_x = xyes ; then + have_x11=no + enable_x11=no +else + have_x11=yes + enable_x11=yes +fi + +if test x$enable_x11 = xyes ; then + AC_DEFINE(DBUS_BUILD_X11,1,[Build X11-dependent code]) + DBUS_X_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" + DBUS_X_CFLAGS="$X_CFLAGS" +else + DBUS_X_LIBS= + DBUS_X_CFLAGS= +fi + +AC_SUBST(DBUS_X_CFLAGS) +AC_SUBST(DBUS_X_LIBS) + + +#### gcc warning flags + +cc_supports_flag() { + AC_MSG_CHECKING(whether $CC supports "$@") + Cfile=/tmp/foo${$} + touch ${Cfile}.c + $CC -c "$@" ${Cfile}.c -o ${Cfile}.o >/dev/null 2>&1 + rc=$? + rm -f ${Cfile}.c ${Cfile}.o + case $rc in + 0) AC_MSG_RESULT(yes);; + *) AC_MSG_RESULT(no);; + esac + return $rc +} + +ld_supports_flag() { + AC_MSG_CHECKING([whether $LD supports "$@"]) + AC_TRY_LINK([ + int one(void) { return 1; } + int two(void) { return 2; } + ], [ two(); ] , [_ac_ld_flag_supported=yes], [_ac_ld_flag_supported=no]) + + if test "$_ac_ld_flag_supported" = "yes"; then + rm -f conftest.c + touch conftest.c + if $CC -c conftest.c; then + ld_out=`$LD $@ -o conftest conftest.o 2>&1` + ld_ret=$? + if test $ld_ret -ne 0 ; then + _ac_ld_flag_supported=no + elif echo "$ld_out" | egrep 'option ignored|^usage:|unrecognized option|illegal option' >/dev/null ; then + _ac_ld_flag_supported=no + fi + fi + rm -f conftest.c conftest.o conftest + fi + + AC_MSG_RESULT($_ac_ld_flag_supported) + if test "$_ac_ld_flag_supported" = "yes" ; then + return 0 + else + return 1 + fi +} + +if test x$USE_MAINTAINER_MODE = xyes; then + if cc_supports_flag "-Werror"; then + CFLAGS="$CFLAGS -Werror" + fi +fi + +if test "x$GCC" = "xyes"; then + changequote(,)dnl + case " $CFLAGS " in + *[\ \ ]-Wall[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wall" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wchar-subscripts[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wchar-subscripts" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wmissing-declarations[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wmissing-declarations" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wmissing-prototypes[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wmissing-prototypes" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wnested-externs[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wnested-externs" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wpointer-arith[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wpointer-arith" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wcast-align[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wcast-align" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wfloat-equal[\ \ ]*) ;; + *) if cc_supports_flag -Wfloat-equals; then + CFLAGS="$CFLAGS -Wfloat-equal" + fi + ;; + esac + + case " $CFLAGS " in + *[\ \ ]-Wdeclaration-after-statement[\ \ ]*) ;; + *) if cc_supports_flag -Wdeclaration-after-statement; then + CFLAGS="$CFLAGS -Wdeclaration-after-statement" + fi + ;; + esac + + case " $CFLAGS " in + *[\ \ ]-fno-common[\ \ ]*) ;; + *) if cc_supports_flag -fno-common; then + CFLAGS="$CFLAGS -fno-common" + fi + ;; + esac + + case " $CFLAGS " in + *[\ \ ]-fPIC[\ \ ]*) ;; + *) if cc_supports_flag -fPIC; then + PIC_CFLAGS="-fPIC" + if ld_supports_flag -z,relro; then + PIC_LDFLAGS="-Wl,-z,relro" + fi + fi + ;; + esac + + case " $CFLAGS " in + *[\ \ ]-fPIE[\ \ ]*) ;; + *) if cc_supports_flag -fPIE; then + PIE_CFLAGS="-fPIE" + if ld_supports_flag -z,relro; then + PIE_LDFLAGS="-pie -Wl,-z,relro" + else + PIE_LDFLAGS="-pie" + fi + fi + ;; + esac + + ### Disabled warnings, and compiler flag overrides + + # Let's just ignore unused for now + case " $CFLAGS " in + *[\ \ ]-Wno-unused[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wno-unused" ;; + esac + + # This group is for warnings we currently don't pass. + # We would like to, however. Please fix. + + # http://bugs.freedesktop.org/show_bug.cgi?id=17433 + case " $CFLAGS " in + *[\ \ ]-Wno-sign-compare[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -Wno-sign-compare" ;; + esac + case " $CFLAGS " in + *[\ \ ]-Wno-pointer-sign[\ \ ]*) ;; + *) if cc_supports_flag -Wno-pointer-sign; then + CFLAGS="$CFLAGS -Wno-pointer-sign" + fi + ;; + esac + + # This one is special - it's not a warning override. + # http://bugs.freedesktop.org/show_bug.cgi?id=10599 + case " $CFLAGS " in + *[\ \ ]-fno-strict-aliasing[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -fno-strict-aliasing" ;; + esac + ### End disabled warnings + + if test "x$enable_ansi" = "xyes"; then + case " $CFLAGS " in + *[\ \ ]-ansi[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -ansi" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-D_POSIX_C_SOURCE*) ;; + *) CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=199309L" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-D_BSD_SOURCE[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -D_BSD_SOURCE" ;; + esac + + case " $CFLAGS " in + *[\ \ ]-pedantic[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -pedantic" ;; + esac + fi + if test x$enable_gcov = xyes; then + case " $CFLAGS " in + *[\ \ ]-fprofile-arcs[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -fprofile-arcs" ;; + esac + case " $CFLAGS " in + *[\ \ ]-ftest-coverage[\ \ ]*) ;; + *) CFLAGS="$CFLAGS -ftest-coverage" ;; + esac + + ## remove optimization + CFLAGS=`echo "$CFLAGS" | sed -e 's/-O[0-9]*//g'` + fi + changequote([,])dnl +else + if test x$enable_gcov = xyes; then + AC_MSG_ERROR([--enable-gcov can only be used with gcc]) + fi +fi + +AC_SUBST(PIC_CFLAGS) +AC_SUBST(PIC_LDFLAGS) +AC_SUBST(PIE_CFLAGS) +AC_SUBST(PIE_LDFLAGS) + +if ld_supports_flag --gc-sections; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + CFLAGS="-ffunction-sections -fdata-sections $CFLAGS" +fi +AC_SUBST(SECTION_FLAGS) +AC_SUBST(SECTION_LDFLAGS) +AC_MSG_RESULT($ac_gcsections) + +changequote(,)dnl +# compress spaces in flags +CFLAGS=`echo "$CFLAGS" | sed -e 's/ +/ /g'` +CXXFLAGS=`echo "$CXXFLAGS" | sed -e 's/ +/ /g'` +CPPFLAGS=`echo "$CPPFLAGS" | sed -e 's/ +/ /g'` +changequote([,])dnl + +### Doxygen Documentation + +AC_PATH_PROG(DOXYGEN, doxygen, no) + +AC_MSG_CHECKING([whether to build Doxygen documentation]) + +if test x$DOXYGEN = xno ; then + have_doxygen=no +else + have_doxygen=yes +fi + +if test x$enable_doxygen_docs = xauto ; then + if test x$have_doxygen = xno ; then + enable_doxygen_docs=no + else + enable_doxygen_docs=yes + fi +fi + +if test x$enable_doxygen_docs = xyes; then + if test x$have_doxygen = xno; then + AC_MSG_ERROR([Building Doxygen docs explicitly required, but Doxygen not found]) + fi +fi + +AM_CONDITIONAL(DBUS_DOXYGEN_DOCS_ENABLED, test x$enable_doxygen_docs = xyes) +AC_MSG_RESULT(yes) + +### XML Documentation + +AC_PATH_PROG(XMLTO, xmlto, no) + +AC_MSG_CHECKING([whether to build XML documentation]) + +if test x$XMLTO = xno ; then + have_xmlto=no +else + have_xmlto=yes +fi + +if test x$enable_xml_docs = xauto ; then + if test x$have_xmlto = xno ; then + enable_xml_docs=no + else + enable_xml_docs=yes + fi +fi + +if test x$enable_xml_docs = xyes; then + if test x$have_xmlto = xno; then + AC_MSG_ERROR([Building XML docs explicitly required, but xmlto not found]) + fi +fi + +AM_CONDITIONAL(DBUS_XML_DOCS_ENABLED, test x$enable_xml_docs = xyes) +AC_MSG_RESULT(yes) + +#### Have to go $localstatedir->$prefix/var->/usr/local/var + +#### find the actual value for $prefix that we'll end up with +## (I know this is broken and should be done in the Makefile, but +## that's a major pain and almost nobody actually seems to care) +AS_AC_EXPAND(EXPANDED_LOCALSTATEDIR, "$localstatedir") +AS_AC_EXPAND(EXPANDED_SYSCONFDIR, "$sysconfdir") +AS_AC_EXPAND(EXPANDED_BINDIR, "$bindir") +AS_AC_EXPAND(EXPANDED_LIBDIR, "$libdir") +AS_AC_EXPAND(EXPANDED_LIBEXECDIR, "$libexecdir") +AS_AC_EXPAND(EXPANDED_DATADIR, "$datadir") + +#### Check our operating system +operating_system=unknown +if test -f /etc/redhat-release || test -f $EXPANDED_SYSCONFDIR/redhat-release ; then + operating_system=redhat +fi + +if test -f /etc/slackware-version || test -f $EXPANDED_SYSCONFDIR/slackware-version ; then + operating_system=slackware +fi + +#### Sort out init scripts + +if test x$with_init_scripts = x; then + if test xredhat = x$operating_system ; then + with_init_scripts=redhat + else + if test xslackware = x$operating_system ; then + with_init_scripts=slackware + else + with_init_scripts=none + fi + fi +fi + +AM_CONDITIONAL(DBUS_INIT_SCRIPTS_RED_HAT, test x$with_init_scripts = xredhat) + +AM_CONDITIONAL(DBUS_INIT_SCRIPTS_SLACKWARE, test x$with_init_scripts = xslackware) + +##### Set up location for system bus socket +if ! test -z "$with_system_socket"; then + DBUS_SYSTEM_SOCKET=$with_system_socket +else + DBUS_SYSTEM_SOCKET=${EXPANDED_LOCALSTATEDIR}/run/dbus/system_bus_socket +fi + +AC_SUBST(DBUS_SYSTEM_SOCKET) +AC_DEFINE_UNQUOTED(DBUS_SYSTEM_SOCKET,"$DBUS_SYSTEM_SOCKET",[The name of the socket the system bus listens on by default]) + +## system bus only listens on local domain sockets, and never +## on an abstract socket (so only root can create the socket) +DBUS_SYSTEM_BUS_DEFAULT_ADDRESS="unix:path=$DBUS_SYSTEM_SOCKET" +AC_SUBST(DBUS_SYSTEM_BUS_DEFAULT_ADDRESS) +AC_DEFINE_UNQUOTED(DBUS_SYSTEM_BUS_DEFAULT_ADDRESS, "$DBUS_SYSTEM_BUS_DEFAULT_ADDRESS",[The default D-Bus address of the system bus]) + +#### Set up the pid file +if ! test -z "$with_system_pid_file"; then + DBUS_SYSTEM_PID_FILE=$with_system_pid_file +elif test x$with_init_scripts = xredhat ; then + DBUS_SYSTEM_PID_FILE=${EXPANDED_LOCALSTATEDIR}/run/messagebus.pid +else + DBUS_SYSTEM_PID_FILE=${EXPANDED_LOCALSTATEDIR}/run/dbus/pid +fi + +AC_SUBST(DBUS_SYSTEM_PID_FILE) + +#### Directory to check for console ownership +if ! test -z "$with_console_auth_dir"; then + DBUS_CONSOLE_AUTH_DIR=$with_console_auth_dir +else + DBUS_CONSOLE_AUTH_DIR=/var/run/console/ +fi + +AC_SUBST(DBUS_CONSOLE_AUTH_DIR) +AC_DEFINE_UNQUOTED(DBUS_CONSOLE_AUTH_DIR, "$DBUS_CONSOLE_AUTH_DIR", [Directory to check for console ownerhip]) + +#### File to check for console ownership +if test x$have_console_owner_file = xyes; then + if ! test -z "$with_console_owner_file"; then + DBUS_CONSOLE_OWNER_FILE=$with_console_owner_file + else + DBUS_CONSOLE_OWNER_FILE=/dev/console + fi +else + DBUS_CONSOLE_OWNER_FILE= +fi + +AC_SUBST(DBUS_CONSOLE_OWNER_FILE) +AC_DEFINE_UNQUOTED(DBUS_CONSOLE_OWNER_FILE, "$DBUS_CONSOLE_OWNER_FILE", [File to check for console ownerhip]) + +#### User to start the system bus as +if test -z "$with_dbus_user" ; then + DBUS_USER=messagebus +else + DBUS_USER=$with_dbus_user +fi +AC_SUBST(DBUS_USER) +AC_DEFINE_UNQUOTED(DBUS_USER,"$DBUS_USER", [User for running the system BUS daemon]) + +#### Direcotry to install data files into +DBUS_DATADIR=$EXPANDED_DATADIR +AC_SUBST(DBUS_DATADIR) +AC_DEFINE_UNQUOTED(DBUS_DATADIR,"$DBUS_DATADIR", [Directory for installing DBUS data files]) + +#### Directory to install dbus-daemon +if test -z "$with_dbus_daemondir" ; then + DBUS_DAEMONDIR=$EXPANDED_BINDIR +else + DBUS_DAEMONDIR=$with_dbus_daemondir +fi +AC_SUBST(DBUS_DAEMONDIR) +AC_DEFINE_UNQUOTED(DBUS_DAEMONDIR,"$DBUS_DAEMONDIR", [Directory for installing the DBUS daemon]) + +#### Directory to install the other binaries +DBUS_BINDIR="$EXPANDED_BINDIR" +AC_SUBST(DBUS_BINDIR) +AC_DEFINE_UNQUOTED(DBUS_BINDIR,"$DBUS_BINDIR", [Directory for installing the binaries]) + +#### Directory to install the libexec binaries +DBUS_LIBEXECDIR="$EXPANDED_LIBEXECDIR" +AC_SUBST(DBUS_LIBEXECDIR) +AC_DEFINE_UNQUOTED(DBUS_LIBEXECDIR,"$DBUS_LIBEXECDIR", [Directory for installing the libexec binaries]) + +#### Tell tests where to find certain stuff in builddir + +DBUS_PWD=`pwd` +AC_DEFUN([TEST_PATH], [ +TEST_$1=${DBUS_PWD}/test/$2 +AC_DEFINE_UNQUOTED(TEST_$1, "$TEST_$1", + [Full path to test file test/$2 in builddir]) +AC_SUBST(TEST_$1) +]) + +TEST_PATH(VALID_SERVICE_DIR, data/valid-service-files) +TEST_PATH(INVALID_SERVICE_DIR, data/invalid-service-files) +TEST_PATH(VALID_SERVICE_SYSTEM_DIR, data/valid-service-files-system) +TEST_PATH(INVALID_SERVICE_SYSTEM_DIR, data/invalid-service-files-system) +TEST_PATH(SERVICE_BINARY, test-service) +TEST_PATH(SHELL_SERVICE_BINARY, test-shell-service) +TEST_PATH(EXIT_BINARY, test-exit) +TEST_PATH(SEGFAULT_BINARY, test-segfault) +TEST_PATH(SLEEP_FOREVER_BINARY, test-sleep-forever) +TEST_PATH(PRIVSERVER_BINARY, name-test/test-privserver) + +AC_DEFINE_UNQUOTED(TEST_BUS_BINARY, "$DBUS_PWD/bus/dbus-daemon", + [Full path to the daemon in the builddir]) +AC_SUBST(TEST_BUS_BINARY) + +## Export the non-setuid external helper +TEST_LAUNCH_HELPER_BINARY="$DBUS_PWD/bus/dbus-daemon-launch-helper-test" +AC_SUBST(TEST_LAUNCH_HELPER_BINARY) +AC_DEFINE_UNQUOTED(DBUS_TEST_LAUNCH_HELPER_BINARY, "$TEST_LAUNCH_HELPER_BINARY", + [Full path to the launch helper test program in the builddir]) + +#### Find socket directories +if ! test -z "$TMPDIR" ; then + DEFAULT_SOCKET_DIR=$TMPDIR +elif ! test -z "$TEMP" ; then + DEFAULT_SOCKET_DIR=$TEMP +elif ! test -z "$TMP" ; then + DEFAULT_SOCKET_DIR=$TMP +else + DEFAULT_SOCKET_DIR=/tmp +fi + +if ! test -z "$with_test_socket_dir" ; then + TEST_SOCKET_DIR="$with_test_socket_dir" +else + TEST_SOCKET_DIR=$DEFAULT_SOCKET_DIR +fi +AC_SUBST(TEST_SOCKET_DIR) +AC_DEFINE_UNQUOTED(DBUS_TEST_SOCKET_DIR, "$TEST_SOCKET_DIR", [Where to put test sockets]) + +if ! test -z "$with_session_socket_dir" ; then + DBUS_SESSION_SOCKET_DIR="$with_session_socket_dir" +else + DBUS_SESSION_SOCKET_DIR=$DEFAULT_SOCKET_DIR +fi +AC_DEFINE_UNQUOTED(DBUS_SESSION_SOCKET_DIR, "$DBUS_SESSION_SOCKET_DIR", [Where per-session bus puts its sockets]) +AC_SUBST(DBUS_SESSION_SOCKET_DIR) + +AC_DEFINE_UNQUOTED(DBUS_UNIX, "1", [Defined on UNIX and Linux systems and not on Windows]) + +# darwin needs this to initialize the environment +AC_CHECK_HEADERS(crt_externs.h) +AC_CHECK_FUNC(_NSGetEnviron, [AC_DEFINE(HAVE_NSGETENVIRON, 1, [Define if your system needs _NSGetEnviron to set up the environment])]) +AH_VERBATIM(_DARWIN_ENVIRON, +[ +#if defined(HAVE_NSGETENVIRON) && defined(HAVE_CRT_EXTERNS_H) +# include +# include +# define environ (*_NSGetEnviron()) +#endif +]) + +AC_OUTPUT([ +Doxyfile +dbus/dbus-arch-deps.h +bus/system.conf +bus/session.conf +bus/messagebus +bus/rc.messagebus +bus/dbus-daemon.1 +Makefile +dbus/Makefile +bus/Makefile +tools/Makefile +test/Makefile +test/name-test/Makefile +doc/Makefile +dbus-1.pc +test/data/valid-config-files/debug-allow-all.conf +test/data/valid-config-files/debug-allow-all-sha1.conf +test/data/valid-config-files-system/debug-allow-all-pass.conf +test/data/valid-config-files-system/debug-allow-all-fail.conf +test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service +test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service +test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service +test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service +test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service +test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service +test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service +test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service +test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service +test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service +test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service +test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service +test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service +]) + +dnl ========================================================================== +echo " + D-Bus $VERSION + ============== + + prefix: ${prefix} + exec_prefix: ${exec_prefix} + libdir: ${EXPANDED_LIBDIR} + libexecdir: ${EXPANDED_LIBEXECDIR} + bindir: ${EXPANDED_BINDIR} + sysconfdir: ${EXPANDED_SYSCONFDIR} + localstatedir: ${EXPANDED_LOCALSTATEDIR} + datadir: ${EXPANDED_DATADIR} + source code location: ${srcdir} + compiler: ${CC} + cflags: ${CFLAGS} + cppflags: ${CPPFLAGS} + cxxflags: ${CXXFLAGS} + 64-bit int: ${DBUS_INT64_TYPE} + 32-bit int: ${DBUS_INT32_TYPE} + 16-bit int: ${DBUS_INT16_TYPE} + Doxygen: ${DOXYGEN} + xmlto: ${XMLTO}" + +echo " + Maintainer mode: ${USE_MAINTAINER_MODE} + gcc coverage profiling: ${enable_gcov} + Building unit tests: ${enable_tests} + Building verbose mode: ${enable_verbose_mode} + Building assertions: ${enable_asserts} + Building checks: ${enable_checks} + Building SELinux support: ${have_selinux} + Building inotify support: ${have_inotify} + Building dnotify support: ${have_dnotify} + Building kqueue support: ${have_kqueue} + Building X11 code: ${enable_x11} + Building Doxygen docs: ${enable_doxygen_docs} + Building XML docs: ${enable_xml_docs} + Building cache support: ${enable_userdb_cache} + Gettext libs (empty OK): ${INTLLIBS} + Using XML parser: ${with_xml} + Init scripts style: ${with_init_scripts} + Abstract socket names: ${ac_cv_have_abstract_sockets} + System bus socket: ${DBUS_SYSTEM_SOCKET} + System bus address: ${DBUS_SYSTEM_BUS_DEFAULT_ADDRESS} + System bus PID file: ${DBUS_SYSTEM_PID_FILE} + Session bus socket dir: ${DBUS_SESSION_SOCKET_DIR} + Console auth dir: ${DBUS_CONSOLE_AUTH_DIR} + Console owner file: ${have_console_owner_file} + Console owner file path: ${DBUS_CONSOLE_OWNER_FILE} + System bus user: ${DBUS_USER} + Session bus services dir: ${EXPANDED_DATADIR}/dbus-1/services + 'make check' socket dir: ${TEST_SOCKET_DIR} +" + +if test x$enable_tests = xyes; then + echo "NOTE: building with unit tests increases the size of the installed library and renders it insecure." +fi +if test x$enable_tests = xyes -a x$enable_asserts = xno; then + echo "NOTE: building with unit tests but without assertions means tests may not properly report failures (this configuration is only useful when doing something like profiling the tests)" +fi +if test x$enable_gcov = xyes; then + echo "NOTE: building with coverage profiling is definitely for developers only." +fi +if test x$enable_verbose_mode = xyes; then + echo "NOTE: building with verbose mode increases library size, may slightly increase security risk, and decreases performance." +fi +if test x$enable_asserts = xyes; then + echo "NOTE: building with assertions increases library size and decreases performance." +fi +if test x$enable_checks = xno; then + echo "NOTE: building without checks for arguments passed to public API makes it harder to debug apps using D-Bus, but will slightly decrease D-Bus library size and _very_ slightly improve performance." +fi +if test x$dbus_use_libxml = xtrue; then + echo + echo "WARNING: You have chosen to use libxml as your xml parser however this code path is not maintained by the D-Bus developers and if it breaks you get to keep the pieces. If you have selected this option in err please reconfigure with expat (e.g. --with-xml=expat)." +fi diff --git a/dbus-1.pc.in b/dbus-1.pc.in new file mode 100644 index 00000000..866f81ce --- /dev/null +++ b/dbus-1.pc.in @@ -0,0 +1,15 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +system_bus_default_address=@DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ +sysconfdir=@EXPANDED_SYSCONFDIR@ +session_bus_services_dir=@EXPANDED_DATADIR@/dbus-1/services +daemondir=@DBUS_DAEMONDIR@ + +Name: dbus +Description: Free desktop message bus +Version: @VERSION@ +Libs: -L${libdir} -ldbus-1 @DBUS_CLIENT_LIBS@ +Cflags: -I${includedir}/dbus-1.0 -I${libdir}/dbus-1.0/include + diff --git a/dbus/Makefile.am b/dbus/Makefile.am new file mode 100644 index 00000000..597fe08d --- /dev/null +++ b/dbus/Makefile.am @@ -0,0 +1,203 @@ + +configdir=$(sysconfdir)/dbus-1 + +INCLUDES=-I$(top_builddir) -I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) @PIC_CFLAGS@ -DDBUS_COMPILATION \ + -DDBUS_MACHINE_UUID_FILE=\""$(localstatedir)/lib/dbus/machine-id"\" \ + -DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\" \ + -DDBUS_SESSION_CONFIG_FILE=\""$(configdir)/session.conf"\" + +dbusincludedir=$(includedir)/dbus-1.0/dbus +dbusarchincludedir=$(libdir)/dbus-1.0/include/dbus + +lib_LTLIBRARIES=libdbus-1.la + +dbusinclude_HEADERS= \ + dbus.h \ + dbus-address.h \ + dbus-bus.h \ + dbus-connection.h \ + dbus-errors.h \ + dbus-macros.h \ + dbus-memory.h \ + dbus-message.h \ + dbus-misc.h \ + dbus-pending-call.h \ + dbus-protocol.h \ + dbus-server.h \ + dbus-shared.h \ + dbus-signature.h \ + dbus-threads.h \ + dbus-types.h + + +dbusarchinclude_HEADERS= \ + dbus-arch-deps.h + +### source code that goes in the installed client library +### and is specific to library functionality +DBUS_LIB_SOURCES= \ + dbus-address.c \ + dbus-auth.c \ + dbus-auth.h \ + dbus-auth-script.c \ + dbus-auth-script.h \ + dbus-bus.c \ + dbus-connection.c \ + dbus-connection-internal.h \ + dbus-credentials.c \ + dbus-credentials.h \ + dbus-errors.c \ + dbus-keyring.c \ + dbus-keyring.h \ + dbus-marshal-header.c \ + dbus-marshal-header.h \ + dbus-marshal-byteswap.c \ + dbus-marshal-byteswap.h \ + dbus-marshal-recursive.c \ + dbus-marshal-recursive.h \ + dbus-marshal-validate.c \ + dbus-marshal-validate.h \ + dbus-message.c \ + dbus-message-internal.h \ + dbus-message-private.h \ + dbus-misc.c \ + dbus-object-tree.c \ + dbus-object-tree.h \ + dbus-pending-call.c \ + dbus-pending-call-internal.h \ + dbus-resources.c \ + dbus-resources.h \ + dbus-server.c \ + dbus-server-debug-pipe.c \ + dbus-server-debug-pipe.h \ + dbus-server-protected.h \ + dbus-server-socket.c \ + dbus-server-socket.h \ + dbus-server-unix.c \ + dbus-server-unix.h \ + dbus-sha.c \ + dbus-sha.h \ + dbus-signature.c \ + dbus-timeout.c \ + dbus-timeout.h \ + dbus-threads-internal.h \ + dbus-threads.c \ + dbus-transport.c \ + dbus-transport.h \ + dbus-transport-protected.h \ + dbus-transport-socket.c \ + dbus-transport-socket.h \ + dbus-transport-unix.c \ + dbus-transport-unix.h \ + dbus-uuidgen.c \ + dbus-uuidgen.h \ + dbus-watch.c \ + dbus-watch.h + +## dbus-md5.c \ +## dbus-md5.h \ + +### source code that goes in the installed client library +### AND is generic utility functionality used by the +### daemon or test programs (all symbols in here should +### be underscore-prefixed) +DBUS_SHARED_SOURCES= \ + dbus-dataslot.c \ + dbus-dataslot.h \ + dbus-hash.c \ + dbus-hash.h \ + dbus-internals.c \ + dbus-internals.h \ + dbus-list.c \ + dbus-list.h \ + dbus-marshal-basic.c \ + dbus-marshal-basic.h \ + dbus-memory.c \ + dbus-mempool.c \ + dbus-mempool.h \ + dbus-string.c \ + dbus-string.h \ + dbus-string-private.h \ + dbus-sysdeps.c \ + dbus-sysdeps.h \ + dbus-sysdeps-pthread.c \ + dbus-sysdeps-unix.c \ + dbus-sysdeps-unix.h \ + dbus-userdb.c \ + dbus-userdb.h + +### source code that is generic utility functionality used +### by the bus daemon or test apps, but is NOT included +### in the D-Bus client library (all symbols in here +### should be underscore-prefixed but don't really need +### to be unless they move to DBUS_SHARED_SOURCES later) +DBUS_UTIL_SOURCES= \ + dbus-auth-util.c \ + dbus-credentials-util.c \ + dbus-mainloop.c \ + dbus-mainloop.h \ + dbus-marshal-byteswap-util.c \ + dbus-marshal-recursive-util.c \ + dbus-marshal-validate-util.c \ + dbus-message-factory.c \ + dbus-message-factory.h \ + dbus-message-util.c \ + dbus-shell.c \ + dbus-shell.h \ + dbus-spawn.c \ + dbus-spawn.h \ + dbus-string-util.c \ + dbus-sysdeps-util.c \ + dbus-sysdeps-util-unix.c \ + dbus-test.c \ + dbus-test.h \ + dbus-userdb-util.c + +libdbus_1_la_SOURCES= \ + $(DBUS_LIB_SOURCES) \ + $(DBUS_SHARED_SOURCES) + +libdbus_convenience_la_SOURCES= \ + $(DBUS_LIB_SOURCES) \ + $(DBUS_SHARED_SOURCES) \ + $(DBUS_UTIL_SOURCES) + + +BUILT_SOURCES=$(dbusarchinclude_HEADERS) +EXTRA_DIST=dbus-arch-deps.h.in + +## this library is the same as libdbus, but exports all the symbols +## and is only used for static linking within the dbus package. +noinst_LTLIBRARIES=libdbus-convenience.la + +libdbus_1_la_LIBADD= $(DBUS_CLIENT_LIBS) +## don't export symbols that start with "_" (we use this +## convention for internal symbols) +libdbus_1_la_LDFLAGS= -export-symbols-regex "^[^_].*" -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) -no-undefined @R_DYNAMIC_LDFLAG@ @PIC_LDFLAGS@ + +libdbus_convenience_la_LIBADD=$(DBUS_CLIENT_LIBS) +libdbus_convenience_la_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +## note that TESTS has special meaning (stuff to use in make check) +## so if adding tests not to be run in make check, don't add them to +## TESTS +if DBUS_BUILD_TESTS +TESTS_ENVIRONMENT=DBUS_TEST_DATA=$(top_builddir)/test/data DBUS_TEST_HOMEDIR=$(top_builddir)/dbus +TESTS=dbus-test +else +TESTS= +endif + +## we use noinst_PROGRAMS not check_PROGRAMS so that we build +## even when not doing "make check" +noinst_PROGRAMS=$(TESTS) + +dbus_test_SOURCES= \ + dbus-test-main.c + +dbus_test_LDADD=libdbus-convenience.la $(DBUS_TEST_LIBS) +dbus_test_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +## mop up the gcov files +clean-local: + /bin/rm *.bb *.bbg *.da *.gcov .libs/*.da .libs/*.bbg || true diff --git a/dbus/Makefile.in b/dbus/Makefile.in new file mode 100644 index 00000000..2ab720bb --- /dev/null +++ b/dbus/Makefile.in @@ -0,0 +1,1060 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@DBUS_BUILD_TESTS_TRUE@TESTS = dbus-test$(EXEEXT) +noinst_PROGRAMS = $(am__EXEEXT_1) +subdir = dbus +DIST_COMMON = $(dbusarchinclude_HEADERS) $(dbusinclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/dbus-arch-deps.h.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = dbus-arch-deps.h +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" \ + "$(DESTDIR)$(dbusarchincludedir)" \ + "$(DESTDIR)$(dbusincludedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) +am__DEPENDENCIES_1 = +libdbus_1_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_1 = dbus-address.lo dbus-auth.lo dbus-auth-script.lo \ + dbus-bus.lo dbus-connection.lo dbus-credentials.lo \ + dbus-errors.lo dbus-keyring.lo dbus-marshal-header.lo \ + dbus-marshal-byteswap.lo dbus-marshal-recursive.lo \ + dbus-marshal-validate.lo dbus-message.lo dbus-misc.lo \ + dbus-object-tree.lo dbus-pending-call.lo dbus-resources.lo \ + dbus-server.lo dbus-server-debug-pipe.lo dbus-server-socket.lo \ + dbus-server-unix.lo dbus-sha.lo dbus-signature.lo \ + dbus-timeout.lo dbus-threads.lo dbus-transport.lo \ + dbus-transport-socket.lo dbus-transport-unix.lo \ + dbus-uuidgen.lo dbus-watch.lo +am__objects_2 = dbus-dataslot.lo dbus-hash.lo dbus-internals.lo \ + dbus-list.lo dbus-marshal-basic.lo dbus-memory.lo \ + dbus-mempool.lo dbus-string.lo dbus-sysdeps.lo \ + dbus-sysdeps-pthread.lo dbus-sysdeps-unix.lo dbus-userdb.lo +am_libdbus_1_la_OBJECTS = $(am__objects_1) $(am__objects_2) +libdbus_1_la_OBJECTS = $(am_libdbus_1_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libdbus_1_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libdbus_1_la_LDFLAGS) $(LDFLAGS) -o $@ +libdbus_convenience_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_3 = dbus-auth-util.lo dbus-credentials-util.lo \ + dbus-mainloop.lo dbus-marshal-byteswap-util.lo \ + dbus-marshal-recursive-util.lo dbus-marshal-validate-util.lo \ + dbus-message-factory.lo dbus-message-util.lo dbus-shell.lo \ + dbus-spawn.lo dbus-string-util.lo dbus-sysdeps-util.lo \ + dbus-sysdeps-util-unix.lo dbus-test.lo dbus-userdb-util.lo +am_libdbus_convenience_la_OBJECTS = $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) +libdbus_convenience_la_OBJECTS = $(am_libdbus_convenience_la_OBJECTS) +libdbus_convenience_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libdbus_convenience_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@DBUS_BUILD_TESTS_TRUE@am__EXEEXT_1 = dbus-test$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) +am_dbus_test_OBJECTS = dbus-test-main.$(OBJEXT) +dbus_test_OBJECTS = $(am_dbus_test_OBJECTS) +dbus_test_DEPENDENCIES = libdbus-convenience.la $(am__DEPENDENCIES_1) +dbus_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(dbus_test_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libdbus_1_la_SOURCES) $(libdbus_convenience_la_SOURCES) \ + $(dbus_test_SOURCES) +DIST_SOURCES = $(libdbus_1_la_SOURCES) \ + $(libdbus_convenience_la_SOURCES) $(dbus_test_SOURCES) +HEADERS = $(dbusarchinclude_HEADERS) $(dbusinclude_HEADERS) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DBUS_BINDIR = @DBUS_BINDIR@ +DBUS_BUS_CFLAGS = @DBUS_BUS_CFLAGS@ +DBUS_BUS_LIBS = @DBUS_BUS_LIBS@ +DBUS_CLIENT_CFLAGS = @DBUS_CLIENT_CFLAGS@ +DBUS_CLIENT_LIBS = @DBUS_CLIENT_LIBS@ +DBUS_CONSOLE_AUTH_DIR = @DBUS_CONSOLE_AUTH_DIR@ +DBUS_CONSOLE_OWNER_FILE = @DBUS_CONSOLE_OWNER_FILE@ +DBUS_DAEMONDIR = @DBUS_DAEMONDIR@ +DBUS_DATADIR = @DBUS_DATADIR@ +DBUS_HAVE_INT64 = @DBUS_HAVE_INT64@ +DBUS_INT16_TYPE = @DBUS_INT16_TYPE@ +DBUS_INT32_TYPE = @DBUS_INT32_TYPE@ +DBUS_INT64_CONSTANT = @DBUS_INT64_CONSTANT@ +DBUS_INT64_TYPE = @DBUS_INT64_TYPE@ +DBUS_LAUNCHER_CFLAGS = @DBUS_LAUNCHER_CFLAGS@ +DBUS_LAUNCHER_LIBS = @DBUS_LAUNCHER_LIBS@ +DBUS_LIBEXECDIR = @DBUS_LIBEXECDIR@ +DBUS_MAJOR_VERSION = @DBUS_MAJOR_VERSION@ +DBUS_MICRO_VERSION = @DBUS_MICRO_VERSION@ +DBUS_MINOR_VERSION = @DBUS_MINOR_VERSION@ +DBUS_PATH_OR_ABSTRACT = @DBUS_PATH_OR_ABSTRACT@ +DBUS_SESSION_SOCKET_DIR = @DBUS_SESSION_SOCKET_DIR@ +DBUS_SYSTEM_BUS_DEFAULT_ADDRESS = @DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ +DBUS_SYSTEM_PID_FILE = @DBUS_SYSTEM_PID_FILE@ +DBUS_SYSTEM_SOCKET = @DBUS_SYSTEM_SOCKET@ +DBUS_TEST_CFLAGS = @DBUS_TEST_CFLAGS@ +DBUS_TEST_LIBS = @DBUS_TEST_LIBS@ +DBUS_UINT64_CONSTANT = @DBUS_UINT64_CONSTANT@ +DBUS_USER = @DBUS_USER@ +DBUS_VERSION = @DBUS_VERSION@ +DBUS_X_CFLAGS = @DBUS_X_CFLAGS@ +DBUS_X_LIBS = @DBUS_X_LIBS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPANDED_BINDIR = @EXPANDED_BINDIR@ +EXPANDED_DATADIR = @EXPANDED_DATADIR@ +EXPANDED_LIBDIR = @EXPANDED_LIBDIR@ +EXPANDED_LIBEXECDIR = @EXPANDED_LIBEXECDIR@ +EXPANDED_LOCALSTATEDIR = @EXPANDED_LOCALSTATEDIR@ +EXPANDED_SYSCONFDIR = @EXPANDED_SYSCONFDIR@ +FGREP = @FGREP@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML_CFLAGS = @LIBXML_CFLAGS@ +LIBXML_LIBS = @LIBXML_LIBS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_AGE = @LT_AGE@ +LT_CURRENT = @LT_CURRENT@ +LT_REVISION = @LT_REVISION@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIC_CFLAGS = @PIC_CFLAGS@ +PIC_LDFLAGS = @PIC_LDFLAGS@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +R_DYNAMIC_LDFLAG = @R_DYNAMIC_LDFLAG@ +SECTION_FLAGS = @SECTION_FLAGS@ +SECTION_LDFLAGS = @SECTION_LDFLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TEST_BUS_BINARY = @TEST_BUS_BINARY@ +TEST_EXIT_BINARY = @TEST_EXIT_BINARY@ +TEST_INVALID_SERVICE_DIR = @TEST_INVALID_SERVICE_DIR@ +TEST_INVALID_SERVICE_SYSTEM_DIR = @TEST_INVALID_SERVICE_SYSTEM_DIR@ +TEST_LAUNCH_HELPER_BINARY = @TEST_LAUNCH_HELPER_BINARY@ +TEST_PRIVSERVER_BINARY = @TEST_PRIVSERVER_BINARY@ +TEST_SEGFAULT_BINARY = @TEST_SEGFAULT_BINARY@ +TEST_SERVICE_BINARY = @TEST_SERVICE_BINARY@ +TEST_SHELL_SERVICE_BINARY = @TEST_SHELL_SERVICE_BINARY@ +TEST_SLEEP_FOREVER_BINARY = @TEST_SLEEP_FOREVER_BINARY@ +TEST_SOCKET_DIR = @TEST_SOCKET_DIR@ +TEST_VALID_SERVICE_DIR = @TEST_VALID_SERVICE_DIR@ +TEST_VALID_SERVICE_SYSTEM_DIR = @TEST_VALID_SERVICE_SYSTEM_DIR@ +VERSION = @VERSION@ +XMKMF = @XMKMF@ +XMLTO = @XMLTO@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +configdir = $(sysconfdir)/dbus-1 +INCLUDES = -I$(top_builddir) -I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) @PIC_CFLAGS@ -DDBUS_COMPILATION \ + -DDBUS_MACHINE_UUID_FILE=\""$(localstatedir)/lib/dbus/machine-id"\" \ + -DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\" \ + -DDBUS_SESSION_CONFIG_FILE=\""$(configdir)/session.conf"\" + +dbusincludedir = $(includedir)/dbus-1.0/dbus +dbusarchincludedir = $(libdir)/dbus-1.0/include/dbus +lib_LTLIBRARIES = libdbus-1.la +dbusinclude_HEADERS = \ + dbus.h \ + dbus-address.h \ + dbus-bus.h \ + dbus-connection.h \ + dbus-errors.h \ + dbus-macros.h \ + dbus-memory.h \ + dbus-message.h \ + dbus-misc.h \ + dbus-pending-call.h \ + dbus-protocol.h \ + dbus-server.h \ + dbus-shared.h \ + dbus-signature.h \ + dbus-threads.h \ + dbus-types.h + +dbusarchinclude_HEADERS = \ + dbus-arch-deps.h + + +### source code that goes in the installed client library +### and is specific to library functionality +DBUS_LIB_SOURCES = \ + dbus-address.c \ + dbus-auth.c \ + dbus-auth.h \ + dbus-auth-script.c \ + dbus-auth-script.h \ + dbus-bus.c \ + dbus-connection.c \ + dbus-connection-internal.h \ + dbus-credentials.c \ + dbus-credentials.h \ + dbus-errors.c \ + dbus-keyring.c \ + dbus-keyring.h \ + dbus-marshal-header.c \ + dbus-marshal-header.h \ + dbus-marshal-byteswap.c \ + dbus-marshal-byteswap.h \ + dbus-marshal-recursive.c \ + dbus-marshal-recursive.h \ + dbus-marshal-validate.c \ + dbus-marshal-validate.h \ + dbus-message.c \ + dbus-message-internal.h \ + dbus-message-private.h \ + dbus-misc.c \ + dbus-object-tree.c \ + dbus-object-tree.h \ + dbus-pending-call.c \ + dbus-pending-call-internal.h \ + dbus-resources.c \ + dbus-resources.h \ + dbus-server.c \ + dbus-server-debug-pipe.c \ + dbus-server-debug-pipe.h \ + dbus-server-protected.h \ + dbus-server-socket.c \ + dbus-server-socket.h \ + dbus-server-unix.c \ + dbus-server-unix.h \ + dbus-sha.c \ + dbus-sha.h \ + dbus-signature.c \ + dbus-timeout.c \ + dbus-timeout.h \ + dbus-threads-internal.h \ + dbus-threads.c \ + dbus-transport.c \ + dbus-transport.h \ + dbus-transport-protected.h \ + dbus-transport-socket.c \ + dbus-transport-socket.h \ + dbus-transport-unix.c \ + dbus-transport-unix.h \ + dbus-uuidgen.c \ + dbus-uuidgen.h \ + dbus-watch.c \ + dbus-watch.h + + +### source code that goes in the installed client library +### AND is generic utility functionality used by the +### daemon or test programs (all symbols in here should +### be underscore-prefixed) +DBUS_SHARED_SOURCES = \ + dbus-dataslot.c \ + dbus-dataslot.h \ + dbus-hash.c \ + dbus-hash.h \ + dbus-internals.c \ + dbus-internals.h \ + dbus-list.c \ + dbus-list.h \ + dbus-marshal-basic.c \ + dbus-marshal-basic.h \ + dbus-memory.c \ + dbus-mempool.c \ + dbus-mempool.h \ + dbus-string.c \ + dbus-string.h \ + dbus-string-private.h \ + dbus-sysdeps.c \ + dbus-sysdeps.h \ + dbus-sysdeps-pthread.c \ + dbus-sysdeps-unix.c \ + dbus-sysdeps-unix.h \ + dbus-userdb.c \ + dbus-userdb.h + + +### source code that is generic utility functionality used +### by the bus daemon or test apps, but is NOT included +### in the D-Bus client library (all symbols in here +### should be underscore-prefixed but don't really need +### to be unless they move to DBUS_SHARED_SOURCES later) +DBUS_UTIL_SOURCES = \ + dbus-auth-util.c \ + dbus-credentials-util.c \ + dbus-mainloop.c \ + dbus-mainloop.h \ + dbus-marshal-byteswap-util.c \ + dbus-marshal-recursive-util.c \ + dbus-marshal-validate-util.c \ + dbus-message-factory.c \ + dbus-message-factory.h \ + dbus-message-util.c \ + dbus-shell.c \ + dbus-shell.h \ + dbus-spawn.c \ + dbus-spawn.h \ + dbus-string-util.c \ + dbus-sysdeps-util.c \ + dbus-sysdeps-util-unix.c \ + dbus-test.c \ + dbus-test.h \ + dbus-userdb-util.c + +libdbus_1_la_SOURCES = \ + $(DBUS_LIB_SOURCES) \ + $(DBUS_SHARED_SOURCES) + +libdbus_convenience_la_SOURCES = \ + $(DBUS_LIB_SOURCES) \ + $(DBUS_SHARED_SOURCES) \ + $(DBUS_UTIL_SOURCES) + +BUILT_SOURCES = $(dbusarchinclude_HEADERS) +EXTRA_DIST = dbus-arch-deps.h.in +noinst_LTLIBRARIES = libdbus-convenience.la +libdbus_1_la_LIBADD = $(DBUS_CLIENT_LIBS) +libdbus_1_la_LDFLAGS = -export-symbols-regex "^[^_].*" -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) -no-undefined @R_DYNAMIC_LDFLAG@ @PIC_LDFLAGS@ +libdbus_convenience_la_LIBADD = $(DBUS_CLIENT_LIBS) +libdbus_convenience_la_LDFLAGS = @R_DYNAMIC_LDFLAG@ +@DBUS_BUILD_TESTS_TRUE@TESTS_ENVIRONMENT = DBUS_TEST_DATA=$(top_builddir)/test/data DBUS_TEST_HOMEDIR=$(top_builddir)/dbus +dbus_test_SOURCES = \ + dbus-test-main.c + +dbus_test_LDADD = libdbus-convenience.la $(DBUS_TEST_LIBS) +dbus_test_LDFLAGS = @R_DYNAMIC_LDFLAG@ +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu dbus/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu dbus/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +dbus-arch-deps.h: $(top_builddir)/config.status $(srcdir)/dbus-arch-deps.h.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libdbus-1.la: $(libdbus_1_la_OBJECTS) $(libdbus_1_la_DEPENDENCIES) + $(AM_V_CCLD)$(libdbus_1_la_LINK) -rpath $(libdir) $(libdbus_1_la_OBJECTS) $(libdbus_1_la_LIBADD) $(LIBS) +libdbus-convenience.la: $(libdbus_convenience_la_OBJECTS) $(libdbus_convenience_la_DEPENDENCIES) + $(AM_V_CCLD)$(libdbus_convenience_la_LINK) $(libdbus_convenience_la_OBJECTS) $(libdbus_convenience_la_LIBADD) $(LIBS) + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +dbus-test$(EXEEXT): $(dbus_test_OBJECTS) $(dbus_test_DEPENDENCIES) + @rm -f dbus-test$(EXEEXT) + $(AM_V_CCLD)$(dbus_test_LINK) $(dbus_test_OBJECTS) $(dbus_test_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-address.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-auth-script.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-auth-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-auth.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-bus.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-connection.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-credentials-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-credentials.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-dataslot.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-errors.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-hash.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-internals.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-keyring.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-list.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-mainloop.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-marshal-basic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-marshal-byteswap-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-marshal-byteswap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-marshal-header.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-marshal-recursive-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-marshal-recursive.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-marshal-validate-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-marshal-validate.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-memory.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-mempool.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-message-factory.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-message-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-message.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-misc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-object-tree.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-pending-call.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-resources.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-server-debug-pipe.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-server-socket.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-server-unix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-server.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-sha.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-shell.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-signature.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-spawn.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-string-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-string.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-sysdeps-pthread.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-sysdeps-unix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-sysdeps-util-unix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-sysdeps-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-sysdeps.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-test-main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-test.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-threads.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-timeout.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-transport-socket.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-transport-unix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-transport.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-userdb-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-userdb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-uuidgen.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-watch.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dbusarchincludeHEADERS: $(dbusarchinclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(dbusarchincludedir)" || $(MKDIR_P) "$(DESTDIR)$(dbusarchincludedir)" + @list='$(dbusarchinclude_HEADERS)'; test -n "$(dbusarchincludedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(dbusarchincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(dbusarchincludedir)" || exit $$?; \ + done + +uninstall-dbusarchincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(dbusarchinclude_HEADERS)'; test -n "$(dbusarchincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(dbusarchincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(dbusarchincludedir)" && rm -f $$files +install-dbusincludeHEADERS: $(dbusinclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(dbusincludedir)" || $(MKDIR_P) "$(DESTDIR)$(dbusincludedir)" + @list='$(dbusinclude_HEADERS)'; test -n "$(dbusincludedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(dbusincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(dbusincludedir)" || exit $$?; \ + done + +uninstall-dbusincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(dbusinclude_HEADERS)'; test -n "$(dbusincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(dbusincludedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(dbusincludedir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(dbusarchincludedir)" "$(DESTDIR)$(dbusincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ + clean-noinstLTLIBRARIES clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dbusarchincludeHEADERS \ + install-dbusincludeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dbusarchincludeHEADERS \ + uninstall-dbusincludeHEADERS uninstall-libLTLIBRARIES + +.MAKE: all check check-am install install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ + clean-noinstLTLIBRARIES clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-dbusarchincludeHEADERS install-dbusincludeHEADERS \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-dbusarchincludeHEADERS \ + uninstall-dbusincludeHEADERS uninstall-libLTLIBRARIES + + +clean-local: + /bin/rm *.bb *.bbg *.da *.gcov .libs/*.da .libs/*.bbg || true + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/dbus/dbus-address.c b/dbus/dbus-address.c new file mode 100644 index 00000000..90484dc1 --- /dev/null +++ b/dbus/dbus-address.c @@ -0,0 +1,826 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-address.c Server address parser. + * + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2004,2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include "dbus-address.h" +#include "dbus-internals.h" +#include "dbus-list.h" +#include "dbus-string.h" +#include "dbus-protocol.h" + +/** + * @defgroup DBusAddressInternals Address parsing + * @ingroup DBusInternals + * @brief Implementation of parsing addresses of D-Bus servers. + * + * @{ + */ + +/** + * Internals of DBusAddressEntry + */ +struct DBusAddressEntry +{ + DBusString method; /**< The address type (unix, tcp, etc.) */ + + DBusList *keys; /**< List of keys */ + DBusList *values; /**< List of values */ +}; + + +/** + * + * Sets #DBUS_ERROR_BAD_ADDRESS. + * If address_problem_type and address_problem_field are not #NULL, + * sets an error message about how the field is no good. Otherwise, sets + * address_problem_other as the error message. + * + * @param error the error to set + * @param address_problem_type the address type of the bad address or #NULL + * @param address_problem_field the missing field of the bad address or #NULL + * @param address_problem_other any other error message or #NULL + */ +void +_dbus_set_bad_address (DBusError *error, + const char *address_problem_type, + const char *address_problem_field, + const char *address_problem_other) +{ + if (address_problem_type != NULL) + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Server address of type %s was missing argument %s", + address_problem_type, address_problem_field); + else + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Could not parse server address: %s", + address_problem_other); +} + +/** + * #TRUE if the byte need not be escaped when found in a dbus address. + * All other bytes are required to be escaped in a valid address. + */ +#define _DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE(b) \ + (((b) >= 'a' && (b) <= 'z') || \ + ((b) >= 'A' && (b) <= 'Z') || \ + ((b) >= '0' && (b) <= '9') || \ + (b) == '-' || \ + (b) == '_' || \ + (b) == '/' || \ + (b) == '\\' || \ + (b) == '*' || \ + (b) == '.') + +/** + * Appends an escaped version of one string to another string, + * using the D-Bus address escaping mechanism + * + * @param escaped the string to append to + * @param unescaped the string to escape + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_address_append_escaped (DBusString *escaped, + const DBusString *unescaped) +{ + const char *p; + const char *end; + dbus_bool_t ret; + int orig_len; + + ret = FALSE; + + orig_len = _dbus_string_get_length (escaped); + p = _dbus_string_get_const_data (unescaped); + end = p + _dbus_string_get_length (unescaped); + while (p != end) + { + if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p)) + { + if (!_dbus_string_append_byte (escaped, *p)) + goto out; + } + else + { + if (!_dbus_string_append_byte (escaped, '%')) + goto out; + if (!_dbus_string_append_byte_as_hex (escaped, *p)) + goto out; + } + + ++p; + } + + ret = TRUE; + + out: + if (!ret) + _dbus_string_set_length (escaped, orig_len); + return ret; +} + +/** @} */ /* End of internals */ + +static void +dbus_address_entry_free (DBusAddressEntry *entry) +{ + DBusList *link; + + _dbus_string_free (&entry->method); + + link = _dbus_list_get_first_link (&entry->keys); + while (link != NULL) + { + _dbus_string_free (link->data); + dbus_free (link->data); + + link = _dbus_list_get_next_link (&entry->keys, link); + } + _dbus_list_clear (&entry->keys); + + link = _dbus_list_get_first_link (&entry->values); + while (link != NULL) + { + _dbus_string_free (link->data); + dbus_free (link->data); + + link = _dbus_list_get_next_link (&entry->values, link); + } + _dbus_list_clear (&entry->values); + + dbus_free (entry); +} + +/** + * @defgroup DBusAddress Address parsing + * @ingroup DBus + * @brief Parsing addresses of D-Bus servers. + * + * @{ + */ + +/** + * Frees a #NULL-terminated array of address entries. + * + * @param entries the array. + */ +void +dbus_address_entries_free (DBusAddressEntry **entries) +{ + int i; + + for (i = 0; entries[i] != NULL; i++) + dbus_address_entry_free (entries[i]); + dbus_free (entries); +} + +static DBusAddressEntry * +create_entry (void) +{ + DBusAddressEntry *entry; + + entry = dbus_new0 (DBusAddressEntry, 1); + + if (entry == NULL) + return NULL; + + if (!_dbus_string_init (&entry->method)) + { + dbus_free (entry); + return NULL; + } + + return entry; +} + +/** + * Returns the method string of an address entry. For example, given + * the address entry "tcp:host=example.com" it would return the string + * "tcp" + * + * @param entry the entry. + * @returns a string describing the method. This string + * must not be freed. + */ +const char * +dbus_address_entry_get_method (DBusAddressEntry *entry) +{ + return _dbus_string_get_const_data (&entry->method); +} + +/** + * Returns a value from a key of an entry. For example, + * given the address "tcp:host=example.com,port=8073" if you asked + * for the key "host" you would get the value "example.com" + * + * The returned value is already unescaped. + * + * @param entry the entry. + * @param key the key. + * @returns the key value. This string must not be freed. + */ +const char * +dbus_address_entry_get_value (DBusAddressEntry *entry, + const char *key) +{ + DBusList *values, *keys; + + keys = _dbus_list_get_first_link (&entry->keys); + values = _dbus_list_get_first_link (&entry->values); + + while (keys != NULL) + { + _dbus_assert (values != NULL); + + if (_dbus_string_equal_c_str (keys->data, key)) + return _dbus_string_get_const_data (values->data); + + keys = _dbus_list_get_next_link (&entry->keys, keys); + values = _dbus_list_get_next_link (&entry->values, values); + } + + return NULL; +} + +static dbus_bool_t +append_unescaped_value (DBusString *unescaped, + const DBusString *escaped, + int escaped_start, + int escaped_len, + DBusError *error) +{ + const char *p; + const char *end; + dbus_bool_t ret; + + ret = FALSE; + + p = _dbus_string_get_const_data (escaped) + escaped_start; + end = p + escaped_len; + while (p != end) + { + if (_DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE (*p)) + { + if (!_dbus_string_append_byte (unescaped, *p)) + goto out; + } + else if (*p == '%') + { + /* Efficiency is king */ + char buf[3]; + DBusString hex; + int hex_end; + + ++p; + + if ((p + 2) > end) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "In D-Bus address, percent character was not followed by two hex digits"); + goto out; + } + + buf[0] = *p; + ++p; + buf[1] = *p; + buf[2] = '\0'; + + _dbus_string_init_const (&hex, buf); + + if (!_dbus_string_hex_decode (&hex, 0, &hex_end, + unescaped, + _dbus_string_get_length (unescaped))) + goto out; + + if (hex_end != 2) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "In D-Bus address, percent character was followed by characters other than hex digits"); + goto out; + } + } + else + { + /* Error, should have been escaped */ + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "In D-Bus address, character '%c' should have been escaped\n", + *p); + goto out; + } + + ++p; + } + + ret = TRUE; + + out: + if (!ret && error && !dbus_error_is_set (error)) + _DBUS_SET_OOM (error); + + _dbus_assert (ret || error == NULL || dbus_error_is_set (error)); + + return ret; +} + +/** + * Parses an address string of the form: + * + * method:key=value,key=value;method:key=value + * + * See the D-Bus specification for complete docs on the format. + * + * When connecting to an address, the first address entries + * in the semicolon-separated list should be tried first. + * + * @param address the address. + * @param entry return location to an array of entries. + * @param array_len return location for array length. + * @param error address where an error can be returned. + * @returns #TRUE on success, #FALSE otherwise. + */ +dbus_bool_t +dbus_parse_address (const char *address, + DBusAddressEntry ***entry, + int *array_len, + DBusError *error) +{ + DBusString str; + int pos, end_pos, len, i; + DBusList *entries, *link; + DBusAddressEntry **entry_array; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_string_init_const (&str, address); + + entries = NULL; + pos = 0; + len = _dbus_string_get_length (&str); + + if (len == 0) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Empty address '%s'", address); + goto error; + } + + while (pos < len) + { + DBusAddressEntry *entry; + + int found_pos; + + entry = create_entry (); + if (!entry) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + + goto error; + } + + /* Append the entry */ + if (!_dbus_list_append (&entries, entry)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + dbus_address_entry_free (entry); + goto error; + } + + /* Look for a semi-colon */ + if (!_dbus_string_find (&str, pos, ";", &end_pos)) + end_pos = len; + + /* Look for the colon : */ + if (!_dbus_string_find_to (&str, pos, end_pos, ":", &found_pos)) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Address does not contain a colon"); + goto error; + } + + if (!_dbus_string_copy_len (&str, pos, found_pos - pos, &entry->method, 0)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto error; + } + + pos = found_pos + 1; + + while (pos < end_pos) + { + int comma_pos, equals_pos; + + if (!_dbus_string_find_to (&str, pos, end_pos, ",", &comma_pos)) + comma_pos = end_pos; + + if (!_dbus_string_find_to (&str, pos, comma_pos, "=", &equals_pos) || + equals_pos == pos || equals_pos + 1 == comma_pos) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "'=' character not found or has no value following it"); + goto error; + } + else + { + DBusString *key; + DBusString *value; + + key = dbus_new0 (DBusString, 1); + + if (!key) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto error; + } + + value = dbus_new0 (DBusString, 1); + if (!value) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + dbus_free (key); + goto error; + } + + if (!_dbus_string_init (key)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + dbus_free (key); + dbus_free (value); + + goto error; + } + + if (!_dbus_string_init (value)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (key); + + dbus_free (key); + dbus_free (value); + goto error; + } + + if (!_dbus_string_copy_len (&str, pos, equals_pos - pos, key, 0)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (key); + _dbus_string_free (value); + + dbus_free (key); + dbus_free (value); + goto error; + } + + if (!append_unescaped_value (value, &str, equals_pos + 1, + comma_pos - equals_pos - 1, error)) + { + _dbus_assert (error == NULL || dbus_error_is_set (error)); + _dbus_string_free (key); + _dbus_string_free (value); + + dbus_free (key); + dbus_free (value); + goto error; + } + + if (!_dbus_list_append (&entry->keys, key)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (key); + _dbus_string_free (value); + + dbus_free (key); + dbus_free (value); + goto error; + } + + if (!_dbus_list_append (&entry->values, value)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (value); + + dbus_free (value); + goto error; + } + } + + pos = comma_pos + 1; + } + + pos = end_pos + 1; + } + + *array_len = _dbus_list_get_length (&entries); + + entry_array = dbus_new (DBusAddressEntry *, *array_len + 1); + + if (!entry_array) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + + goto error; + } + + entry_array [*array_len] = NULL; + + link = _dbus_list_get_first_link (&entries); + i = 0; + while (link != NULL) + { + entry_array[i] = link->data; + i++; + link = _dbus_list_get_next_link (&entries, link); + } + + _dbus_list_clear (&entries); + *entry = entry_array; + + return TRUE; + + error: + + link = _dbus_list_get_first_link (&entries); + while (link != NULL) + { + dbus_address_entry_free (link->data); + link = _dbus_list_get_next_link (&entries, link); + } + + _dbus_list_clear (&entries); + + return FALSE; + +} + +/** + * Escapes the given string as a value in a key=value pair + * for a D-Bus address. + * + * @param value the unescaped value + * @returns newly-allocated escaped value or #NULL if no memory + */ +char* +dbus_address_escape_value (const char *value) +{ + DBusString escaped; + DBusString unescaped; + char *ret; + + ret = NULL; + + _dbus_string_init_const (&unescaped, value); + + if (!_dbus_string_init (&escaped)) + return NULL; + + if (!_dbus_address_append_escaped (&escaped, &unescaped)) + goto out; + + if (!_dbus_string_steal_data (&escaped, &ret)) + goto out; + + out: + _dbus_string_free (&escaped); + return ret; +} + +/** + * Unescapes the given string as a value in a key=value pair + * for a D-Bus address. Note that dbus_address_entry_get_value() + * returns an already-unescaped value. + * + * @param value the escaped value + * @param error error to set if the unescaping fails + * @returns newly-allocated unescaped value or #NULL if no memory + */ +char* +dbus_address_unescape_value (const char *value, + DBusError *error) +{ + DBusString unescaped; + DBusString escaped; + char *ret; + + ret = NULL; + + _dbus_string_init_const (&escaped, value); + + if (!_dbus_string_init (&unescaped)) + return NULL; + + if (!append_unescaped_value (&unescaped, &escaped, + 0, _dbus_string_get_length (&escaped), + error)) + goto out; + + if (!_dbus_string_steal_data (&unescaped, &ret)) + goto out; + + out: + if (ret == NULL && error && !dbus_error_is_set (error)) + _DBUS_SET_OOM (error); + + _dbus_assert (ret != NULL || error == NULL || dbus_error_is_set (error)); + + _dbus_string_free (&unescaped); + return ret; +} + +/** @} */ /* End of public API */ + +#ifdef DBUS_BUILD_TESTS + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#include "dbus-test.h" +#include + +typedef struct +{ + const char *escaped; + const char *unescaped; +} EscapeTest; + +static const EscapeTest escape_tests[] = { + { "abcde", "abcde" }, + { "", "" }, + { "%20%20", " " }, + { "%24", "$" }, + { "%25", "%" }, + { "abc%24", "abc$" }, + { "%24abc", "$abc" }, + { "abc%24abc", "abc$abc" }, + { "/", "/" }, + { "-", "-" }, + { "_", "_" }, + { "A", "A" }, + { "I", "I" }, + { "Z", "Z" }, + { "a", "a" }, + { "i", "i" }, + { "z", "z" } +}; + +static const char* invalid_escaped_values[] = { + "%a", + "%q", + "%az", + "%%", + "%$$", + "abc%a", + "%axyz", + "%", + "$", + " ", +}; + +dbus_bool_t +_dbus_address_test (void) +{ + DBusAddressEntry **entries; + int len; + DBusError error = DBUS_ERROR_INIT; + int i; + + i = 0; + while (i < _DBUS_N_ELEMENTS (escape_tests)) + { + const EscapeTest *test = &escape_tests[i]; + char *escaped; + char *unescaped; + + escaped = dbus_address_escape_value (test->unescaped); + if (escaped == NULL) + _dbus_assert_not_reached ("oom"); + + if (strcmp (escaped, test->escaped) != 0) + { + _dbus_warn ("Escaped '%s' as '%s' should have been '%s'\n", + test->unescaped, escaped, test->escaped); + exit (1); + } + dbus_free (escaped); + + unescaped = dbus_address_unescape_value (test->escaped, &error); + if (unescaped == NULL) + { + _dbus_warn ("Failed to unescape '%s': %s\n", + test->escaped, error.message); + dbus_error_free (&error); + exit (1); + } + + if (strcmp (unescaped, test->unescaped) != 0) + { + _dbus_warn ("Unescaped '%s' as '%s' should have been '%s'\n", + test->escaped, unescaped, test->unescaped); + exit (1); + } + dbus_free (unescaped); + + ++i; + } + + i = 0; + while (i < _DBUS_N_ELEMENTS (invalid_escaped_values)) + { + char *unescaped; + + unescaped = dbus_address_unescape_value (invalid_escaped_values[i], + &error); + if (unescaped != NULL) + { + _dbus_warn ("Should not have successfully unescaped '%s' to '%s'\n", + invalid_escaped_values[i], unescaped); + dbus_free (unescaped); + exit (1); + } + + _dbus_assert (dbus_error_is_set (&error)); + dbus_error_free (&error); + + ++i; + } + + if (!dbus_parse_address ("unix:path=/tmp/foo;debug:name=test,sliff=sloff;", + &entries, &len, &error)) + _dbus_assert_not_reached ("could not parse address"); + _dbus_assert (len == 2); + _dbus_assert (strcmp (dbus_address_entry_get_value (entries[0], "path"), "/tmp/foo") == 0); + _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "name"), "test") == 0); + _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "sliff"), "sloff") == 0); + + dbus_address_entries_free (entries); + + /* Different possible errors */ + if (dbus_parse_address ("", &entries, &len, &error)) + _dbus_assert_not_reached ("Parsed incorrect address."); + else + dbus_error_free (&error); + + if (dbus_parse_address ("foo", &entries, &len, &error)) + _dbus_assert_not_reached ("Parsed incorrect address."); + else + dbus_error_free (&error); + + if (dbus_parse_address ("foo:bar", &entries, &len, &error)) + _dbus_assert_not_reached ("Parsed incorrect address."); + else + dbus_error_free (&error); + + if (dbus_parse_address ("foo:bar,baz", &entries, &len, &error)) + _dbus_assert_not_reached ("Parsed incorrect address."); + else + dbus_error_free (&error); + + if (dbus_parse_address ("foo:bar=foo,baz", &entries, &len, &error)) + _dbus_assert_not_reached ("Parsed incorrect address."); + else + dbus_error_free (&error); + + if (dbus_parse_address ("foo:bar=foo;baz", &entries, &len, &error)) + _dbus_assert_not_reached ("Parsed incorrect address."); + else + dbus_error_free (&error); + + if (dbus_parse_address ("foo:=foo", &entries, &len, &error)) + _dbus_assert_not_reached ("Parsed incorrect address."); + else + dbus_error_free (&error); + + if (dbus_parse_address ("foo:foo=", &entries, &len, &error)) + _dbus_assert_not_reached ("Parsed incorrect address."); + else + dbus_error_free (&error); + + if (dbus_parse_address ("foo:foo,bar=baz", &entries, &len, &error)) + _dbus_assert_not_reached ("Parsed incorrect address."); + else + dbus_error_free (&error); + + return TRUE; +} + +#endif /* !DOXYGEN_SHOULD_SKIP_THIS */ + +#endif diff --git a/dbus/dbus-address.h b/dbus/dbus-address.h new file mode 100644 index 00000000..07d5339c --- /dev/null +++ b/dbus/dbus-address.h @@ -0,0 +1,61 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-address.h Server address parser. + * + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_ADDRESS_H +#define DBUS_ADDRESS_H + +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusAddress + * @{ + */ + +/** Opaque type representing one of the semicolon-separated items in an address */ +typedef struct DBusAddressEntry DBusAddressEntry; + +dbus_bool_t dbus_parse_address (const char *address, + DBusAddressEntry ***entry, + int *array_len, + DBusError *error); +const char *dbus_address_entry_get_value (DBusAddressEntry *entry, + const char *key); +const char *dbus_address_entry_get_method (DBusAddressEntry *entry); +void dbus_address_entries_free (DBusAddressEntry **entries); + +char* dbus_address_escape_value (const char *value); +char* dbus_address_unescape_value (const char *value, + DBusError *error); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_ADDRESS_H */ + diff --git a/dbus/dbus-arch-deps.h b/dbus/dbus-arch-deps.h new file mode 100644 index 00000000..ee5e96ff --- /dev/null +++ b/dbus/dbus-arch-deps.h @@ -0,0 +1,67 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-arch-deps.h Header with architecture/compiler specific information, installed to libdir + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_ARCH_DEPS_H +#define DBUS_ARCH_DEPS_H + +#include + +DBUS_BEGIN_DECLS + +#if 1 +#define DBUS_HAVE_INT64 1 +_DBUS_GNUC_EXTENSION typedef long dbus_int64_t; +_DBUS_GNUC_EXTENSION typedef unsigned long dbus_uint64_t; + +#define DBUS_INT64_CONSTANT(val) (_DBUS_GNUC_EXTENSION (val##L)) +#define DBUS_UINT64_CONSTANT(val) (_DBUS_GNUC_EXTENSION (val##UL)) + +#else +#undef DBUS_HAVE_INT64 +#undef DBUS_INT64_CONSTANT +#undef DBUS_UINT64_CONSTANT +#endif + +typedef int dbus_int32_t; +typedef unsigned int dbus_uint32_t; + +typedef short dbus_int16_t; +typedef unsigned short dbus_uint16_t; + +/* This is not really arch-dependent, but it's not worth + * creating an additional generated header just for this + */ +#define DBUS_MAJOR_VERSION 1 +#define DBUS_MINOR_VERSION 2 +#define DBUS_MICRO_VERSION 24 + +#define DBUS_VERSION_STRING "1.2.24" + +#define DBUS_VERSION ((1 << 16) | (2 << 8) | (24)) + +DBUS_END_DECLS + +#endif /* DBUS_ARCH_DEPS_H */ diff --git a/dbus/dbus-arch-deps.h.in b/dbus/dbus-arch-deps.h.in new file mode 100644 index 00000000..45952cfb --- /dev/null +++ b/dbus/dbus-arch-deps.h.in @@ -0,0 +1,67 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-arch-deps.h Header with architecture/compiler specific information, installed to libdir + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_ARCH_DEPS_H +#define DBUS_ARCH_DEPS_H + +#include + +DBUS_BEGIN_DECLS + +#if @DBUS_HAVE_INT64@ +#define DBUS_HAVE_INT64 1 +_DBUS_GNUC_EXTENSION typedef @DBUS_INT64_TYPE@ dbus_int64_t; +_DBUS_GNUC_EXTENSION typedef unsigned @DBUS_INT64_TYPE@ dbus_uint64_t; + +#define DBUS_INT64_CONSTANT(val) (_DBUS_GNUC_EXTENSION @DBUS_INT64_CONSTANT@) +#define DBUS_UINT64_CONSTANT(val) (_DBUS_GNUC_EXTENSION @DBUS_UINT64_CONSTANT@) + +#else +#undef DBUS_HAVE_INT64 +#undef DBUS_INT64_CONSTANT +#undef DBUS_UINT64_CONSTANT +#endif + +typedef @DBUS_INT32_TYPE@ dbus_int32_t; +typedef unsigned @DBUS_INT32_TYPE@ dbus_uint32_t; + +typedef @DBUS_INT16_TYPE@ dbus_int16_t; +typedef unsigned @DBUS_INT16_TYPE@ dbus_uint16_t; + +/* This is not really arch-dependent, but it's not worth + * creating an additional generated header just for this + */ +#define DBUS_MAJOR_VERSION @DBUS_MAJOR_VERSION@ +#define DBUS_MINOR_VERSION @DBUS_MINOR_VERSION@ +#define DBUS_MICRO_VERSION @DBUS_MICRO_VERSION@ + +#define DBUS_VERSION_STRING "@DBUS_VERSION@" + +#define DBUS_VERSION ((@DBUS_MAJOR_VERSION@ << 16) | (@DBUS_MINOR_VERSION@ << 8) | (@DBUS_MICRO_VERSION@)) + +DBUS_END_DECLS + +#endif /* DBUS_ARCH_DEPS_H */ diff --git a/dbus/dbus-auth-script.c b/dbus/dbus-auth-script.c new file mode 100644 index 00000000..6285e3ba --- /dev/null +++ b/dbus/dbus-auth-script.c @@ -0,0 +1,803 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-auth-script.c Test DBusAuth using a special script file (internal to D-Bus implementation) + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include + +#ifdef DBUS_BUILD_TESTS + +#include "dbus-auth-script.h" +#include "dbus-auth.h" +#include "dbus-string.h" +#include "dbus-hash.h" +#include "dbus-credentials.h" +#include "dbus-internals.h" + +/** + * @defgroup DBusAuthScript code for running unit test scripts for DBusAuth + * @ingroup DBusInternals + * @brief DBusAuth unit test scripting + * + * The code in here is used for unit testing, it loads + * up a script that tests DBusAuth. + * + * @{ + */ + +/* this is slightly different from the other append_quoted_string + * in dbus-message-builder.c + */ +static dbus_bool_t +append_quoted_string (DBusString *dest, + const DBusString *quoted) +{ + dbus_bool_t in_quotes = FALSE; + dbus_bool_t in_backslash = FALSE; + int i; + + i = 0; + while (i < _dbus_string_get_length (quoted)) + { + unsigned char b; + + b = _dbus_string_get_byte (quoted, i); + + if (in_backslash) + { + unsigned char a; + + if (b == 'r') + a = '\r'; + else if (b == 'n') + a = '\n'; + else if (b == '\\') + a = '\\'; + else + { + _dbus_warn ("bad backslashed byte %c\n", b); + return FALSE; + } + + if (!_dbus_string_append_byte (dest, a)) + return FALSE; + + in_backslash = FALSE; + } + else if (b == '\\') + { + in_backslash = TRUE; + } + else if (in_quotes) + { + if (b == '\'') + in_quotes = FALSE; + else + { + if (!_dbus_string_append_byte (dest, b)) + return FALSE; + } + } + else + { + if (b == '\'') + in_quotes = TRUE; + else if (b == ' ' || b == '\n' || b == '\t') + break; /* end on whitespace if not quoted */ + else + { + if (!_dbus_string_append_byte (dest, b)) + return FALSE; + } + } + + ++i; + } + + return TRUE; +} + +static dbus_bool_t +same_first_word (const DBusString *a, + const DBusString *b) +{ + int first_a_blank, first_b_blank; + + _dbus_string_find_blank (a, 0, &first_a_blank); + _dbus_string_find_blank (b, 0, &first_b_blank); + + if (first_a_blank != first_b_blank) + return FALSE; + + return _dbus_string_equal_len (a, b, first_a_blank); +} + +static DBusAuthState +auth_state_from_string (const DBusString *str) +{ + if (_dbus_string_starts_with_c_str (str, "WAITING_FOR_INPUT")) + return DBUS_AUTH_STATE_WAITING_FOR_INPUT; + else if (_dbus_string_starts_with_c_str (str, "WAITING_FOR_MEMORY")) + return DBUS_AUTH_STATE_WAITING_FOR_MEMORY; + else if (_dbus_string_starts_with_c_str (str, "HAVE_BYTES_TO_SEND")) + return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND; + else if (_dbus_string_starts_with_c_str (str, "NEED_DISCONNECT")) + return DBUS_AUTH_STATE_NEED_DISCONNECT; + else if (_dbus_string_starts_with_c_str (str, "AUTHENTICATED")) + return DBUS_AUTH_STATE_AUTHENTICATED; + else + return -1; +} + +static const char* +auth_state_to_string (DBusAuthState state) +{ + switch (state) + { + case DBUS_AUTH_STATE_WAITING_FOR_INPUT: + return "WAITING_FOR_INPUT"; + case DBUS_AUTH_STATE_WAITING_FOR_MEMORY: + return "WAITING_FOR_MEMORY"; + case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND: + return "HAVE_BYTES_TO_SEND"; + case DBUS_AUTH_STATE_NEED_DISCONNECT: + return "NEED_DISCONNECT"; + case DBUS_AUTH_STATE_AUTHENTICATED: + return "AUTHENTICATED"; + } + + return "unknown"; +} + +static char ** +split_string (DBusString *str) +{ + int i, j, k, count, end; + char **array; + + end = _dbus_string_get_length (str); + + i = 0; + _dbus_string_skip_blank (str, i, &i); + for (count = 0; i < end; count++) + { + _dbus_string_find_blank (str, i, &i); + _dbus_string_skip_blank (str, i, &i); + } + + array = dbus_new0 (char *, count + 1); + if (array == NULL) + return NULL; + + i = 0; + _dbus_string_skip_blank (str, i, &i); + for (k = 0; k < count; k++) + { + _dbus_string_find_blank (str, i, &j); + + array[k] = dbus_malloc (j - i + 1); + if (array[k] == NULL) + { + dbus_free_string_array (array); + return NULL; + } + memcpy (array[k], + _dbus_string_get_const_data_len (str, i, j - i), j - i); + array[k][j - i] = '\0'; + + _dbus_string_skip_blank (str, j, &i); + } + array[k] = NULL; + + return array; +} + +static void +auth_set_unix_credentials(DBusAuth *auth, + dbus_uid_t uid, + dbus_pid_t pid) +{ + DBusCredentials *credentials; + + credentials = _dbus_credentials_new (); + if (credentials == NULL) + _dbus_assert_not_reached ("no memory"); + + if (uid != DBUS_UID_UNSET) + _dbus_credentials_add_unix_uid (credentials, uid); + if (pid != DBUS_PID_UNSET) + _dbus_credentials_add_unix_pid (credentials, pid); + + _dbus_auth_set_credentials (auth, credentials); + + _dbus_credentials_unref (credentials); +} + +/** + * Runs an "auth script" which is a script for testing the + * authentication protocol. Scripts send and receive data, and then + * include assertions about the state of both ends of the connection + * after processing the data. A script succeeds if these assertions + * hold. + * + * @param filename the file containing the script to run + * @returns #TRUE if the script succeeds, #FALSE otherwise + */ +dbus_bool_t +_dbus_auth_script_run (const DBusString *filename) +{ + DBusString file; + DBusError error = DBUS_ERROR_INIT; + DBusString line; + dbus_bool_t retval; + int line_no; + DBusAuth *auth; + DBusString from_auth; + DBusAuthState state; + DBusString context; + DBusString guid; + + retval = FALSE; + auth = NULL; + + _dbus_string_init_const (&guid, "5fa01f4202cd837709a3274ca0df9d00"); + _dbus_string_init_const (&context, "org_freedesktop_test"); + + if (!_dbus_string_init (&file)) + return FALSE; + + if (!_dbus_string_init (&line)) + { + _dbus_string_free (&file); + return FALSE; + } + + if (!_dbus_string_init (&from_auth)) + { + _dbus_string_free (&file); + _dbus_string_free (&line); + return FALSE; + } + + if (!_dbus_file_get_contents (&file, filename, &error)) { + _dbus_warn ("Getting contents of %s failed: %s\n", + _dbus_string_get_const_data (filename), error.message); + dbus_error_free (&error); + goto out; + } + + state = DBUS_AUTH_STATE_NEED_DISCONNECT; + line_no = 0; + + next_iteration: + while (_dbus_string_pop_line (&file, &line)) + { + line_no += 1; + + /* _dbus_warn ("%s\n", _dbus_string_get_const_data (&line)); */ + + _dbus_string_delete_leading_blanks (&line); + + if (auth != NULL) + { + while ((state = _dbus_auth_do_work (auth)) == + DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND) + { + const DBusString *tmp; + if (_dbus_auth_get_bytes_to_send (auth, &tmp)) + { + int count = _dbus_string_get_length (tmp); + + if (_dbus_string_copy (tmp, 0, &from_auth, + _dbus_string_get_length (&from_auth))) + _dbus_auth_bytes_sent (auth, count); + } + } + } + + if (_dbus_string_get_length (&line) == 0) + { + /* empty line */ + goto next_iteration; + } + else if (_dbus_string_starts_with_c_str (&line, + "#")) + { + /* Ignore this comment */ + goto next_iteration; + } +#ifdef DBUS_WIN + else if (_dbus_string_starts_with_c_str (&line, + "WIN_ONLY")) + { + /* Ignore this line */ + goto next_iteration; + } + else if (_dbus_string_starts_with_c_str (&line, + "UNIX_ONLY")) + { + /* skip this file */ + _dbus_warn ("skipping unix only auth script\n"); + retval = TRUE; + goto out; + } +#endif +#ifdef DBUS_UNIX + else if (_dbus_string_starts_with_c_str (&line, + "UNIX_ONLY")) + { + /* Ignore this line */ + goto next_iteration; + } + else if (_dbus_string_starts_with_c_str (&line, + "WIN_ONLY")) + { + /* skip this file */ + _dbus_warn ("skipping windows only auth script\n"); + retval = TRUE; + goto out; + } +#endif + else if (_dbus_string_starts_with_c_str (&line, + "CLIENT")) + { + DBusCredentials *creds; + + if (auth != NULL) + { + _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n"); + goto out; + } + + auth = _dbus_auth_client_new (); + if (auth == NULL) + { + _dbus_warn ("no memory to create DBusAuth\n"); + goto out; + } + + /* test ref/unref */ + _dbus_auth_ref (auth); + _dbus_auth_unref (auth); + + creds = _dbus_credentials_new_from_current_process (); + if (creds == NULL) + { + _dbus_warn ("no memory for credentials\n"); + _dbus_auth_unref (auth); + auth = NULL; + goto out; + } + + if (!_dbus_auth_set_credentials (auth, creds)) + { + _dbus_warn ("no memory for setting credentials\n"); + _dbus_auth_unref (auth); + auth = NULL; + _dbus_credentials_unref (creds); + goto out; + } + + _dbus_credentials_unref (creds); + } + else if (_dbus_string_starts_with_c_str (&line, + "SERVER")) + { + DBusCredentials *creds; + + if (auth != NULL) + { + _dbus_warn ("already created a DBusAuth (CLIENT or SERVER given twice)\n"); + goto out; + } + + auth = _dbus_auth_server_new (&guid); + if (auth == NULL) + { + _dbus_warn ("no memory to create DBusAuth\n"); + goto out; + } + + /* test ref/unref */ + _dbus_auth_ref (auth); + _dbus_auth_unref (auth); + + creds = _dbus_credentials_new_from_current_process (); + if (creds == NULL) + { + _dbus_warn ("no memory for credentials\n"); + _dbus_auth_unref (auth); + auth = NULL; + goto out; + } + + if (!_dbus_auth_set_credentials (auth, creds)) + { + _dbus_warn ("no memory for setting credentials\n"); + _dbus_auth_unref (auth); + auth = NULL; + _dbus_credentials_unref (creds); + goto out; + } + + _dbus_credentials_unref (creds); + + _dbus_auth_set_context (auth, &context); + } + else if (auth == NULL) + { + _dbus_warn ("must specify CLIENT or SERVER\n"); + goto out; + + } + else if (_dbus_string_starts_with_c_str (&line, + "NO_CREDENTIALS")) + { + auth_set_unix_credentials (auth, DBUS_UID_UNSET, DBUS_PID_UNSET); + } + else if (_dbus_string_starts_with_c_str (&line, + "ROOT_CREDENTIALS")) + { + auth_set_unix_credentials (auth, 0, DBUS_PID_UNSET); + } + else if (_dbus_string_starts_with_c_str (&line, + "SILLY_CREDENTIALS")) + { + auth_set_unix_credentials (auth, 4312, DBUS_PID_UNSET); + } + else if (_dbus_string_starts_with_c_str (&line, + "ALLOWED_MECHS")) + { + char **mechs; + + _dbus_string_delete_first_word (&line); + mechs = split_string (&line); + _dbus_auth_set_mechanisms (auth, (const char **) mechs); + dbus_free_string_array (mechs); + } + else if (_dbus_string_starts_with_c_str (&line, + "SEND")) + { + DBusString to_send; + + _dbus_string_delete_first_word (&line); + + if (!_dbus_string_init (&to_send)) + { + _dbus_warn ("no memory to allocate string\n"); + goto out; + } + + if (!append_quoted_string (&to_send, &line)) + { + _dbus_warn ("failed to append quoted string line %d\n", + line_no); + _dbus_string_free (&to_send); + goto out; + } + + _dbus_verbose ("Sending '%s'\n", _dbus_string_get_const_data (&to_send)); + + if (!_dbus_string_append (&to_send, "\r\n")) + { + _dbus_warn ("failed to append \r\n from line %d\n", + line_no); + _dbus_string_free (&to_send); + goto out; + } + + /* Replace USERID_HEX with our username in hex */ + { + int where; + + if (_dbus_string_find (&to_send, 0, + "USERID_HEX", &where)) + { + DBusString username; + + if (!_dbus_string_init (&username)) + { + _dbus_warn ("no memory for userid\n"); + _dbus_string_free (&to_send); + goto out; + } + + if (!_dbus_append_user_from_current_process (&username)) + { + _dbus_warn ("no memory for userid\n"); + _dbus_string_free (&username); + _dbus_string_free (&to_send); + goto out; + } + + _dbus_string_delete (&to_send, where, strlen ("USERID_HEX")); + + if (!_dbus_string_hex_encode (&username, 0, + &to_send, where)) + { + _dbus_warn ("no memory to subst USERID_HEX\n"); + _dbus_string_free (&username); + _dbus_string_free (&to_send); + goto out; + } + + _dbus_string_free (&username); + } + else if (_dbus_string_find (&to_send, 0, + "USERNAME_HEX", &where)) + { + DBusString username; + + if (!_dbus_string_init (&username)) + { + _dbus_warn ("no memory for username\n"); + _dbus_string_free (&to_send); + goto out; + } + + if (!_dbus_append_user_from_current_process (&username)) + { + _dbus_warn ("no memory for username\n"); + _dbus_string_free (&username); + _dbus_string_free (&to_send); + goto out; + } + + _dbus_string_delete (&to_send, where, strlen ("USERNAME_HEX")); + + if (!_dbus_string_hex_encode (&username, 0, + &to_send, where)) + { + _dbus_warn ("no memory to subst USERNAME_HEX\n"); + _dbus_string_free (&username); + _dbus_string_free (&to_send); + goto out; + } + + _dbus_string_free (&username); + } + } + + { + DBusString *buffer; + + _dbus_auth_get_buffer (auth, &buffer); + if (!_dbus_string_copy (&to_send, 0, + buffer, _dbus_string_get_length (buffer))) + { + _dbus_warn ("not enough memory to call bytes_received, or can't add bytes to auth object already in end state\n"); + _dbus_string_free (&to_send); + _dbus_auth_return_buffer (auth, buffer, 0); + goto out; + } + + _dbus_auth_return_buffer (auth, buffer, _dbus_string_get_length (&to_send)); + } + + _dbus_string_free (&to_send); + } + else if (_dbus_string_starts_with_c_str (&line, + "EXPECT_STATE")) + { + DBusAuthState expected; + + _dbus_string_delete_first_word (&line); + + expected = auth_state_from_string (&line); + if (expected < 0) + { + _dbus_warn ("bad auth state given to EXPECT_STATE\n"); + goto parse_failed; + } + + if (expected != state) + { + _dbus_warn ("expected auth state %s but got %s on line %d\n", + auth_state_to_string (expected), + auth_state_to_string (state), + line_no); + goto out; + } + } + else if (_dbus_string_starts_with_c_str (&line, + "EXPECT_COMMAND")) + { + DBusString received; + + _dbus_string_delete_first_word (&line); + + if (!_dbus_string_init (&received)) + { + _dbus_warn ("no mem to allocate string received\n"); + goto out; + } + + if (!_dbus_string_pop_line (&from_auth, &received)) + { + _dbus_warn ("no line popped from the DBusAuth being tested, expected command %s on line %d\n", + _dbus_string_get_const_data (&line), line_no); + _dbus_string_free (&received); + goto out; + } + + if (!same_first_word (&received, &line)) + { + _dbus_warn ("line %d expected command '%s' and got '%s'\n", + line_no, + _dbus_string_get_const_data (&line), + _dbus_string_get_const_data (&received)); + _dbus_string_free (&received); + goto out; + } + + _dbus_string_free (&received); + } + else if (_dbus_string_starts_with_c_str (&line, + "EXPECT_UNUSED")) + { + DBusString expected; + const DBusString *unused; + + _dbus_string_delete_first_word (&line); + + if (!_dbus_string_init (&expected)) + { + _dbus_warn ("no mem to allocate string expected\n"); + goto out; + } + + if (!append_quoted_string (&expected, &line)) + { + _dbus_warn ("failed to append quoted string line %d\n", + line_no); + _dbus_string_free (&expected); + goto out; + } + + _dbus_auth_get_unused_bytes (auth, &unused); + + if (_dbus_string_equal (&expected, unused)) + { + _dbus_auth_delete_unused_bytes (auth); + _dbus_string_free (&expected); + } + else + { + _dbus_warn ("Expected unused bytes '%s' and have '%s'\n", + _dbus_string_get_const_data (&expected), + _dbus_string_get_const_data (unused)); + _dbus_string_free (&expected); + goto out; + } + } + else if (_dbus_string_starts_with_c_str (&line, + "EXPECT_HAVE_NO_CREDENTIALS")) + { + DBusCredentials *authorized_identity; + + authorized_identity = _dbus_auth_get_identity (auth); + if (!_dbus_credentials_are_anonymous (authorized_identity)) + { + _dbus_warn ("Expected anonymous login or failed login, but some credentials were authorized\n"); + goto out; + } + } + else if (_dbus_string_starts_with_c_str (&line, + "EXPECT_HAVE_SOME_CREDENTIALS")) + { + DBusCredentials *authorized_identity; + + authorized_identity = _dbus_auth_get_identity (auth); + if (_dbus_credentials_are_anonymous (authorized_identity)) + { + _dbus_warn ("Expected to have some credentials, but we don't\n"); + goto out; + } + } + else if (_dbus_string_starts_with_c_str (&line, + "EXPECT")) + { + DBusString expected; + + _dbus_string_delete_first_word (&line); + + if (!_dbus_string_init (&expected)) + { + _dbus_warn ("no mem to allocate string expected\n"); + goto out; + } + + if (!append_quoted_string (&expected, &line)) + { + _dbus_warn ("failed to append quoted string line %d\n", + line_no); + _dbus_string_free (&expected); + goto out; + } + + if (_dbus_string_equal_len (&expected, &from_auth, + _dbus_string_get_length (&expected))) + { + _dbus_string_delete (&from_auth, 0, + _dbus_string_get_length (&expected)); + _dbus_string_free (&expected); + } + else + { + _dbus_warn ("Expected exact string '%s' and have '%s'\n", + _dbus_string_get_const_data (&expected), + _dbus_string_get_const_data (&from_auth)); + _dbus_string_free (&expected); + goto out; + } + } + else + goto parse_failed; + + goto next_iteration; /* skip parse_failed */ + + parse_failed: + { + _dbus_warn ("couldn't process line %d \"%s\"\n", + line_no, _dbus_string_get_const_data (&line)); + goto out; + } + } + + if (auth == NULL) + { + _dbus_warn ("Auth script is bogus, did not even have CLIENT or SERVER\n"); + goto out; + } + else if (state == DBUS_AUTH_STATE_AUTHENTICATED) + { + const DBusString *unused; + + _dbus_auth_get_unused_bytes (auth, &unused); + + if (_dbus_string_get_length (unused) > 0) + { + _dbus_warn ("did not expect unused bytes (scripts must specify explicitly if they are expected)\n"); + goto out; + } + } + + if (_dbus_string_get_length (&from_auth) > 0) + { + _dbus_warn ("script did not have EXPECT_ statements for all the data received from the DBusAuth\n"); + _dbus_warn ("Leftover data: %s\n", _dbus_string_get_const_data (&from_auth)); + goto out; + } + + retval = TRUE; + + out: + if (auth) + _dbus_auth_unref (auth); + + _dbus_string_free (&file); + _dbus_string_free (&line); + _dbus_string_free (&from_auth); + + return retval; +} + +/** @} */ +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-auth-script.h b/dbus/dbus-auth-script.h new file mode 100644 index 00000000..30cd5642 --- /dev/null +++ b/dbus/dbus-auth-script.h @@ -0,0 +1,39 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-auth-script.h Test DBusAuth using a special script file (internal to D-Bus implementation) + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_AUTH_SCRIPT_H +#define DBUS_AUTH_SCRIPT_H + +#include + +#include +#include +#include + +DBUS_BEGIN_DECLS + +dbus_bool_t _dbus_auth_script_run (const DBusString *filename); + +DBUS_END_DECLS + +#endif /* DBUS_AUTH_SCRIPT_H */ diff --git a/dbus/dbus-auth-util.c b/dbus/dbus-auth-util.c new file mode 100644 index 00000000..09ecdd47 --- /dev/null +++ b/dbus/dbus-auth-util.c @@ -0,0 +1,168 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-auth-util.c Would be in dbus-auth.c, but only used for tests/bus + * + * Copyright (C) 2002, 2003, 2004 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-internals.h" +#include "dbus-test.h" +#include "dbus-auth.h" + +/** + * @addtogroup DBusAuth + * @{ + */ + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include "dbus-auth-script.h" +#include + +static dbus_bool_t +process_test_subdir (const DBusString *test_base_dir, + const char *subdir) +{ + DBusString test_directory; + DBusString filename; + DBusDirIter *dir; + dbus_bool_t retval; + DBusError error = DBUS_ERROR_INIT; + + retval = FALSE; + dir = NULL; + + if (!_dbus_string_init (&test_directory)) + _dbus_assert_not_reached ("didn't allocate test_directory\n"); + + _dbus_string_init_const (&filename, subdir); + + if (!_dbus_string_copy (test_base_dir, 0, + &test_directory, 0)) + _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); + + if (!_dbus_concat_dir_and_file (&test_directory, &filename)) + _dbus_assert_not_reached ("couldn't allocate full path"); + + _dbus_string_free (&filename); + if (!_dbus_string_init (&filename)) + _dbus_assert_not_reached ("didn't allocate filename string\n"); + + dir = _dbus_directory_open (&test_directory, &error); + if (dir == NULL) + { + _dbus_warn ("Could not open %s: %s\n", + _dbus_string_get_const_data (&test_directory), + error.message); + dbus_error_free (&error); + goto failed; + } + + printf ("Testing %s:\n", subdir); + + next: + while (_dbus_directory_get_next_file (dir, &filename, &error)) + { + DBusString full_path; + + if (!_dbus_string_init (&full_path)) + _dbus_assert_not_reached ("couldn't init string"); + + if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) + _dbus_assert_not_reached ("couldn't copy dir to full_path"); + + if (!_dbus_concat_dir_and_file (&full_path, &filename)) + _dbus_assert_not_reached ("couldn't concat file to dir"); + + if (!_dbus_string_ends_with_c_str (&filename, ".auth-script")) + { + _dbus_verbose ("Skipping non-.auth-script file %s\n", + _dbus_string_get_const_data (&filename)); + _dbus_string_free (&full_path); + goto next; + } + + printf (" %s\n", _dbus_string_get_const_data (&filename)); + + if (!_dbus_auth_script_run (&full_path)) + { + _dbus_string_free (&full_path); + goto failed; + } + else + _dbus_string_free (&full_path); + } + + if (dbus_error_is_set (&error)) + { + _dbus_warn ("Could not get next file in %s: %s\n", + _dbus_string_get_const_data (&test_directory), error.message); + dbus_error_free (&error); + goto failed; + } + + retval = TRUE; + + failed: + + if (dir) + _dbus_directory_close (dir); + _dbus_string_free (&test_directory); + _dbus_string_free (&filename); + + return retval; +} + +static dbus_bool_t +process_test_dirs (const char *test_data_dir) +{ + DBusString test_directory; + dbus_bool_t retval; + + retval = FALSE; + + _dbus_string_init_const (&test_directory, test_data_dir); + + if (!process_test_subdir (&test_directory, "auth")) + goto failed; + + retval = TRUE; + + failed: + + _dbus_string_free (&test_directory); + + return retval; +} + +dbus_bool_t +_dbus_auth_test (const char *test_data_dir) +{ + + if (test_data_dir == NULL) + return TRUE; + + if (!process_test_dirs (test_data_dir)) + return FALSE; + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c new file mode 100644 index 00000000..b81c7f25 --- /dev/null +++ b/dbus/dbus-auth.c @@ -0,0 +1,2690 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-auth.c Authentication + * + * Copyright (C) 2002, 2003, 2004 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-auth.h" +#include "dbus-string.h" +#include "dbus-list.h" +#include "dbus-internals.h" +#include "dbus-keyring.h" +#include "dbus-sha.h" +#include "dbus-protocol.h" +#include "dbus-credentials.h" + +/** + * @defgroup DBusAuth Authentication + * @ingroup DBusInternals + * @brief DBusAuth object + * + * DBusAuth manages the authentication negotiation when a connection + * is first established, and also manage any encryption used over a + * connection. + * + * @todo some SASL profiles require sending the empty string as a + * challenge/response, but we don't currently allow that in our + * protocol. + * + * @todo right now sometimes both ends will block waiting for input + * from the other end, e.g. if there's an error during + * DBUS_COOKIE_SHA1. + * + * @todo the cookie keyring needs to be cached globally not just + * per-auth (which raises threadsafety issues too) + * + * @todo grep FIXME in dbus-auth.c + */ + +/** + * @defgroup DBusAuthInternals Authentication implementation details + * @ingroup DBusInternals + * @brief DBusAuth implementation details + * + * Private details of authentication code. + * + * @{ + */ + +/** + * This function appends an initial client response to the given string + */ +typedef dbus_bool_t (* DBusInitialResponseFunction) (DBusAuth *auth, + DBusString *response); + +/** + * This function processes a block of data received from the peer. + * i.e. handles a DATA command. + */ +typedef dbus_bool_t (* DBusAuthDataFunction) (DBusAuth *auth, + const DBusString *data); + +/** + * This function encodes a block of data from the peer. + */ +typedef dbus_bool_t (* DBusAuthEncodeFunction) (DBusAuth *auth, + const DBusString *data, + DBusString *encoded); + +/** + * This function decodes a block of data from the peer. + */ +typedef dbus_bool_t (* DBusAuthDecodeFunction) (DBusAuth *auth, + const DBusString *data, + DBusString *decoded); + +/** + * This function is called when the mechanism is abandoned. + */ +typedef void (* DBusAuthShutdownFunction) (DBusAuth *auth); + +/** + * Virtual table representing a particular auth mechanism. + */ +typedef struct +{ + const char *mechanism; /**< Name of the mechanism */ + DBusAuthDataFunction server_data_func; /**< Function on server side for DATA */ + DBusAuthEncodeFunction server_encode_func; /**< Function on server side to encode */ + DBusAuthDecodeFunction server_decode_func; /**< Function on server side to decode */ + DBusAuthShutdownFunction server_shutdown_func; /**< Function on server side to shut down */ + DBusInitialResponseFunction client_initial_response_func; /**< Function on client side to handle initial response */ + DBusAuthDataFunction client_data_func; /**< Function on client side for DATA */ + DBusAuthEncodeFunction client_encode_func; /**< Function on client side for encode */ + DBusAuthDecodeFunction client_decode_func; /**< Function on client side for decode */ + DBusAuthShutdownFunction client_shutdown_func; /**< Function on client side for shutdown */ +} DBusAuthMechanismHandler; + +/** + * Enumeration for the known authentication commands. + */ +typedef enum { + DBUS_AUTH_COMMAND_AUTH, + DBUS_AUTH_COMMAND_CANCEL, + DBUS_AUTH_COMMAND_DATA, + DBUS_AUTH_COMMAND_BEGIN, + DBUS_AUTH_COMMAND_REJECTED, + DBUS_AUTH_COMMAND_OK, + DBUS_AUTH_COMMAND_ERROR, + DBUS_AUTH_COMMAND_UNKNOWN +} DBusAuthCommand; + +/** + * Auth state function, determines the reaction to incoming events for + * a particular state. Returns whether we had enough memory to + * complete the operation. + */ +typedef dbus_bool_t (* DBusAuthStateFunction) (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args); + +/** + * Information about a auth state. + */ +typedef struct +{ + const char *name; /**< Name of the state */ + DBusAuthStateFunction handler; /**< State function for this state */ +} DBusAuthStateData; + +/** + * Internal members of DBusAuth. + */ +struct DBusAuth +{ + int refcount; /**< reference count */ + const char *side; /**< Client or server */ + + DBusString incoming; /**< Incoming data buffer */ + DBusString outgoing; /**< Outgoing data buffer */ + + const DBusAuthStateData *state; /**< Current protocol state */ + + const DBusAuthMechanismHandler *mech; /**< Current auth mechanism */ + + DBusString identity; /**< Current identity we're authorizing + * as. + */ + + DBusCredentials *credentials; /**< Credentials read from socket + */ + + DBusCredentials *authorized_identity; /**< Credentials that are authorized */ + + DBusCredentials *desired_identity; /**< Identity client has requested */ + + DBusString context; /**< Cookie scope */ + DBusKeyring *keyring; /**< Keyring for cookie mechanism. */ + int cookie_id; /**< ID of cookie to use */ + DBusString challenge; /**< Challenge sent to client */ + + char **allowed_mechs; /**< Mechanisms we're allowed to use, + * or #NULL if we can use any + */ + + unsigned int needed_memory : 1; /**< We needed memory to continue since last + * successful getting something done + */ + unsigned int already_got_mechanisms : 1; /**< Client already got mech list */ + unsigned int already_asked_for_initial_response : 1; /**< Already sent a blank challenge to get an initial response */ + unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */ +}; + +/** + * "Subclass" of DBusAuth for client side + */ +typedef struct +{ + DBusAuth base; /**< Parent class */ + + DBusList *mechs_to_try; /**< Mechanisms we got from the server that we're going to try using */ + + DBusString guid_from_server; /**< GUID received from server */ + +} DBusAuthClient; + +/** + * "Subclass" of DBusAuth for server side. + */ +typedef struct +{ + DBusAuth base; /**< Parent class */ + + int failures; /**< Number of times client has been rejected */ + int max_failures; /**< Number of times we reject before disconnect */ + + DBusString guid; /**< Our globally unique ID in hex encoding */ + +} DBusAuthServer; + +static void goto_state (DBusAuth *auth, + const DBusAuthStateData *new_state); +static dbus_bool_t send_auth (DBusAuth *auth, + const DBusAuthMechanismHandler *mech); +static dbus_bool_t send_data (DBusAuth *auth, + DBusString *data); +static dbus_bool_t send_rejected (DBusAuth *auth); +static dbus_bool_t send_error (DBusAuth *auth, + const char *message); +static dbus_bool_t send_ok (DBusAuth *auth); +static dbus_bool_t send_begin (DBusAuth *auth, + const DBusString *args_from_ok); +static dbus_bool_t send_cancel (DBusAuth *auth); + +/** + * Client states + */ + +static dbus_bool_t handle_server_state_waiting_for_auth (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args); +static dbus_bool_t handle_server_state_waiting_for_data (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args); +static dbus_bool_t handle_server_state_waiting_for_begin (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args); + +static const DBusAuthStateData server_state_waiting_for_auth = { + "WaitingForAuth", handle_server_state_waiting_for_auth +}; +static const DBusAuthStateData server_state_waiting_for_data = { + "WaitingForData", handle_server_state_waiting_for_data +}; +static const DBusAuthStateData server_state_waiting_for_begin = { + "WaitingForBegin", handle_server_state_waiting_for_begin +}; + +/** + * Client states + */ + +static dbus_bool_t handle_client_state_waiting_for_data (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args); +static dbus_bool_t handle_client_state_waiting_for_ok (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args); +static dbus_bool_t handle_client_state_waiting_for_reject (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args); + +static const DBusAuthStateData client_state_need_send_auth = { + "NeedSendAuth", NULL +}; +static const DBusAuthStateData client_state_waiting_for_data = { + "WaitingForData", handle_client_state_waiting_for_data +}; +static const DBusAuthStateData client_state_waiting_for_ok = { + "WaitingForOK", handle_client_state_waiting_for_ok +}; +static const DBusAuthStateData client_state_waiting_for_reject = { + "WaitingForReject", handle_client_state_waiting_for_reject +}; + +/** + * Common terminal states. Terminal states have handler == NULL. + */ + +static const DBusAuthStateData common_state_authenticated = { + "Authenticated", NULL +}; + +static const DBusAuthStateData common_state_need_disconnect = { + "NeedDisconnect", NULL +}; + +static const char auth_side_client[] = "client"; +static const char auth_side_server[] = "server"; +/** + * @param auth the auth conversation + * @returns #TRUE if the conversation is the server side + */ +#define DBUS_AUTH_IS_SERVER(auth) ((auth)->side == auth_side_server) +/** + * @param auth the auth conversation + * @returns #TRUE if the conversation is the client side + */ +#define DBUS_AUTH_IS_CLIENT(auth) ((auth)->side == auth_side_client) +/** + * @param auth the auth conversation + * @returns auth cast to DBusAuthClient + */ +#define DBUS_AUTH_CLIENT(auth) ((DBusAuthClient*)(auth)) +/** + * @param auth the auth conversation + * @returns auth cast to DBusAuthServer + */ +#define DBUS_AUTH_SERVER(auth) ((DBusAuthServer*)(auth)) + +/** + * The name of the auth ("client" or "server") + * @param auth the auth conversation + * @returns a string + */ +#define DBUS_AUTH_NAME(auth) ((auth)->side) + +static DBusAuth* +_dbus_auth_new (int size) +{ + DBusAuth *auth; + + auth = dbus_malloc0 (size); + if (auth == NULL) + return NULL; + + auth->refcount = 1; + + auth->keyring = NULL; + auth->cookie_id = -1; + + /* note that we don't use the max string length feature, + * because you can't use that feature if you're going to + * try to recover from out-of-memory (it creates + * what looks like unrecoverable inability to alloc + * more space in the string). But we do handle + * overlong buffers in _dbus_auth_do_work(). + */ + + if (!_dbus_string_init (&auth->incoming)) + goto enomem_0; + + if (!_dbus_string_init (&auth->outgoing)) + goto enomem_1; + + if (!_dbus_string_init (&auth->identity)) + goto enomem_2; + + if (!_dbus_string_init (&auth->context)) + goto enomem_3; + + if (!_dbus_string_init (&auth->challenge)) + goto enomem_4; + + /* default context if none is specified */ + if (!_dbus_string_append (&auth->context, "org_freedesktop_general")) + goto enomem_5; + + auth->credentials = _dbus_credentials_new (); + if (auth->credentials == NULL) + goto enomem_6; + + auth->authorized_identity = _dbus_credentials_new (); + if (auth->authorized_identity == NULL) + goto enomem_7; + + auth->desired_identity = _dbus_credentials_new (); + if (auth->desired_identity == NULL) + goto enomem_8; + + return auth; + +#if 0 + enomem_9: + _dbus_credentials_unref (auth->desired_identity); +#endif + enomem_8: + _dbus_credentials_unref (auth->authorized_identity); + enomem_7: + _dbus_credentials_unref (auth->credentials); + enomem_6: + /* last alloc was an append to context, which is freed already below */ ; + enomem_5: + _dbus_string_free (&auth->challenge); + enomem_4: + _dbus_string_free (&auth->context); + enomem_3: + _dbus_string_free (&auth->identity); + enomem_2: + _dbus_string_free (&auth->outgoing); + enomem_1: + _dbus_string_free (&auth->incoming); + enomem_0: + dbus_free (auth); + return NULL; +} + +static void +shutdown_mech (DBusAuth *auth) +{ + /* Cancel any auth */ + auth->already_asked_for_initial_response = FALSE; + _dbus_string_set_length (&auth->identity, 0); + + _dbus_credentials_clear (auth->authorized_identity); + _dbus_credentials_clear (auth->desired_identity); + + if (auth->mech != NULL) + { + _dbus_verbose ("%s: Shutting down mechanism %s\n", + DBUS_AUTH_NAME (auth), auth->mech->mechanism); + + if (DBUS_AUTH_IS_CLIENT (auth)) + (* auth->mech->client_shutdown_func) (auth); + else + (* auth->mech->server_shutdown_func) (auth); + + auth->mech = NULL; + } +} + +/* + * DBUS_COOKIE_SHA1 mechanism + */ + +/* Returns TRUE but with an empty string hash if the + * cookie_id isn't known. As with all this code + * TRUE just means we had enough memory. + */ +static dbus_bool_t +sha1_compute_hash (DBusAuth *auth, + int cookie_id, + const DBusString *server_challenge, + const DBusString *client_challenge, + DBusString *hash) +{ + DBusString cookie; + DBusString to_hash; + dbus_bool_t retval; + + _dbus_assert (auth->keyring != NULL); + + retval = FALSE; + + if (!_dbus_string_init (&cookie)) + return FALSE; + + if (!_dbus_keyring_get_hex_key (auth->keyring, cookie_id, + &cookie)) + goto out_0; + + if (_dbus_string_get_length (&cookie) == 0) + { + retval = TRUE; + goto out_0; + } + + if (!_dbus_string_init (&to_hash)) + goto out_0; + + if (!_dbus_string_copy (server_challenge, 0, + &to_hash, _dbus_string_get_length (&to_hash))) + goto out_1; + + if (!_dbus_string_append (&to_hash, ":")) + goto out_1; + + if (!_dbus_string_copy (client_challenge, 0, + &to_hash, _dbus_string_get_length (&to_hash))) + goto out_1; + + if (!_dbus_string_append (&to_hash, ":")) + goto out_1; + + if (!_dbus_string_copy (&cookie, 0, + &to_hash, _dbus_string_get_length (&to_hash))) + goto out_1; + + if (!_dbus_sha_compute (&to_hash, hash)) + goto out_1; + + retval = TRUE; + + out_1: + _dbus_string_zero (&to_hash); + _dbus_string_free (&to_hash); + out_0: + _dbus_string_zero (&cookie); + _dbus_string_free (&cookie); + return retval; +} + +/** http://www.ietf.org/rfc/rfc2831.txt suggests at least 64 bits of + * entropy, we use 128. This is the number of bytes in the random + * challenge. + */ +#define N_CHALLENGE_BYTES (128/8) + +static dbus_bool_t +sha1_handle_first_client_response (DBusAuth *auth, + const DBusString *data) +{ + /* We haven't sent a challenge yet, we're expecting a desired + * username from the client. + */ + DBusString tmp; + DBusString tmp2; + dbus_bool_t retval; + DBusError error; + + retval = FALSE; + + _dbus_string_set_length (&auth->challenge, 0); + + if (_dbus_string_get_length (data) > 0) + { + if (_dbus_string_get_length (&auth->identity) > 0) + { + /* Tried to send two auth identities, wtf */ + _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n", + DBUS_AUTH_NAME (auth)); + return send_rejected (auth); + } + else + { + /* this is our auth identity */ + if (!_dbus_string_copy (data, 0, &auth->identity, 0)) + return FALSE; + } + } + + if (!_dbus_credentials_add_from_user (auth->desired_identity, data)) + { + _dbus_verbose ("%s: Did not get a valid username from client\n", + DBUS_AUTH_NAME (auth)); + return send_rejected (auth); + } + + if (!_dbus_string_init (&tmp)) + return FALSE; + + if (!_dbus_string_init (&tmp2)) + { + _dbus_string_free (&tmp); + return FALSE; + } + + /* we cache the keyring for speed, so here we drop it if it's the + * wrong one. FIXME caching the keyring here is useless since we use + * a different DBusAuth for every connection. + */ + if (auth->keyring && + !_dbus_keyring_is_for_credentials (auth->keyring, + auth->desired_identity)) + { + _dbus_keyring_unref (auth->keyring); + auth->keyring = NULL; + } + + if (auth->keyring == NULL) + { + dbus_error_init (&error); + auth->keyring = _dbus_keyring_new_for_credentials (auth->desired_identity, + &auth->context, + &error); + + if (auth->keyring == NULL) + { + if (dbus_error_has_name (&error, + DBUS_ERROR_NO_MEMORY)) + { + dbus_error_free (&error); + goto out; + } + else + { + _DBUS_ASSERT_ERROR_IS_SET (&error); + _dbus_verbose ("%s: Error loading keyring: %s\n", + DBUS_AUTH_NAME (auth), error.message); + if (send_rejected (auth)) + retval = TRUE; /* retval is only about mem */ + dbus_error_free (&error); + goto out; + } + } + else + { + _dbus_assert (!dbus_error_is_set (&error)); + } + } + + _dbus_assert (auth->keyring != NULL); + + dbus_error_init (&error); + auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error); + if (auth->cookie_id < 0) + { + _DBUS_ASSERT_ERROR_IS_SET (&error); + _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n", + DBUS_AUTH_NAME (auth), error.message); + if (send_rejected (auth)) + retval = TRUE; + dbus_error_free (&error); + goto out; + } + else + { + _dbus_assert (!dbus_error_is_set (&error)); + } + + if (!_dbus_string_copy (&auth->context, 0, + &tmp2, _dbus_string_get_length (&tmp2))) + goto out; + + if (!_dbus_string_append (&tmp2, " ")) + goto out; + + if (!_dbus_string_append_int (&tmp2, auth->cookie_id)) + goto out; + + if (!_dbus_string_append (&tmp2, " ")) + goto out; + + if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES)) + goto out; + + _dbus_string_set_length (&auth->challenge, 0); + if (!_dbus_string_hex_encode (&tmp, 0, &auth->challenge, 0)) + goto out; + + if (!_dbus_string_hex_encode (&tmp, 0, &tmp2, + _dbus_string_get_length (&tmp2))) + goto out; + + if (!send_data (auth, &tmp2)) + goto out; + + goto_state (auth, &server_state_waiting_for_data); + retval = TRUE; + + out: + _dbus_string_zero (&tmp); + _dbus_string_free (&tmp); + _dbus_string_zero (&tmp2); + _dbus_string_free (&tmp2); + + return retval; +} + +static dbus_bool_t +sha1_handle_second_client_response (DBusAuth *auth, + const DBusString *data) +{ + /* We are expecting a response which is the hex-encoded client + * challenge, space, then SHA-1 hash of the concatenation of our + * challenge, ":", client challenge, ":", secret key, all + * hex-encoded. + */ + int i; + DBusString client_challenge; + DBusString client_hash; + dbus_bool_t retval; + DBusString correct_hash; + + retval = FALSE; + + if (!_dbus_string_find_blank (data, 0, &i)) + { + _dbus_verbose ("%s: no space separator in client response\n", + DBUS_AUTH_NAME (auth)); + return send_rejected (auth); + } + + if (!_dbus_string_init (&client_challenge)) + goto out_0; + + if (!_dbus_string_init (&client_hash)) + goto out_1; + + if (!_dbus_string_copy_len (data, 0, i, &client_challenge, + 0)) + goto out_2; + + _dbus_string_skip_blank (data, i, &i); + + if (!_dbus_string_copy_len (data, i, + _dbus_string_get_length (data) - i, + &client_hash, + 0)) + goto out_2; + + if (_dbus_string_get_length (&client_challenge) == 0 || + _dbus_string_get_length (&client_hash) == 0) + { + _dbus_verbose ("%s: zero-length client challenge or hash\n", + DBUS_AUTH_NAME (auth)); + if (send_rejected (auth)) + retval = TRUE; + goto out_2; + } + + if (!_dbus_string_init (&correct_hash)) + goto out_2; + + if (!sha1_compute_hash (auth, auth->cookie_id, + &auth->challenge, + &client_challenge, + &correct_hash)) + goto out_3; + + /* if cookie_id was invalid, then we get an empty hash */ + if (_dbus_string_get_length (&correct_hash) == 0) + { + if (send_rejected (auth)) + retval = TRUE; + goto out_3; + } + + if (!_dbus_string_equal (&client_hash, &correct_hash)) + { + if (send_rejected (auth)) + retval = TRUE; + goto out_3; + } + + if (!_dbus_credentials_add_credentials (auth->authorized_identity, + auth->desired_identity)) + goto out_3; + + /* Copy process ID from the socket credentials if it's there + */ + if (!_dbus_credentials_add_credential (auth->authorized_identity, + DBUS_CREDENTIAL_UNIX_PROCESS_ID, + auth->credentials)) + goto out_3; + + if (!send_ok (auth)) + goto out_3; + + _dbus_verbose ("%s: authenticated client using DBUS_COOKIE_SHA1\n", + DBUS_AUTH_NAME (auth)); + + retval = TRUE; + + out_3: + _dbus_string_zero (&correct_hash); + _dbus_string_free (&correct_hash); + out_2: + _dbus_string_zero (&client_hash); + _dbus_string_free (&client_hash); + out_1: + _dbus_string_free (&client_challenge); + out_0: + return retval; +} + +static dbus_bool_t +handle_server_data_cookie_sha1_mech (DBusAuth *auth, + const DBusString *data) +{ + if (auth->cookie_id < 0) + return sha1_handle_first_client_response (auth, data); + else + return sha1_handle_second_client_response (auth, data); +} + +static void +handle_server_shutdown_cookie_sha1_mech (DBusAuth *auth) +{ + auth->cookie_id = -1; + _dbus_string_set_length (&auth->challenge, 0); +} + +static dbus_bool_t +handle_client_initial_response_cookie_sha1_mech (DBusAuth *auth, + DBusString *response) +{ + DBusString username; + dbus_bool_t retval; + + retval = FALSE; + + if (!_dbus_string_init (&username)) + return FALSE; + + if (!_dbus_append_user_from_current_process (&username)) + goto out_0; + + if (!_dbus_string_hex_encode (&username, 0, + response, + _dbus_string_get_length (response))) + goto out_0; + + retval = TRUE; + + out_0: + _dbus_string_free (&username); + + return retval; +} + +static dbus_bool_t +handle_client_data_cookie_sha1_mech (DBusAuth *auth, + const DBusString *data) +{ + /* The data we get from the server should be the cookie context + * name, the cookie ID, and the server challenge, separated by + * spaces. We send back our challenge string and the correct hash. + */ + dbus_bool_t retval; + DBusString context; + DBusString cookie_id_str; + DBusString server_challenge; + DBusString client_challenge; + DBusString correct_hash; + DBusString tmp; + int i, j; + long val; + + retval = FALSE; + + if (!_dbus_string_find_blank (data, 0, &i)) + { + if (send_error (auth, + "Server did not send context/ID/challenge properly")) + retval = TRUE; + goto out_0; + } + + if (!_dbus_string_init (&context)) + goto out_0; + + if (!_dbus_string_copy_len (data, 0, i, + &context, 0)) + goto out_1; + + _dbus_string_skip_blank (data, i, &i); + if (!_dbus_string_find_blank (data, i, &j)) + { + if (send_error (auth, + "Server did not send context/ID/challenge properly")) + retval = TRUE; + goto out_1; + } + + if (!_dbus_string_init (&cookie_id_str)) + goto out_1; + + if (!_dbus_string_copy_len (data, i, j - i, + &cookie_id_str, 0)) + goto out_2; + + if (!_dbus_string_init (&server_challenge)) + goto out_2; + + i = j; + _dbus_string_skip_blank (data, i, &i); + j = _dbus_string_get_length (data); + + if (!_dbus_string_copy_len (data, i, j - i, + &server_challenge, 0)) + goto out_3; + + if (!_dbus_keyring_validate_context (&context)) + { + if (send_error (auth, "Server sent invalid cookie context")) + retval = TRUE; + goto out_3; + } + + if (!_dbus_string_parse_int (&cookie_id_str, 0, &val, NULL)) + { + if (send_error (auth, "Could not parse cookie ID as an integer")) + retval = TRUE; + goto out_3; + } + + if (_dbus_string_get_length (&server_challenge) == 0) + { + if (send_error (auth, "Empty server challenge string")) + retval = TRUE; + goto out_3; + } + + if (auth->keyring == NULL) + { + DBusError error; + + dbus_error_init (&error); + auth->keyring = _dbus_keyring_new_for_credentials (NULL, + &context, + &error); + + if (auth->keyring == NULL) + { + if (dbus_error_has_name (&error, + DBUS_ERROR_NO_MEMORY)) + { + dbus_error_free (&error); + goto out_3; + } + else + { + _DBUS_ASSERT_ERROR_IS_SET (&error); + + _dbus_verbose ("%s: Error loading keyring: %s\n", + DBUS_AUTH_NAME (auth), error.message); + + if (send_error (auth, "Could not load cookie file")) + retval = TRUE; /* retval is only about mem */ + + dbus_error_free (&error); + goto out_3; + } + } + else + { + _dbus_assert (!dbus_error_is_set (&error)); + } + } + + _dbus_assert (auth->keyring != NULL); + + if (!_dbus_string_init (&tmp)) + goto out_3; + + if (!_dbus_generate_random_bytes (&tmp, N_CHALLENGE_BYTES)) + goto out_4; + + if (!_dbus_string_init (&client_challenge)) + goto out_4; + + if (!_dbus_string_hex_encode (&tmp, 0, &client_challenge, 0)) + goto out_5; + + if (!_dbus_string_init (&correct_hash)) + goto out_5; + + if (!sha1_compute_hash (auth, val, + &server_challenge, + &client_challenge, + &correct_hash)) + goto out_6; + + if (_dbus_string_get_length (&correct_hash) == 0) + { + /* couldn't find the cookie ID or something */ + if (send_error (auth, "Don't have the requested cookie ID")) + retval = TRUE; + goto out_6; + } + + _dbus_string_set_length (&tmp, 0); + + if (!_dbus_string_copy (&client_challenge, 0, &tmp, + _dbus_string_get_length (&tmp))) + goto out_6; + + if (!_dbus_string_append (&tmp, " ")) + goto out_6; + + if (!_dbus_string_copy (&correct_hash, 0, &tmp, + _dbus_string_get_length (&tmp))) + goto out_6; + + if (!send_data (auth, &tmp)) + goto out_6; + + retval = TRUE; + + out_6: + _dbus_string_zero (&correct_hash); + _dbus_string_free (&correct_hash); + out_5: + _dbus_string_free (&client_challenge); + out_4: + _dbus_string_zero (&tmp); + _dbus_string_free (&tmp); + out_3: + _dbus_string_free (&server_challenge); + out_2: + _dbus_string_free (&cookie_id_str); + out_1: + _dbus_string_free (&context); + out_0: + return retval; +} + +static void +handle_client_shutdown_cookie_sha1_mech (DBusAuth *auth) +{ + auth->cookie_id = -1; + _dbus_string_set_length (&auth->challenge, 0); +} + +/* + * EXTERNAL mechanism + */ + +static dbus_bool_t +handle_server_data_external_mech (DBusAuth *auth, + const DBusString *data) +{ + if (_dbus_credentials_are_anonymous (auth->credentials)) + { + _dbus_verbose ("%s: no credentials, mechanism EXTERNAL can't authenticate\n", + DBUS_AUTH_NAME (auth)); + return send_rejected (auth); + } + + if (_dbus_string_get_length (data) > 0) + { + if (_dbus_string_get_length (&auth->identity) > 0) + { + /* Tried to send two auth identities, wtf */ + _dbus_verbose ("%s: client tried to send auth identity, but we already have one\n", + DBUS_AUTH_NAME (auth)); + return send_rejected (auth); + } + else + { + /* this is our auth identity */ + if (!_dbus_string_copy (data, 0, &auth->identity, 0)) + return FALSE; + } + } + + /* Poke client for an auth identity, if none given */ + if (_dbus_string_get_length (&auth->identity) == 0 && + !auth->already_asked_for_initial_response) + { + if (send_data (auth, NULL)) + { + _dbus_verbose ("%s: sending empty challenge asking client for auth identity\n", + DBUS_AUTH_NAME (auth)); + auth->already_asked_for_initial_response = TRUE; + goto_state (auth, &server_state_waiting_for_data); + return TRUE; + } + else + return FALSE; + } + + _dbus_credentials_clear (auth->desired_identity); + + /* If auth->identity is still empty here, then client + * responded with an empty string after we poked it for + * an initial response. This means to try to auth the + * identity provided in the credentials. + */ + if (_dbus_string_get_length (&auth->identity) == 0) + { + if (!_dbus_credentials_add_credentials (auth->desired_identity, + auth->credentials)) + { + return FALSE; /* OOM */ + } + } + else + { + if (!_dbus_credentials_add_from_user (auth->desired_identity, + &auth->identity)) + { + _dbus_verbose ("%s: could not get credentials from uid string\n", + DBUS_AUTH_NAME (auth)); + return send_rejected (auth); + } + } + + if (_dbus_credentials_are_anonymous (auth->desired_identity)) + { + _dbus_verbose ("%s: desired user %s is no good\n", + DBUS_AUTH_NAME (auth), + _dbus_string_get_const_data (&auth->identity)); + return send_rejected (auth); + } + + if (_dbus_credentials_are_superset (auth->credentials, + auth->desired_identity)) + { + /* client has authenticated */ + if (!_dbus_credentials_add_credentials (auth->authorized_identity, + auth->desired_identity)) + return FALSE; + + /* also copy process ID from the socket credentials + */ + if (!_dbus_credentials_add_credential (auth->authorized_identity, + DBUS_CREDENTIAL_UNIX_PROCESS_ID, + auth->credentials)) + return FALSE; + + /* also copy audit data from the socket credentials + */ + if (!_dbus_credentials_add_credential (auth->authorized_identity, + DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, + auth->credentials)) + return FALSE; + + if (!send_ok (auth)) + return FALSE; + + _dbus_verbose ("%s: authenticated client based on socket credentials\n", + DBUS_AUTH_NAME (auth)); + + return TRUE; + } + else + { + _dbus_verbose ("%s: desired identity not found in socket credentials\n", + DBUS_AUTH_NAME (auth)); + return send_rejected (auth); + } +} + +static void +handle_server_shutdown_external_mech (DBusAuth *auth) +{ + +} + +static dbus_bool_t +handle_client_initial_response_external_mech (DBusAuth *auth, + DBusString *response) +{ + /* We always append our UID as an initial response, so the server + * doesn't have to send back an empty challenge to check whether we + * want to specify an identity. i.e. this avoids a round trip that + * the spec for the EXTERNAL mechanism otherwise requires. + */ + DBusString plaintext; + + if (!_dbus_string_init (&plaintext)) + return FALSE; + + if (!_dbus_append_user_from_current_process (&plaintext)) + goto failed; + + if (!_dbus_string_hex_encode (&plaintext, 0, + response, + _dbus_string_get_length (response))) + goto failed; + + _dbus_string_free (&plaintext); + + return TRUE; + + failed: + _dbus_string_free (&plaintext); + return FALSE; +} + +static dbus_bool_t +handle_client_data_external_mech (DBusAuth *auth, + const DBusString *data) +{ + + return TRUE; +} + +static void +handle_client_shutdown_external_mech (DBusAuth *auth) +{ + +} + +/* + * ANONYMOUS mechanism + */ + +static dbus_bool_t +handle_server_data_anonymous_mech (DBusAuth *auth, + const DBusString *data) +{ + if (_dbus_string_get_length (data) > 0) + { + /* Client is allowed to send "trace" data, the only defined + * meaning is that if it contains '@' it is an email address, + * and otherwise it is anything else, and it's supposed to be + * UTF-8 + */ + if (!_dbus_string_validate_utf8 (data, 0, _dbus_string_get_length (data))) + { + _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n", + DBUS_AUTH_NAME (auth)); + + { + DBusString plaintext; + DBusString encoded; + _dbus_string_init_const (&plaintext, "D-Bus " VERSION); + _dbus_string_init (&encoded); + _dbus_string_hex_encode (&plaintext, 0, + &encoded, + 0); + _dbus_verbose ("%s: try '%s'\n", + DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded)); + } + return send_rejected (auth); + } + + _dbus_verbose ("%s: ANONYMOUS client sent trace string: '%s'\n", + DBUS_AUTH_NAME (auth), + _dbus_string_get_const_data (data)); + } + + /* We want to be anonymous (clear in case some other protocol got midway through I guess) */ + _dbus_credentials_clear (auth->desired_identity); + + /* Copy process ID from the socket credentials + */ + if (!_dbus_credentials_add_credential (auth->authorized_identity, + DBUS_CREDENTIAL_UNIX_PROCESS_ID, + auth->credentials)) + return FALSE; + + /* Anonymous is always allowed */ + if (!send_ok (auth)) + return FALSE; + + _dbus_verbose ("%s: authenticated client as anonymous\n", + DBUS_AUTH_NAME (auth)); + + return TRUE; +} + +static void +handle_server_shutdown_anonymous_mech (DBusAuth *auth) +{ + +} + +static dbus_bool_t +handle_client_initial_response_anonymous_mech (DBusAuth *auth, + DBusString *response) +{ + /* Our initial response is a "trace" string which must be valid UTF-8 + * and must be an email address if it contains '@'. + * We just send the dbus implementation info, like a user-agent or + * something, because... why not. There's nothing guaranteed here + * though, we could change it later. + */ + DBusString plaintext; + + if (!_dbus_string_init (&plaintext)) + return FALSE; + + if (!_dbus_string_append (&plaintext, + "libdbus " VERSION)) + goto failed; + + if (!_dbus_string_hex_encode (&plaintext, 0, + response, + _dbus_string_get_length (response))) + goto failed; + + _dbus_string_free (&plaintext); + + return TRUE; + + failed: + _dbus_string_free (&plaintext); + return FALSE; +} + +static dbus_bool_t +handle_client_data_anonymous_mech (DBusAuth *auth, + const DBusString *data) +{ + + return TRUE; +} + +static void +handle_client_shutdown_anonymous_mech (DBusAuth *auth) +{ + +} + +/* Put mechanisms here in order of preference. + * Right now we have: + * + * - EXTERNAL checks socket credentials (or in the future, other info from the OS) + * - DBUS_COOKIE_SHA1 uses a cookie in the home directory, like xauth or ICE + * - ANONYMOUS checks nothing but doesn't auth the person as a user + * + * We might ideally add a mechanism to chain to Cyrus SASL so we can + * use its mechanisms as well. + * + */ +static const DBusAuthMechanismHandler +all_mechanisms[] = { + { "EXTERNAL", + handle_server_data_external_mech, + NULL, NULL, + handle_server_shutdown_external_mech, + handle_client_initial_response_external_mech, + handle_client_data_external_mech, + NULL, NULL, + handle_client_shutdown_external_mech }, + { "DBUS_COOKIE_SHA1", + handle_server_data_cookie_sha1_mech, + NULL, NULL, + handle_server_shutdown_cookie_sha1_mech, + handle_client_initial_response_cookie_sha1_mech, + handle_client_data_cookie_sha1_mech, + NULL, NULL, + handle_client_shutdown_cookie_sha1_mech }, + { "ANONYMOUS", + handle_server_data_anonymous_mech, + NULL, NULL, + handle_server_shutdown_anonymous_mech, + handle_client_initial_response_anonymous_mech, + handle_client_data_anonymous_mech, + NULL, NULL, + handle_client_shutdown_anonymous_mech }, + { NULL, NULL } +}; + +static const DBusAuthMechanismHandler* +find_mech (const DBusString *name, + char **allowed_mechs) +{ + int i; + + if (allowed_mechs != NULL && + !_dbus_string_array_contains ((const char**) allowed_mechs, + _dbus_string_get_const_data (name))) + return NULL; + + i = 0; + while (all_mechanisms[i].mechanism != NULL) + { + if (_dbus_string_equal_c_str (name, + all_mechanisms[i].mechanism)) + + return &all_mechanisms[i]; + + ++i; + } + + return NULL; +} + +static dbus_bool_t +send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech) +{ + DBusString auth_command; + + if (!_dbus_string_init (&auth_command)) + return FALSE; + + if (!_dbus_string_append (&auth_command, + "AUTH ")) + { + _dbus_string_free (&auth_command); + return FALSE; + } + + if (!_dbus_string_append (&auth_command, + mech->mechanism)) + { + _dbus_string_free (&auth_command); + return FALSE; + } + + if (mech->client_initial_response_func != NULL) + { + if (!_dbus_string_append (&auth_command, " ")) + { + _dbus_string_free (&auth_command); + return FALSE; + } + + if (!(* mech->client_initial_response_func) (auth, &auth_command)) + { + _dbus_string_free (&auth_command); + return FALSE; + } + } + + if (!_dbus_string_append (&auth_command, + "\r\n")) + { + _dbus_string_free (&auth_command); + return FALSE; + } + + if (!_dbus_string_copy (&auth_command, 0, + &auth->outgoing, + _dbus_string_get_length (&auth->outgoing))) + { + _dbus_string_free (&auth_command); + return FALSE; + } + + _dbus_string_free (&auth_command); + shutdown_mech (auth); + auth->mech = mech; + goto_state (auth, &client_state_waiting_for_data); + + return TRUE; +} + +static dbus_bool_t +send_data (DBusAuth *auth, DBusString *data) +{ + int old_len; + + if (data == NULL || _dbus_string_get_length (data) == 0) + return _dbus_string_append (&auth->outgoing, "DATA\r\n"); + else + { + old_len = _dbus_string_get_length (&auth->outgoing); + if (!_dbus_string_append (&auth->outgoing, "DATA ")) + goto out; + + if (!_dbus_string_hex_encode (data, 0, &auth->outgoing, + _dbus_string_get_length (&auth->outgoing))) + goto out; + + if (!_dbus_string_append (&auth->outgoing, "\r\n")) + goto out; + + return TRUE; + + out: + _dbus_string_set_length (&auth->outgoing, old_len); + + return FALSE; + } +} + +static dbus_bool_t +send_rejected (DBusAuth *auth) +{ + DBusString command; + DBusAuthServer *server_auth; + int i; + + if (!_dbus_string_init (&command)) + return FALSE; + + if (!_dbus_string_append (&command, + "REJECTED")) + goto nomem; + + i = 0; + while (all_mechanisms[i].mechanism != NULL) + { + if (!_dbus_string_append (&command, + " ")) + goto nomem; + + if (!_dbus_string_append (&command, + all_mechanisms[i].mechanism)) + goto nomem; + + ++i; + } + + if (!_dbus_string_append (&command, "\r\n")) + goto nomem; + + if (!_dbus_string_copy (&command, 0, &auth->outgoing, + _dbus_string_get_length (&auth->outgoing))) + goto nomem; + + shutdown_mech (auth); + + _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); + server_auth = DBUS_AUTH_SERVER (auth); + server_auth->failures += 1; + + if (server_auth->failures >= server_auth->max_failures) + goto_state (auth, &common_state_need_disconnect); + else + goto_state (auth, &server_state_waiting_for_auth); + + _dbus_string_free (&command); + + return TRUE; + + nomem: + _dbus_string_free (&command); + return FALSE; +} + +static dbus_bool_t +send_error (DBusAuth *auth, const char *message) +{ + return _dbus_string_append_printf (&auth->outgoing, + "ERROR \"%s\"\r\n", message); +} + +static dbus_bool_t +send_ok (DBusAuth *auth) +{ + int orig_len; + + orig_len = _dbus_string_get_length (&auth->outgoing); + + if (_dbus_string_append (&auth->outgoing, "OK ") && + _dbus_string_copy (& DBUS_AUTH_SERVER (auth)->guid, + 0, + &auth->outgoing, + _dbus_string_get_length (&auth->outgoing)) && + _dbus_string_append (&auth->outgoing, "\r\n")) + { + goto_state (auth, &server_state_waiting_for_begin); + return TRUE; + } + else + { + _dbus_string_set_length (&auth->outgoing, orig_len); + return FALSE; + } +} + +static dbus_bool_t +send_begin (DBusAuth *auth, + const DBusString *args_from_ok) +{ + int end_of_hex; + + /* "args_from_ok" should be the GUID, whitespace already pulled off the front */ + _dbus_assert (_dbus_string_get_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server) == 0); + + /* We decode the hex string to binary, using guid_from_server as scratch... */ + + end_of_hex = 0; + if (!_dbus_string_hex_decode (args_from_ok, 0, &end_of_hex, + & DBUS_AUTH_CLIENT (auth)->guid_from_server, 0)) + return FALSE; + + /* now clear out the scratch */ + _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); + + if (end_of_hex != _dbus_string_get_length (args_from_ok) || + end_of_hex == 0) + { + _dbus_verbose ("Bad GUID from server, parsed %d bytes and had %d bytes from server\n", + end_of_hex, _dbus_string_get_length (args_from_ok)); + goto_state (auth, &common_state_need_disconnect); + return TRUE; + } + + if (_dbus_string_copy (args_from_ok, 0, &DBUS_AUTH_CLIENT (auth)->guid_from_server, 0) && + _dbus_string_append (&auth->outgoing, "BEGIN\r\n")) + { + _dbus_verbose ("Got GUID '%s' from the server\n", + _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server)); + + goto_state (auth, &common_state_authenticated); + return TRUE; + } + else + { + _dbus_string_set_length (& DBUS_AUTH_CLIENT (auth)->guid_from_server, 0); + return FALSE; + } +} + +static dbus_bool_t +send_cancel (DBusAuth *auth) +{ + if (_dbus_string_append (&auth->outgoing, "CANCEL\r\n")) + { + goto_state (auth, &client_state_waiting_for_reject); + return TRUE; + } + else + return FALSE; +} + +static dbus_bool_t +process_data (DBusAuth *auth, + const DBusString *args, + DBusAuthDataFunction data_func) +{ + int end; + DBusString decoded; + + if (!_dbus_string_init (&decoded)) + return FALSE; + + if (!_dbus_string_hex_decode (args, 0, &end, &decoded, 0)) + { + _dbus_string_free (&decoded); + return FALSE; + } + + if (_dbus_string_get_length (args) != end) + { + _dbus_string_free (&decoded); + if (!send_error (auth, "Invalid hex encoding")) + return FALSE; + + return TRUE; + } + +#ifdef DBUS_ENABLE_VERBOSE_MODE + if (_dbus_string_validate_ascii (&decoded, 0, + _dbus_string_get_length (&decoded))) + _dbus_verbose ("%s: data: '%s'\n", + DBUS_AUTH_NAME (auth), + _dbus_string_get_const_data (&decoded)); +#endif + + if (!(* data_func) (auth, &decoded)) + { + _dbus_string_free (&decoded); + return FALSE; + } + + _dbus_string_free (&decoded); + return TRUE; +} + +static dbus_bool_t +handle_auth (DBusAuth *auth, const DBusString *args) +{ + if (_dbus_string_get_length (args) == 0) + { + /* No args to the auth, send mechanisms */ + if (!send_rejected (auth)) + return FALSE; + + return TRUE; + } + else + { + int i; + DBusString mech; + DBusString hex_response; + + _dbus_string_find_blank (args, 0, &i); + + if (!_dbus_string_init (&mech)) + return FALSE; + + if (!_dbus_string_init (&hex_response)) + { + _dbus_string_free (&mech); + return FALSE; + } + + if (!_dbus_string_copy_len (args, 0, i, &mech, 0)) + goto failed; + + _dbus_string_skip_blank (args, i, &i); + if (!_dbus_string_copy (args, i, &hex_response, 0)) + goto failed; + + auth->mech = find_mech (&mech, auth->allowed_mechs); + if (auth->mech != NULL) + { + _dbus_verbose ("%s: Trying mechanism %s\n", + DBUS_AUTH_NAME (auth), + auth->mech->mechanism); + + if (!process_data (auth, &hex_response, + auth->mech->server_data_func)) + goto failed; + } + else + { + /* Unsupported mechanism */ + _dbus_verbose ("%s: Unsupported mechanism %s\n", + DBUS_AUTH_NAME (auth), + _dbus_string_get_const_data (&mech)); + + if (!send_rejected (auth)) + goto failed; + } + + _dbus_string_free (&mech); + _dbus_string_free (&hex_response); + + return TRUE; + + failed: + auth->mech = NULL; + _dbus_string_free (&mech); + _dbus_string_free (&hex_response); + return FALSE; + } +} + +static dbus_bool_t +handle_server_state_waiting_for_auth (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args) +{ + switch (command) + { + case DBUS_AUTH_COMMAND_AUTH: + return handle_auth (auth, args); + + case DBUS_AUTH_COMMAND_CANCEL: + case DBUS_AUTH_COMMAND_DATA: + return send_error (auth, "Not currently in an auth conversation"); + + case DBUS_AUTH_COMMAND_BEGIN: + goto_state (auth, &common_state_need_disconnect); + return TRUE; + + case DBUS_AUTH_COMMAND_ERROR: + return send_rejected (auth); + + case DBUS_AUTH_COMMAND_REJECTED: + case DBUS_AUTH_COMMAND_OK: + case DBUS_AUTH_COMMAND_UNKNOWN: + default: + return send_error (auth, "Unknown command"); + } +} + +static dbus_bool_t +handle_server_state_waiting_for_data (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args) +{ + switch (command) + { + case DBUS_AUTH_COMMAND_AUTH: + return send_error (auth, "Sent AUTH while another AUTH in progress"); + + case DBUS_AUTH_COMMAND_CANCEL: + case DBUS_AUTH_COMMAND_ERROR: + return send_rejected (auth); + + case DBUS_AUTH_COMMAND_DATA: + return process_data (auth, args, auth->mech->server_data_func); + + case DBUS_AUTH_COMMAND_BEGIN: + goto_state (auth, &common_state_need_disconnect); + return TRUE; + + case DBUS_AUTH_COMMAND_REJECTED: + case DBUS_AUTH_COMMAND_OK: + case DBUS_AUTH_COMMAND_UNKNOWN: + default: + return send_error (auth, "Unknown command"); + } +} + +static dbus_bool_t +handle_server_state_waiting_for_begin (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args) +{ + switch (command) + { + case DBUS_AUTH_COMMAND_AUTH: + return send_error (auth, "Sent AUTH while expecting BEGIN"); + + case DBUS_AUTH_COMMAND_DATA: + return send_error (auth, "Sent DATA while expecting BEGIN"); + + case DBUS_AUTH_COMMAND_BEGIN: + goto_state (auth, &common_state_authenticated); + return TRUE; + + case DBUS_AUTH_COMMAND_REJECTED: + case DBUS_AUTH_COMMAND_OK: + case DBUS_AUTH_COMMAND_UNKNOWN: + default: + return send_error (auth, "Unknown command"); + + case DBUS_AUTH_COMMAND_CANCEL: + case DBUS_AUTH_COMMAND_ERROR: + return send_rejected (auth); + } +} + +/* return FALSE if no memory, TRUE if all OK */ +static dbus_bool_t +get_word (const DBusString *str, + int *start, + DBusString *word) +{ + int i; + + _dbus_string_skip_blank (str, *start, start); + _dbus_string_find_blank (str, *start, &i); + + if (i > *start) + { + if (!_dbus_string_copy_len (str, *start, i - *start, word, 0)) + return FALSE; + + *start = i; + } + + return TRUE; +} + +static dbus_bool_t +record_mechanisms (DBusAuth *auth, + const DBusString *args) +{ + int next; + int len; + + if (auth->already_got_mechanisms) + return TRUE; + + len = _dbus_string_get_length (args); + + next = 0; + while (next < len) + { + DBusString m; + const DBusAuthMechanismHandler *mech; + + if (!_dbus_string_init (&m)) + goto nomem; + + if (!get_word (args, &next, &m)) + { + _dbus_string_free (&m); + goto nomem; + } + + mech = find_mech (&m, auth->allowed_mechs); + + if (mech != NULL) + { + /* FIXME right now we try mechanisms in the order + * the server lists them; should we do them in + * some more deterministic order? + * + * Probably in all_mechanisms order, our order of + * preference. Of course when the server is us, + * it lists things in that order anyhow. + */ + + if (mech != &all_mechanisms[0]) + { + _dbus_verbose ("%s: Adding mechanism %s to list we will try\n", + DBUS_AUTH_NAME (auth), mech->mechanism); + + if (!_dbus_list_append (& DBUS_AUTH_CLIENT (auth)->mechs_to_try, + (void*) mech)) + { + _dbus_string_free (&m); + goto nomem; + } + } + else + { + _dbus_verbose ("%s: Already tried mechanism %s; not adding to list we will try\n", + DBUS_AUTH_NAME (auth), mech->mechanism); + } + } + else + { + _dbus_verbose ("%s: Server offered mechanism \"%s\" that we don't know how to use\n", + DBUS_AUTH_NAME (auth), + _dbus_string_get_const_data (&m)); + } + + _dbus_string_free (&m); + } + + auth->already_got_mechanisms = TRUE; + + return TRUE; + + nomem: + _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); + + return FALSE; +} + +static dbus_bool_t +process_rejected (DBusAuth *auth, const DBusString *args) +{ + const DBusAuthMechanismHandler *mech; + DBusAuthClient *client; + + client = DBUS_AUTH_CLIENT (auth); + + if (!auth->already_got_mechanisms) + { + if (!record_mechanisms (auth, args)) + return FALSE; + } + + if (DBUS_AUTH_CLIENT (auth)->mechs_to_try != NULL) + { + mech = client->mechs_to_try->data; + + if (!send_auth (auth, mech)) + return FALSE; + + _dbus_list_pop_first (&client->mechs_to_try); + + _dbus_verbose ("%s: Trying mechanism %s\n", + DBUS_AUTH_NAME (auth), + mech->mechanism); + } + else + { + /* Give up */ + _dbus_verbose ("%s: Disconnecting because we are out of mechanisms to try using\n", + DBUS_AUTH_NAME (auth)); + goto_state (auth, &common_state_need_disconnect); + } + + return TRUE; +} + + +static dbus_bool_t +handle_client_state_waiting_for_data (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args) +{ + _dbus_assert (auth->mech != NULL); + + switch (command) + { + case DBUS_AUTH_COMMAND_DATA: + return process_data (auth, args, auth->mech->client_data_func); + + case DBUS_AUTH_COMMAND_REJECTED: + return process_rejected (auth, args); + + case DBUS_AUTH_COMMAND_OK: + return send_begin (auth, args); + + case DBUS_AUTH_COMMAND_ERROR: + return send_cancel (auth); + + case DBUS_AUTH_COMMAND_AUTH: + case DBUS_AUTH_COMMAND_CANCEL: + case DBUS_AUTH_COMMAND_BEGIN: + case DBUS_AUTH_COMMAND_UNKNOWN: + default: + return send_error (auth, "Unknown command"); + } +} + +static dbus_bool_t +handle_client_state_waiting_for_ok (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args) +{ + switch (command) + { + case DBUS_AUTH_COMMAND_REJECTED: + return process_rejected (auth, args); + + case DBUS_AUTH_COMMAND_OK: + return send_begin (auth, args); + + case DBUS_AUTH_COMMAND_DATA: + case DBUS_AUTH_COMMAND_ERROR: + return send_cancel (auth); + + case DBUS_AUTH_COMMAND_AUTH: + case DBUS_AUTH_COMMAND_CANCEL: + case DBUS_AUTH_COMMAND_BEGIN: + case DBUS_AUTH_COMMAND_UNKNOWN: + default: + return send_error (auth, "Unknown command"); + } +} + +static dbus_bool_t +handle_client_state_waiting_for_reject (DBusAuth *auth, + DBusAuthCommand command, + const DBusString *args) +{ + switch (command) + { + case DBUS_AUTH_COMMAND_REJECTED: + return process_rejected (auth, args); + + case DBUS_AUTH_COMMAND_AUTH: + case DBUS_AUTH_COMMAND_CANCEL: + case DBUS_AUTH_COMMAND_DATA: + case DBUS_AUTH_COMMAND_BEGIN: + case DBUS_AUTH_COMMAND_OK: + case DBUS_AUTH_COMMAND_ERROR: + case DBUS_AUTH_COMMAND_UNKNOWN: + default: + goto_state (auth, &common_state_need_disconnect); + return TRUE; + } +} + +/** + * Mapping from command name to enum + */ +typedef struct { + const char *name; /**< Name of the command */ + DBusAuthCommand command; /**< Corresponding enum */ +} DBusAuthCommandName; + +static const DBusAuthCommandName auth_command_names[] = { + { "AUTH", DBUS_AUTH_COMMAND_AUTH }, + { "CANCEL", DBUS_AUTH_COMMAND_CANCEL }, + { "DATA", DBUS_AUTH_COMMAND_DATA }, + { "BEGIN", DBUS_AUTH_COMMAND_BEGIN }, + { "REJECTED", DBUS_AUTH_COMMAND_REJECTED }, + { "OK", DBUS_AUTH_COMMAND_OK }, + { "ERROR", DBUS_AUTH_COMMAND_ERROR } +}; + +static DBusAuthCommand +lookup_command_from_name (DBusString *command) +{ + int i; + + for (i = 0; i < _DBUS_N_ELEMENTS (auth_command_names); i++) + { + if (_dbus_string_equal_c_str (command, + auth_command_names[i].name)) + return auth_command_names[i].command; + } + + return DBUS_AUTH_COMMAND_UNKNOWN; +} + +static void +goto_state (DBusAuth *auth, + const DBusAuthStateData *state) +{ + _dbus_verbose ("%s: going from state %s to state %s\n", + DBUS_AUTH_NAME (auth), + auth->state->name, + state->name); + + auth->state = state; +} + +/* returns whether to call it again right away */ +static dbus_bool_t +process_command (DBusAuth *auth) +{ + DBusAuthCommand command; + DBusString line; + DBusString args; + int eol; + int i, j; + dbus_bool_t retval; + + /* _dbus_verbose ("%s: trying process_command()\n"); */ + + retval = FALSE; + + eol = 0; + if (!_dbus_string_find (&auth->incoming, 0, "\r\n", &eol)) + return FALSE; + + if (!_dbus_string_init (&line)) + { + auth->needed_memory = TRUE; + return FALSE; + } + + if (!_dbus_string_init (&args)) + { + _dbus_string_free (&line); + auth->needed_memory = TRUE; + return FALSE; + } + + if (!_dbus_string_copy_len (&auth->incoming, 0, eol, &line, 0)) + goto out; + + if (!_dbus_string_validate_ascii (&line, 0, + _dbus_string_get_length (&line))) + { + _dbus_verbose ("%s: Command contained non-ASCII chars or embedded nul\n", + DBUS_AUTH_NAME (auth)); + if (!send_error (auth, "Command contained non-ASCII")) + goto out; + else + goto next_command; + } + + _dbus_verbose ("%s: got command \"%s\"\n", + DBUS_AUTH_NAME (auth), + _dbus_string_get_const_data (&line)); + + _dbus_string_find_blank (&line, 0, &i); + _dbus_string_skip_blank (&line, i, &j); + + if (j > i) + _dbus_string_delete (&line, i, j - i); + + if (!_dbus_string_move (&line, i, &args, 0)) + goto out; + + /* FIXME 1.0 we should probably validate that only the allowed + * chars are in the command name + */ + + command = lookup_command_from_name (&line); + if (!(* auth->state->handler) (auth, command, &args)) + goto out; + + next_command: + + /* We've succeeded in processing the whole command so drop it out + * of the incoming buffer and return TRUE to try another command. + */ + + _dbus_string_delete (&auth->incoming, 0, eol); + + /* kill the \r\n */ + _dbus_string_delete (&auth->incoming, 0, 2); + + retval = TRUE; + + out: + _dbus_string_free (&args); + _dbus_string_free (&line); + + if (!retval) + auth->needed_memory = TRUE; + else + auth->needed_memory = FALSE; + + return retval; +} + + +/** @} */ + +/** + * @addtogroup DBusAuth + * @{ + */ + +/** + * Creates a new auth conversation object for the server side. + * See doc/dbus-sasl-profile.txt for full details on what + * this object does. + * + * @returns the new object or #NULL if no memory + */ +DBusAuth* +_dbus_auth_server_new (const DBusString *guid) +{ + DBusAuth *auth; + DBusAuthServer *server_auth; + DBusString guid_copy; + + if (!_dbus_string_init (&guid_copy)) + return NULL; + + if (!_dbus_string_copy (guid, 0, &guid_copy, 0)) + { + _dbus_string_free (&guid_copy); + return NULL; + } + + auth = _dbus_auth_new (sizeof (DBusAuthServer)); + if (auth == NULL) + { + _dbus_string_free (&guid_copy); + return NULL; + } + + auth->side = auth_side_server; + auth->state = &server_state_waiting_for_auth; + + server_auth = DBUS_AUTH_SERVER (auth); + + server_auth->guid = guid_copy; + + /* perhaps this should be per-mechanism with a lower + * max + */ + server_auth->failures = 0; + server_auth->max_failures = 6; + + return auth; +} + +/** + * Creates a new auth conversation object for the client side. + * See doc/dbus-sasl-profile.txt for full details on what + * this object does. + * + * @returns the new object or #NULL if no memory + */ +DBusAuth* +_dbus_auth_client_new (void) +{ + DBusAuth *auth; + DBusString guid_str; + + if (!_dbus_string_init (&guid_str)) + return NULL; + + auth = _dbus_auth_new (sizeof (DBusAuthClient)); + if (auth == NULL) + { + _dbus_string_free (&guid_str); + return NULL; + } + + DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str; + + auth->side = auth_side_client; + auth->state = &client_state_need_send_auth; + + /* Start the auth conversation by sending AUTH for our default + * mechanism */ + if (!send_auth (auth, &all_mechanisms[0])) + { + _dbus_auth_unref (auth); + return NULL; + } + + return auth; +} + +/** + * Increments the refcount of an auth object. + * + * @param auth the auth conversation + * @returns the auth conversation + */ +DBusAuth * +_dbus_auth_ref (DBusAuth *auth) +{ + _dbus_assert (auth != NULL); + + auth->refcount += 1; + + return auth; +} + +/** + * Decrements the refcount of an auth object. + * + * @param auth the auth conversation + */ +void +_dbus_auth_unref (DBusAuth *auth) +{ + _dbus_assert (auth != NULL); + _dbus_assert (auth->refcount > 0); + + auth->refcount -= 1; + if (auth->refcount == 0) + { + shutdown_mech (auth); + + if (DBUS_AUTH_IS_CLIENT (auth)) + { + _dbus_string_free (& DBUS_AUTH_CLIENT (auth)->guid_from_server); + _dbus_list_clear (& DBUS_AUTH_CLIENT (auth)->mechs_to_try); + } + else + { + _dbus_assert (DBUS_AUTH_IS_SERVER (auth)); + + _dbus_string_free (& DBUS_AUTH_SERVER (auth)->guid); + } + + if (auth->keyring) + _dbus_keyring_unref (auth->keyring); + + _dbus_string_free (&auth->context); + _dbus_string_free (&auth->challenge); + _dbus_string_free (&auth->identity); + _dbus_string_free (&auth->incoming); + _dbus_string_free (&auth->outgoing); + + dbus_free_string_array (auth->allowed_mechs); + + _dbus_credentials_unref (auth->credentials); + _dbus_credentials_unref (auth->authorized_identity); + _dbus_credentials_unref (auth->desired_identity); + + dbus_free (auth); + } +} + +/** + * Sets an array of authentication mechanism names + * that we are willing to use. + * + * @param auth the auth conversation + * @param mechanisms #NULL-terminated array of mechanism names + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_auth_set_mechanisms (DBusAuth *auth, + const char **mechanisms) +{ + char **copy; + + if (mechanisms != NULL) + { + copy = _dbus_dup_string_array (mechanisms); + if (copy == NULL) + return FALSE; + } + else + copy = NULL; + + dbus_free_string_array (auth->allowed_mechs); + + auth->allowed_mechs = copy; + + return TRUE; +} + +/** + * @param auth the auth conversation object + * @returns #TRUE if we're in a final state + */ +#define DBUS_AUTH_IN_END_STATE(auth) ((auth)->state->handler == NULL) + +/** + * Analyzes buffered input and moves the auth conversation forward, + * returning the new state of the auth conversation. + * + * @param auth the auth conversation + * @returns the new state + */ +DBusAuthState +_dbus_auth_do_work (DBusAuth *auth) +{ + auth->needed_memory = FALSE; + + /* Max amount we'll buffer up before deciding someone's on crack */ +#define MAX_BUFFER (16 * _DBUS_ONE_KILOBYTE) + + do + { + if (DBUS_AUTH_IN_END_STATE (auth)) + break; + + if (_dbus_string_get_length (&auth->incoming) > MAX_BUFFER || + _dbus_string_get_length (&auth->outgoing) > MAX_BUFFER) + { + goto_state (auth, &common_state_need_disconnect); + _dbus_verbose ("%s: Disconnecting due to excessive data buffered in auth phase\n", + DBUS_AUTH_NAME (auth)); + break; + } + } + while (process_command (auth)); + + if (auth->needed_memory) + return DBUS_AUTH_STATE_WAITING_FOR_MEMORY; + else if (_dbus_string_get_length (&auth->outgoing) > 0) + return DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND; + else if (auth->state == &common_state_need_disconnect) + return DBUS_AUTH_STATE_NEED_DISCONNECT; + else if (auth->state == &common_state_authenticated) + return DBUS_AUTH_STATE_AUTHENTICATED; + else return DBUS_AUTH_STATE_WAITING_FOR_INPUT; +} + +/** + * Gets bytes that need to be sent to the peer we're conversing with. + * After writing some bytes, _dbus_auth_bytes_sent() must be called + * to notify the auth object that they were written. + * + * @param auth the auth conversation + * @param str return location for a ref to the buffer to send + * @returns #FALSE if nothing to send + */ +dbus_bool_t +_dbus_auth_get_bytes_to_send (DBusAuth *auth, + const DBusString **str) +{ + _dbus_assert (auth != NULL); + _dbus_assert (str != NULL); + + *str = NULL; + + if (_dbus_string_get_length (&auth->outgoing) == 0) + return FALSE; + + *str = &auth->outgoing; + + return TRUE; +} + +/** + * Notifies the auth conversation object that + * the given number of bytes of the outgoing buffer + * have been written out. + * + * @param auth the auth conversation + * @param bytes_sent number of bytes written out + */ +void +_dbus_auth_bytes_sent (DBusAuth *auth, + int bytes_sent) +{ + _dbus_verbose ("%s: Sent %d bytes of: %s\n", + DBUS_AUTH_NAME (auth), + bytes_sent, + _dbus_string_get_const_data (&auth->outgoing)); + + _dbus_string_delete (&auth->outgoing, + 0, bytes_sent); +} + +/** + * Get a buffer to be used for reading bytes from the peer we're conversing + * with. Bytes should be appended to this buffer. + * + * @param auth the auth conversation + * @param buffer return location for buffer to append bytes to + */ +void +_dbus_auth_get_buffer (DBusAuth *auth, + DBusString **buffer) +{ + _dbus_assert (auth != NULL); + _dbus_assert (!auth->buffer_outstanding); + + *buffer = &auth->incoming; + + auth->buffer_outstanding = TRUE; +} + +/** + * Returns a buffer with new data read into it. + * + * @param auth the auth conversation + * @param buffer the buffer being returned + * @param bytes_read number of new bytes added + */ +void +_dbus_auth_return_buffer (DBusAuth *auth, + DBusString *buffer, + int bytes_read) +{ + _dbus_assert (buffer == &auth->incoming); + _dbus_assert (auth->buffer_outstanding); + + auth->buffer_outstanding = FALSE; +} + +/** + * Returns leftover bytes that were not used as part of the auth + * conversation. These bytes will be part of the message stream + * instead. This function may not be called until authentication has + * succeeded. + * + * @param auth the auth conversation + * @param str return location for pointer to string of unused bytes + */ +void +_dbus_auth_get_unused_bytes (DBusAuth *auth, + const DBusString **str) +{ + if (!DBUS_AUTH_IN_END_STATE (auth)) + return; + + *str = &auth->incoming; +} + + +/** + * Gets rid of unused bytes returned by _dbus_auth_get_unused_bytes() + * after we've gotten them and successfully moved them elsewhere. + * + * @param auth the auth conversation + */ +void +_dbus_auth_delete_unused_bytes (DBusAuth *auth) +{ + if (!DBUS_AUTH_IN_END_STATE (auth)) + return; + + _dbus_string_set_length (&auth->incoming, 0); +} + +/** + * Called post-authentication, indicates whether we need to encode + * the message stream with _dbus_auth_encode_data() prior to + * sending it to the peer. + * + * @param auth the auth conversation + * @returns #TRUE if we need to encode the stream + */ +dbus_bool_t +_dbus_auth_needs_encoding (DBusAuth *auth) +{ + if (auth->state != &common_state_authenticated) + return FALSE; + + if (auth->mech != NULL) + { + if (DBUS_AUTH_IS_CLIENT (auth)) + return auth->mech->client_encode_func != NULL; + else + return auth->mech->server_encode_func != NULL; + } + else + return FALSE; +} + +/** + * Called post-authentication, encodes a block of bytes for sending to + * the peer. If no encoding was negotiated, just copies the bytes + * (you can avoid this by checking _dbus_auth_needs_encoding()). + * + * @param auth the auth conversation + * @param plaintext the plain text data + * @param encoded initialized string to where encoded data is appended + * @returns #TRUE if we had enough memory and successfully encoded + */ +dbus_bool_t +_dbus_auth_encode_data (DBusAuth *auth, + const DBusString *plaintext, + DBusString *encoded) +{ + _dbus_assert (plaintext != encoded); + + if (auth->state != &common_state_authenticated) + return FALSE; + + if (_dbus_auth_needs_encoding (auth)) + { + if (DBUS_AUTH_IS_CLIENT (auth)) + return (* auth->mech->client_encode_func) (auth, plaintext, encoded); + else + return (* auth->mech->server_encode_func) (auth, plaintext, encoded); + } + else + { + return _dbus_string_copy (plaintext, 0, encoded, + _dbus_string_get_length (encoded)); + } +} + +/** + * Called post-authentication, indicates whether we need to decode + * the message stream with _dbus_auth_decode_data() after + * receiving it from the peer. + * + * @param auth the auth conversation + * @returns #TRUE if we need to encode the stream + */ +dbus_bool_t +_dbus_auth_needs_decoding (DBusAuth *auth) +{ + if (auth->state != &common_state_authenticated) + return FALSE; + + if (auth->mech != NULL) + { + if (DBUS_AUTH_IS_CLIENT (auth)) + return auth->mech->client_decode_func != NULL; + else + return auth->mech->server_decode_func != NULL; + } + else + return FALSE; +} + + +/** + * Called post-authentication, decodes a block of bytes received from + * the peer. If no encoding was negotiated, just copies the bytes (you + * can avoid this by checking _dbus_auth_needs_decoding()). + * + * @todo 1.0? We need to be able to distinguish "out of memory" error + * from "the data is hosed" error. + * + * @param auth the auth conversation + * @param encoded the encoded data + * @param plaintext initialized string where decoded data is appended + * @returns #TRUE if we had enough memory and successfully decoded + */ +dbus_bool_t +_dbus_auth_decode_data (DBusAuth *auth, + const DBusString *encoded, + DBusString *plaintext) +{ + _dbus_assert (plaintext != encoded); + + if (auth->state != &common_state_authenticated) + return FALSE; + + if (_dbus_auth_needs_decoding (auth)) + { + if (DBUS_AUTH_IS_CLIENT (auth)) + return (* auth->mech->client_decode_func) (auth, encoded, plaintext); + else + return (* auth->mech->server_decode_func) (auth, encoded, plaintext); + } + else + { + return _dbus_string_copy (encoded, 0, plaintext, + _dbus_string_get_length (plaintext)); + } +} + +/** + * Sets credentials received via reliable means from the operating + * system. + * + * @param auth the auth conversation + * @param credentials the credentials received + * @returns #FALSE on OOM + */ +dbus_bool_t +_dbus_auth_set_credentials (DBusAuth *auth, + DBusCredentials *credentials) +{ + _dbus_credentials_clear (auth->credentials); + return _dbus_credentials_add_credentials (auth->credentials, + credentials); +} + +/** + * Gets the identity we authorized the client as. Apps may have + * different policies as to what identities they allow. + * + * Returned credentials are not a copy and should not be modified + * + * @param auth the auth conversation + * @returns the credentials we've authorized BY REFERENCE do not modify + */ +DBusCredentials* +_dbus_auth_get_identity (DBusAuth *auth) +{ + if (auth->state == &common_state_authenticated) + { + return auth->authorized_identity; + } + else + { + /* FIXME instead of this, keep an empty credential around that + * doesn't require allocation or something + */ + /* return empty credentials */ + _dbus_assert (_dbus_credentials_are_empty (auth->authorized_identity)); + return auth->authorized_identity; + } +} + +/** + * Gets the GUID from the server if we've authenticated; gets + * #NULL otherwise. + * @param auth the auth object + * @returns the GUID in ASCII hex format + */ +const char* +_dbus_auth_get_guid_from_server (DBusAuth *auth) +{ + _dbus_assert (DBUS_AUTH_IS_CLIENT (auth)); + + if (auth->state == &common_state_authenticated) + return _dbus_string_get_const_data (& DBUS_AUTH_CLIENT (auth)->guid_from_server); + else + return NULL; +} + +/** + * Sets the "authentication context" which scopes cookies + * with the DBUS_COOKIE_SHA1 auth mechanism for example. + * + * @param auth the auth conversation + * @param context the context + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_auth_set_context (DBusAuth *auth, + const DBusString *context) +{ + return _dbus_string_replace_len (context, 0, _dbus_string_get_length (context), + &auth->context, 0, _dbus_string_get_length (context)); +} + +/** @} */ + +/* tests in dbus-auth-util.c */ diff --git a/dbus/dbus-auth.h b/dbus/dbus-auth.h new file mode 100644 index 00000000..92150ad6 --- /dev/null +++ b/dbus/dbus-auth.h @@ -0,0 +1,81 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-auth.h Authentication + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_AUTH_H +#define DBUS_AUTH_H + +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +typedef struct DBusAuth DBusAuth; + +typedef enum +{ + DBUS_AUTH_STATE_WAITING_FOR_INPUT, + DBUS_AUTH_STATE_WAITING_FOR_MEMORY, + DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND, + DBUS_AUTH_STATE_NEED_DISCONNECT, + DBUS_AUTH_STATE_AUTHENTICATED +} DBusAuthState; + +DBusAuth* _dbus_auth_server_new (const DBusString *guid); +DBusAuth* _dbus_auth_client_new (void); +DBusAuth* _dbus_auth_ref (DBusAuth *auth); +void _dbus_auth_unref (DBusAuth *auth); +dbus_bool_t _dbus_auth_set_mechanisms (DBusAuth *auth, + const char **mechanisms); +DBusAuthState _dbus_auth_do_work (DBusAuth *auth); +dbus_bool_t _dbus_auth_get_bytes_to_send (DBusAuth *auth, + const DBusString **str); +void _dbus_auth_bytes_sent (DBusAuth *auth, + int bytes_sent); +void _dbus_auth_get_buffer (DBusAuth *auth, + DBusString **buffer); +void _dbus_auth_return_buffer (DBusAuth *auth, + DBusString *buffer, + int bytes_read); +void _dbus_auth_get_unused_bytes (DBusAuth *auth, + const DBusString **str); +void _dbus_auth_delete_unused_bytes (DBusAuth *auth); +dbus_bool_t _dbus_auth_needs_encoding (DBusAuth *auth); +dbus_bool_t _dbus_auth_encode_data (DBusAuth *auth, + const DBusString *plaintext, + DBusString *encoded); +dbus_bool_t _dbus_auth_needs_decoding (DBusAuth *auth); +dbus_bool_t _dbus_auth_decode_data (DBusAuth *auth, + const DBusString *encoded, + DBusString *plaintext); +dbus_bool_t _dbus_auth_set_credentials (DBusAuth *auth, + DBusCredentials *credentials); +DBusCredentials* _dbus_auth_get_identity (DBusAuth *auth); +dbus_bool_t _dbus_auth_set_context (DBusAuth *auth, + const DBusString *context); +const char* _dbus_auth_get_guid_from_server(DBusAuth *auth); + + +DBUS_END_DECLS + +#endif /* DBUS_AUTH_H */ diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c new file mode 100644 index 00000000..92ec20ed --- /dev/null +++ b/dbus/dbus-bus.c @@ -0,0 +1,1587 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-bus.c Convenience functions for communicating with the bus. + * + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include "dbus-bus.h" +#include "dbus-protocol.h" +#include "dbus-internals.h" +#include "dbus-message.h" +#include "dbus-marshal-validate.h" +#include "dbus-threads-internal.h" +#include "dbus-connection-internal.h" +#include "dbus-string.h" + +/** + * @defgroup DBusBus Message bus APIs + * @ingroup DBus + * @brief Functions for communicating with the message bus + * + * dbus_bus_get() allows all modules and libraries in a given + * process to share the same connection to the bus daemon by storing + * the connection globally. + * + * All other functions in this module are just convenience functions; + * most of them invoke methods on the bus daemon, by sending method + * call messages to #DBUS_SERVICE_DBUS. These convenience functions + * often make blocking method calls. If you don't want to block, + * you can send the method call messages manually in the same way + * you would any other method call message. + * + * This module is the only one in libdbus that's specific to + * communicating with the message bus daemon. The rest of the API can + * also be used for connecting to another application directly. + * + * @todo right now the default address of the system bus is hardcoded, + * so if you change it in the global config file suddenly you have to + * set DBUS_SYSTEM_BUS_ADDRESS env variable. Might be nice if the + * client lib somehow read the config file, or if the bus on startup + * somehow wrote out its address to a well-known spot, but might also + * not be worth it. + */ + +/** + * @defgroup DBusBusInternals Message bus APIs internals + * @ingroup DBusInternals + * @brief Internals of functions for communicating with the message bus + * + * @{ + */ + +/** + * Block of message-bus-related data we attach to each + * #DBusConnection used with these convenience functions. + * + */ +typedef struct +{ + DBusConnection *connection; /**< Connection we're associated with */ + char *unique_name; /**< Unique name of this connection */ + + unsigned int is_well_known : 1; /**< Is one of the well-known connections in our global array */ +} BusData; + +/** The slot we have reserved to store BusData. + */ +static dbus_int32_t bus_data_slot = -1; + +/** Number of bus types */ +#define N_BUS_TYPES 3 + +static DBusConnection *bus_connections[N_BUS_TYPES]; +static char *bus_connection_addresses[N_BUS_TYPES] = { NULL, NULL, NULL }; + +static DBusBusType activation_bus_type = DBUS_BUS_STARTER; + +static dbus_bool_t initialized = FALSE; + +/** + * Lock for globals in this file + */ +_DBUS_DEFINE_GLOBAL_LOCK (bus); + +/** + * Global lock covering all BusData on any connection. The bet is + * that some lock contention is better than more memory + * for a per-connection lock, but it's tough to imagine it mattering + * either way. + */ +_DBUS_DEFINE_GLOBAL_LOCK (bus_datas); + +static void +addresses_shutdown_func (void *data) +{ + int i; + + i = 0; + while (i < N_BUS_TYPES) + { + if (bus_connections[i] != NULL) + _dbus_warn_check_failed ("dbus_shutdown() called but connections were still live. This probably means the application did not drop all its references to bus connections.\n"); + + dbus_free (bus_connection_addresses[i]); + bus_connection_addresses[i] = NULL; + ++i; + } + + activation_bus_type = DBUS_BUS_STARTER; + + initialized = FALSE; +} + +static dbus_bool_t +get_from_env (char **connection_p, + const char *env_var) +{ + const char *s; + + _dbus_assert (*connection_p == NULL); + + s = _dbus_getenv (env_var); + if (s == NULL || *s == '\0') + return TRUE; /* successfully didn't use the env var */ + else + { + *connection_p = _dbus_strdup (s); + return *connection_p != NULL; + } +} + +static dbus_bool_t +init_session_address (void) +{ + dbus_bool_t retval; + + retval = FALSE; + + /* First, look in the environment. This is the normal case on + * freedesktop.org/Unix systems. */ + get_from_env (&bus_connection_addresses[DBUS_BUS_SESSION], + "DBUS_SESSION_BUS_ADDRESS"); + if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) + { + dbus_bool_t supported; + DBusString addr; + DBusError error = DBUS_ERROR_INIT; + + if (!_dbus_string_init (&addr)) + return FALSE; + + supported = FALSE; + /* So it's not in the environment - let's try a platform-specific method. + * On MacOS, this involves asking launchd. On Windows (not specified yet) + * we might do a COM lookup. + * Ignore errors - if we failed, fall back to autolaunch. */ + retval = _dbus_lookup_session_address (&supported, &addr, &error); + if (supported && retval) + { + retval =_dbus_string_steal_data (&addr, &bus_connection_addresses[DBUS_BUS_SESSION]); + } + else if (supported && !retval) + { + if (dbus_error_is_set(&error)) + _dbus_warn ("Dynamic session lookup supported but failed: %s\n", error.message); + else + _dbus_warn ("Dynamic session lookup supported but failed silently\n"); + } + _dbus_string_free (&addr); + } + else + retval = TRUE; + + if (!retval) + return FALSE; + + /* The DBUS_SESSION_BUS_DEFAULT_ADDRESS should have really been named + * DBUS_SESSION_BUS_FALLBACK_ADDRESS. + */ + if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) + bus_connection_addresses[DBUS_BUS_SESSION] = + _dbus_strdup (DBUS_SESSION_BUS_DEFAULT_ADDRESS); + if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) + return FALSE; + + return TRUE; +} + +static dbus_bool_t +init_connections_unlocked (void) +{ + if (!initialized) + { + const char *s; + int i; + + i = 0; + while (i < N_BUS_TYPES) + { + bus_connections[i] = NULL; + ++i; + } + + /* Don't init these twice, we may run this code twice if + * init_connections_unlocked() fails midway through. + * In practice, each block below should contain only one + * "return FALSE" or running through twice may not + * work right. + */ + + if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL) + { + _dbus_verbose ("Filling in system bus address...\n"); + + if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SYSTEM], + "DBUS_SYSTEM_BUS_ADDRESS")) + return FALSE; + } + + + if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL) + { + /* Use default system bus address if none set in environment */ + bus_connection_addresses[DBUS_BUS_SYSTEM] = + _dbus_strdup (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS); + + if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL) + return FALSE; + + _dbus_verbose (" used default system bus \"%s\"\n", + bus_connection_addresses[DBUS_BUS_SYSTEM]); + } + else + _dbus_verbose (" used env var system bus \"%s\"\n", + bus_connection_addresses[DBUS_BUS_SYSTEM]); + + if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL) + { + _dbus_verbose ("Filling in session bus address...\n"); + + if (!init_session_address ()) + return FALSE; + + _dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_SESSION] ? + bus_connection_addresses[DBUS_BUS_SESSION] : "none set"); + } + + if (bus_connection_addresses[DBUS_BUS_STARTER] == NULL) + { + _dbus_verbose ("Filling in activation bus address...\n"); + + if (!get_from_env (&bus_connection_addresses[DBUS_BUS_STARTER], + "DBUS_STARTER_ADDRESS")) + return FALSE; + + _dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_STARTER] ? + bus_connection_addresses[DBUS_BUS_STARTER] : "none set"); + } + + + if (bus_connection_addresses[DBUS_BUS_STARTER] != NULL) + { + s = _dbus_getenv ("DBUS_STARTER_BUS_TYPE"); + + if (s != NULL) + { + _dbus_verbose ("Bus activation type was set to \"%s\"\n", s); + + if (strcmp (s, "system") == 0) + activation_bus_type = DBUS_BUS_SYSTEM; + else if (strcmp (s, "session") == 0) + activation_bus_type = DBUS_BUS_SESSION; + } + } + else + { + /* Default to the session bus instead if available */ + if (bus_connection_addresses[DBUS_BUS_SESSION] != NULL) + { + bus_connection_addresses[DBUS_BUS_STARTER] = + _dbus_strdup (bus_connection_addresses[DBUS_BUS_SESSION]); + if (bus_connection_addresses[DBUS_BUS_STARTER] == NULL) + return FALSE; + } + } + + /* If we return FALSE we have to be sure that restarting + * the above code will work right + */ + + if (!_dbus_setenv ("DBUS_ACTIVATION_ADDRESS", NULL)) + return FALSE; + + if (!_dbus_setenv ("DBUS_ACTIVATION_BUS_TYPE", NULL)) + return FALSE; + + if (!_dbus_register_shutdown_func (addresses_shutdown_func, + NULL)) + return FALSE; + + initialized = TRUE; + } + + return initialized; +} + +static void +bus_data_free (void *data) +{ + BusData *bd = data; + + if (bd->is_well_known) + { + int i; + _DBUS_LOCK (bus); + /* We may be stored in more than one slot */ + /* This should now be impossible - these slots are supposed to + * be cleared on disconnect, so should not need to be cleared on + * finalize + */ + i = 0; + while (i < N_BUS_TYPES) + { + if (bus_connections[i] == bd->connection) + bus_connections[i] = NULL; + + ++i; + } + _DBUS_UNLOCK (bus); + } + + dbus_free (bd->unique_name); + dbus_free (bd); + + dbus_connection_free_data_slot (&bus_data_slot); +} + +static BusData* +ensure_bus_data (DBusConnection *connection) +{ + BusData *bd; + + if (!dbus_connection_allocate_data_slot (&bus_data_slot)) + return NULL; + + bd = dbus_connection_get_data (connection, bus_data_slot); + if (bd == NULL) + { + bd = dbus_new0 (BusData, 1); + if (bd == NULL) + { + dbus_connection_free_data_slot (&bus_data_slot); + return NULL; + } + + bd->connection = connection; + + if (!dbus_connection_set_data (connection, bus_data_slot, bd, + bus_data_free)) + { + dbus_free (bd); + dbus_connection_free_data_slot (&bus_data_slot); + return NULL; + } + + /* Data slot refcount now held by the BusData */ + } + else + { + dbus_connection_free_data_slot (&bus_data_slot); + } + + return bd; +} + +/** + * Internal function that checks to see if this + * is a shared connection owned by the bus and if it is unref it. + * + * @param connection a connection that has been disconnected. + */ +void +_dbus_bus_notify_shared_connection_disconnected_unlocked (DBusConnection *connection) +{ + int i; + + _DBUS_LOCK (bus); + + /* We are expecting to have the connection saved in only one of these + * slots, but someone could in a pathological case set system and session + * bus to the same bus or something. Or set one of them to the starter + * bus without setting the starter bus type in the env variable. + * So we don't break the loop as soon as we find a match. + */ + for (i = 0; i < N_BUS_TYPES; ++i) + { + if (bus_connections[i] == connection) + { + bus_connections[i] = NULL; + } + } + + _DBUS_UNLOCK (bus); +} + +static DBusConnection * +internal_bus_get (DBusBusType type, + dbus_bool_t private, + DBusError *error) +{ + const char *address; + DBusConnection *connection; + BusData *bd; + DBusBusType address_type; + + _dbus_return_val_if_fail (type >= 0 && type < N_BUS_TYPES, NULL); + _dbus_return_val_if_error_is_set (error, NULL); + + _DBUS_LOCK (bus); + + if (!init_connections_unlocked ()) + { + _DBUS_UNLOCK (bus); + _DBUS_SET_OOM (error); + return NULL; + } + + /* We want to use the activation address even if the + * activating bus is the session or system bus, + * per the spec. + */ + address_type = type; + + /* Use the real type of the activation bus for getting its + * connection, but only if the real type's address is available. (If + * the activating bus isn't a well-known bus then + * activation_bus_type == DBUS_BUS_STARTER) + */ + if (type == DBUS_BUS_STARTER && + bus_connection_addresses[activation_bus_type] != NULL) + type = activation_bus_type; + + if (!private && bus_connections[type] != NULL) + { + connection = bus_connections[type]; + dbus_connection_ref (connection); + + _DBUS_UNLOCK (bus); + return connection; + } + + address = bus_connection_addresses[address_type]; + if (address == NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Unable to determine the address of the message bus (try 'man dbus-launch' and 'man dbus-daemon' for help)"); + _DBUS_UNLOCK (bus); + return NULL; + } + + if (private) + connection = dbus_connection_open_private (address, error); + else + connection = dbus_connection_open (address, error); + + if (!connection) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _DBUS_UNLOCK (bus); + return NULL; + } + + if (!dbus_bus_register (connection, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_connection_close_possibly_shared (connection); + dbus_connection_unref (connection); + + _DBUS_UNLOCK (bus); + return NULL; + } + + if (!private) + { + /* store a weak ref to the connection (dbus-connection.c is + * supposed to have a strong ref that it drops on disconnect, + * since this is a shared connection) + */ + bus_connections[type] = connection; + } + + /* By default we're bound to the lifecycle of + * the message bus. + */ + dbus_connection_set_exit_on_disconnect (connection, + TRUE); + + _DBUS_LOCK (bus_datas); + bd = ensure_bus_data (connection); + _dbus_assert (bd != NULL); /* it should have been created on + register, so OOM not possible */ + bd->is_well_known = TRUE; + _DBUS_UNLOCK (bus_datas); + + + _DBUS_UNLOCK (bus); + + /* Return a reference to the caller */ + return connection; +} + + +/** @} */ /* end of implementation details docs */ + +/** + * @addtogroup DBusBus + * @{ + */ + +/** + * Connects to a bus daemon and registers the client with it. If a + * connection to the bus already exists, then that connection is + * returned. The caller of this function owns a reference to the bus. + * + * The caller may NOT call dbus_connection_close() on this connection; + * see dbus_connection_open() and dbus_connection_close() for details + * on that. + * + * If this function obtains a new connection object never before + * returned from dbus_bus_get(), it will call + * dbus_connection_set_exit_on_disconnect(), so the application + * will exit if the connection closes. You can undo this + * by calling dbus_connection_set_exit_on_disconnect() yourself + * after you get the connection. + * + * dbus_bus_get() calls dbus_bus_register() for you. + * + * If returning a newly-created connection, this function will block + * until authentication and bus registration are complete. + * + * @param type bus type + * @param error address where an error can be returned. + * @returns a #DBusConnection with new ref + */ +DBusConnection * +dbus_bus_get (DBusBusType type, + DBusError *error) +{ + return internal_bus_get (type, FALSE, error); +} + +/** + * Connects to a bus daemon and registers the client with it as with + * dbus_bus_register(). Unlike dbus_bus_get(), always creates a new + * connection. This connection will not be saved or recycled by + * libdbus. Caller owns a reference to the bus and must either close + * it or know it to be closed prior to releasing this reference. + * + * See dbus_connection_open_private() for more details on when to + * close and unref this connection. + * + * This function calls + * dbus_connection_set_exit_on_disconnect() on the new connection, so the application + * will exit if the connection closes. You can undo this + * by calling dbus_connection_set_exit_on_disconnect() yourself + * after you get the connection. + * + * dbus_bus_get_private() calls dbus_bus_register() for you. + * + * This function will block until authentication and bus registration + * are complete. + * + * @param type bus type + * @param error address where an error can be returned. + * @returns a DBusConnection with new ref + */ +DBusConnection * +dbus_bus_get_private (DBusBusType type, + DBusError *error) +{ + return internal_bus_get (type, TRUE, error); +} + +/** + * Registers a connection with the bus. This must be the first + * thing an application does when connecting to the message bus. + * If registration succeeds, the unique name will be set, + * and can be obtained using dbus_bus_get_unique_name(). + * + * This function will block until registration is complete. + * + * If the connection has already registered with the bus + * (determined by checking whether dbus_bus_get_unique_name() + * returns a non-#NULL value), then this function does nothing. + * + * If you use dbus_bus_get() or dbus_bus_get_private() this + * function will be called for you. + * + * @note Just use dbus_bus_get() or dbus_bus_get_private() instead of + * dbus_bus_register() and save yourself some pain. Using + * dbus_bus_register() manually is only useful if you have your + * own custom message bus not found in #DBusBusType. + * + * If you open a bus connection with dbus_connection_open() or + * dbus_connection_open_private() you will have to dbus_bus_register() + * yourself, or make the appropriate registration method calls + * yourself. If you send the method calls yourself, call + * dbus_bus_set_unique_name() with the unique bus name you get from + * the bus. + * + * For shared connections (created with dbus_connection_open()) in a + * multithreaded application, you can't really make the registration + * calls yourself, because you don't know whether some other thread is + * also registering, and the bus will kick you off if you send two + * registration messages. + * + * If you use dbus_bus_register() however, there is a lock that + * keeps both apps from registering at the same time. + * + * The rule in a multithreaded app, then, is that dbus_bus_register() + * must be used to register, or you need to have your own locks that + * all threads in the app will respect. + * + * In a single-threaded application you can register by hand instead + * of using dbus_bus_register(), as long as you check + * dbus_bus_get_unique_name() to see if a unique name has already been + * stored by another thread before you send the registration messages. + * + * @param connection the connection + * @param error place to store errors + * @returns #TRUE on success + */ +dbus_bool_t +dbus_bus_register (DBusConnection *connection, + DBusError *error) +{ + DBusMessage *message, *reply; + char *name; + BusData *bd; + dbus_bool_t retval; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_error_is_set (error, FALSE); + + retval = FALSE; + + _DBUS_LOCK (bus_datas); + + bd = ensure_bus_data (connection); + if (bd == NULL) + { + _DBUS_SET_OOM (error); + _DBUS_UNLOCK (bus_datas); + return FALSE; + } + + if (bd->unique_name != NULL) + { + _dbus_verbose ("Ignoring attempt to register the same DBusConnection %s with the message bus a second time.\n", + bd->unique_name); + _DBUS_UNLOCK (bus_datas); + + /* Success! */ + return TRUE; + } + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "Hello"); + + if (!message) + { + _DBUS_SET_OOM (error); + + _DBUS_UNLOCK (bus_datas); + return FALSE; + } + + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); + + dbus_message_unref (message); + + if (reply == NULL) + goto out; + else if (dbus_set_error_from_message (error, reply)) + goto out; + else if (!dbus_message_get_args (reply, error, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) + goto out; + + bd->unique_name = _dbus_strdup (name); + if (bd->unique_name == NULL) + { + _DBUS_SET_OOM (error); + goto out; + } + + retval = TRUE; + + out: + if (reply) + dbus_message_unref (reply); + + if (!retval) + _DBUS_ASSERT_ERROR_IS_SET (error); + + _DBUS_UNLOCK (bus_datas); + + return retval; +} + + +/** + * Sets the unique name of the connection, as assigned by the message + * bus. Can only be used if you registered with the bus manually + * (i.e. if you did not call dbus_bus_register()). Can only be called + * once per connection. After the unique name is set, you can get it + * with dbus_bus_get_unique_name(). + * + * The only reason to use this function is to re-implement the + * equivalent of dbus_bus_register() yourself. One (probably unusual) + * reason to do that might be to do the bus registration call + * asynchronously instead of synchronously. + * + * @note Just use dbus_bus_get() or dbus_bus_get_private(), or worst + * case dbus_bus_register(), instead of messing with this + * function. There's really no point creating pain for yourself by + * doing things manually. + * + * It's hard to use this function safely on shared connections + * (created by dbus_connection_open()) in a multithreaded application, + * because only one registration attempt can be sent to the bus. If + * two threads are both sending the registration message, there is no + * mechanism in libdbus itself to avoid sending it twice. + * + * Thus, you need a way to coordinate which thread sends the + * registration attempt; which also means you know which thread + * will call dbus_bus_set_unique_name(). If you don't know + * about all threads in the app (for example, if some libraries + * you're using might start libdbus-using threads), then you + * need to avoid using this function on shared connections. + * + * @param connection the connection + * @param unique_name the unique name + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_bus_set_unique_name (DBusConnection *connection, + const char *unique_name) +{ + BusData *bd; + dbus_bool_t success; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (unique_name != NULL, FALSE); + + _DBUS_LOCK (bus_datas); + + bd = ensure_bus_data (connection); + if (bd == NULL) + return FALSE; + + _dbus_assert (bd->unique_name == NULL); + + bd->unique_name = _dbus_strdup (unique_name); + success = bd->unique_name != NULL; + + _DBUS_UNLOCK (bus_datas); + + return success; +} + +/** + * Gets the unique name of the connection as assigned by the message + * bus. Only possible after the connection has been registered with + * the message bus. All connections returned by dbus_bus_get() or + * dbus_bus_get_private() have been successfully registered. + * + * The name remains valid until the connection is freed, and + * should not be freed by the caller. + * + * Other than dbus_bus_get(), there are two ways to set the unique + * name; one is dbus_bus_register(), the other is + * dbus_bus_set_unique_name(). You are responsible for calling + * dbus_bus_set_unique_name() if you register by hand instead of using + * dbus_bus_register(). + * + * @param connection the connection + * @returns the unique name or #NULL on error + */ +const char* +dbus_bus_get_unique_name (DBusConnection *connection) +{ + BusData *bd; + const char *unique_name; + + _dbus_return_val_if_fail (connection != NULL, NULL); + + _DBUS_LOCK (bus_datas); + + bd = ensure_bus_data (connection); + if (bd == NULL) + return NULL; + + unique_name = bd->unique_name; + + _DBUS_UNLOCK (bus_datas); + + return unique_name; +} + +/** + * Asks the bus to return the UID the named connection authenticated + * as, if any. Only works on UNIX; only works for connections on the + * same machine as the bus. If you are not on the same machine as the + * bus, then calling this is probably a bad idea, since the UID will + * mean little to your application. + * + * For the system message bus you're guaranteed to be on the same + * machine since it only listens on a UNIX domain socket (at least, + * as shipped by default). + * + * This function only works for connections that authenticated as + * a UNIX user, right now that includes all bus connections, but + * it's very possible to have connections with no associated UID. + * So check for errors and do something sensible if they happen. + * + * This function will always return an error on Windows. + * + * @param connection the connection + * @param name a name owned by the connection + * @param error location to store the error + * @returns the unix user id, or ((unsigned)-1) if error is set + */ +unsigned long +dbus_bus_get_unix_user (DBusConnection *connection, + const char *name, + DBusError *error) +{ + DBusMessage *message, *reply; + dbus_uint32_t uid; + + _dbus_return_val_if_fail (connection != NULL, DBUS_UID_UNSET); + _dbus_return_val_if_fail (name != NULL, DBUS_UID_UNSET); + _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), DBUS_UID_UNSET); + _dbus_return_val_if_error_is_set (error, DBUS_UID_UNSET); + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetConnectionUnixUser"); + + if (message == NULL) + { + _DBUS_SET_OOM (error); + return DBUS_UID_UNSET; + } + + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + _DBUS_SET_OOM (error); + return DBUS_UID_UNSET; + } + + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, + error); + + dbus_message_unref (message); + + if (reply == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return DBUS_UID_UNSET; + } + + if (dbus_set_error_from_message (error, reply)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_message_unref (reply); + return DBUS_UID_UNSET; + } + + if (!dbus_message_get_args (reply, error, + DBUS_TYPE_UINT32, &uid, + DBUS_TYPE_INVALID)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_message_unref (reply); + return DBUS_UID_UNSET; + } + + dbus_message_unref (reply); + + return (unsigned long) uid; +} + +/** + * Asks the bus to return its globally unique ID, as described in the + * D-Bus specification. For the session bus, this is useful as a way + * to uniquely identify each user session. For the system bus, + * probably the bus ID is not useful; instead, use the machine ID + * since it's accessible without necessarily connecting to the bus and + * may be persistent beyond a single bus instance (across reboots for + * example). See dbus_get_local_machine_id(). + * + * In addition to an ID for each bus and an ID for each machine, there is + * an ID for each address that the bus is listening on; that can + * be retrieved with dbus_connection_get_server_id(), though it is + * probably not very useful. + * + * @param connection the connection + * @param error location to store the error + * @returns the bus ID or #NULL if error is set + */ +char* +dbus_bus_get_id (DBusConnection *connection, + DBusError *error) +{ + DBusMessage *message, *reply; + char *id; + const char *v_STRING; + + _dbus_return_val_if_fail (connection != NULL, NULL); + _dbus_return_val_if_error_is_set (error, NULL); + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetId"); + + if (message == NULL) + { + _DBUS_SET_OOM (error); + return NULL; + } + + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, + error); + + dbus_message_unref (message); + + if (reply == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return NULL; + } + + if (dbus_set_error_from_message (error, reply)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_message_unref (reply); + return NULL; + } + + v_STRING = NULL; + if (!dbus_message_get_args (reply, error, + DBUS_TYPE_STRING, &v_STRING, + DBUS_TYPE_INVALID)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_message_unref (reply); + return NULL; + } + + id = _dbus_strdup (v_STRING); /* may be NULL */ + + dbus_message_unref (reply); + + if (id == NULL) + _DBUS_SET_OOM (error); + + /* FIXME it might be nice to cache the ID locally */ + + return id; +} + +/** + * Asks the bus to assign the given name to this connection by invoking + * the RequestName method on the bus. This method is fully documented + * in the D-Bus specification. For quick reference, the flags and + * result codes are discussed here, but the specification is the + * canonical version of this information. + * + * First you should know that for each bus name, the bus stores + * a queue of connections that would like to own it. Only + * one owns it at a time - called the primary owner. If the primary + * owner releases the name or disconnects, then the next owner in the + * queue atomically takes over. + * + * So for example if you have an application org.freedesktop.TextEditor + * and multiple instances of it can be run, you can have all of them + * sitting in the queue. The first one to start up will receive messages + * sent to org.freedesktop.TextEditor, but if that one exits another + * will become the primary owner and receive messages. + * + * The queue means you don't need to manually watch for the current owner to + * disappear and then request the name again. + * + * When requesting a name, you can specify several flags. + * + * #DBUS_NAME_FLAG_ALLOW_REPLACEMENT and #DBUS_NAME_FLAG_DO_NOT_QUEUE + * are properties stored by the bus for this connection with respect to + * each requested bus name. These properties are stored even if the + * connection is queued and does not become the primary owner. + * You can update these flags by calling RequestName again (even if + * you already own the name). + * + * #DBUS_NAME_FLAG_ALLOW_REPLACEMENT means that another requestor of the + * name can take it away from you by specifying #DBUS_NAME_FLAG_REPLACE_EXISTING. + * + * #DBUS_NAME_FLAG_DO_NOT_QUEUE means that if you aren't the primary owner, + * you don't want to be queued up - you only care about being the + * primary owner. + * + * Unlike the other two flags, #DBUS_NAME_FLAG_REPLACE_EXISTING is a property + * of the individual RequestName call, i.e. the bus does not persistently + * associate it with the connection-name pair. If a RequestName call includes + * the #DBUS_NAME_FLAG_REPLACE_EXISTING flag, and the current primary + * owner has #DBUS_NAME_FLAG_ALLOW_REPLACEMENT set, then the current primary + * owner will be kicked off. + * + * If no flags are given, an application will receive the requested + * name only if the name is currently unowned; and it will NOT give + * up the name if another application asks to take it over using + * #DBUS_NAME_FLAG_REPLACE_EXISTING. + * + * This function returns a result code. The possible result codes + * are as follows. + * + * #DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER means that the name had no + * existing owner, and the caller is now the primary owner; or that + * the name had an owner, and the caller specified + * #DBUS_NAME_FLAG_REPLACE_EXISTING, and the current owner + * specified #DBUS_NAME_FLAG_ALLOW_REPLACEMENT. + * + * #DBUS_REQUEST_NAME_REPLY_IN_QUEUE happens only if the caller does NOT + * specify #DBUS_NAME_FLAG_DO_NOT_QUEUE and either the current owner + * did NOT specify #DBUS_NAME_FLAG_ALLOW_REPLACEMENT or the caller did NOT + * specify #DBUS_NAME_FLAG_REPLACE_EXISTING. In this case the caller ends up + * in a queue to own the name after the current owner gives it up. + * + * #DBUS_REQUEST_NAME_REPLY_EXISTS happens if the name has an owner + * already and the caller specifies #DBUS_NAME_FLAG_DO_NOT_QUEUE + * and either the current owner has NOT specified + * #DBUS_NAME_FLAG_ALLOW_REPLACEMENT or the caller did NOT specify + * #DBUS_NAME_FLAG_REPLACE_EXISTING. + * + * #DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER happens if an application + * requests a name it already owns. (Re-requesting a name is useful if + * you want to change the #DBUS_NAME_FLAG_ALLOW_REPLACEMENT or + * #DBUS_NAME_FLAG_DO_NOT_QUEUE settings.) + * + * When a service represents an application, say "text editor," then + * it should specify #DBUS_NAME_FLAG_ALLOW_REPLACEMENT if it wants + * the last editor started to be the user's editor vs. the first one + * started. Then any editor that can be the user's editor should + * specify #DBUS_NAME_FLAG_REPLACE_EXISTING to either take over + * (last-started-wins) or be queued up (first-started-wins) according + * to whether #DBUS_NAME_FLAG_ALLOW_REPLACEMENT was given. + * + * Conventionally, single-instance applications often offer a command + * line option called --replace which means to replace the current + * instance. To implement this, always set + * #DBUS_NAME_FLAG_ALLOW_REPLACEMENT when you request your + * application's bus name. When you lose ownership of your bus name, + * you need to exit. Look for the signal "NameLost" from + * #DBUS_SERVICE_DBUS and #DBUS_INTERFACE_DBUS (the signal's first + * argument is the bus name that was lost). If starting up without + * --replace, do not specify #DBUS_NAME_FLAG_REPLACE_EXISTING, and + * exit if you fail to become the bus name owner. If --replace is + * given, ask to replace the old owner. + * + * @param connection the connection + * @param name the name to request + * @param flags flags + * @param error location to store the error + * @returns a result code, -1 if error is set + */ +int +dbus_bus_request_name (DBusConnection *connection, + const char *name, + unsigned int flags, + DBusError *error) +{ + DBusMessage *message, *reply; + dbus_uint32_t result; + + _dbus_return_val_if_fail (connection != NULL, 0); + _dbus_return_val_if_fail (name != NULL, 0); + _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), 0); + _dbus_return_val_if_error_is_set (error, 0); + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "RequestName"); + + if (message == NULL) + { + _DBUS_SET_OOM (error); + return -1; + } + + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_UINT32, &flags, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + _DBUS_SET_OOM (error); + return -1; + } + + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, + error); + + dbus_message_unref (message); + + if (reply == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return -1; + } + + if (dbus_set_error_from_message (error, reply)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_message_unref (reply); + return -1; + } + + if (!dbus_message_get_args (reply, error, + DBUS_TYPE_UINT32, &result, + DBUS_TYPE_INVALID)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_message_unref (reply); + return -1; + } + + dbus_message_unref (reply); + + return result; +} + + +/** + * Asks the bus to unassign the given name from this connection by + * invoking the ReleaseName method on the bus. The "ReleaseName" + * method is canonically documented in the D-Bus specification. + * + * Possible results are: #DBUS_RELEASE_NAME_REPLY_RELEASED + * which means you owned the name or were in the queue to own it, + * and and now you don't own it and aren't in the queue. + * #DBUS_RELEASE_NAME_REPLY_NOT_OWNER which means someone else + * owns the name so you can't release it. + * #DBUS_RELEASE_NAME_REPLY_NON_EXISTENT + * which means nobody owned the name. + * + * @param connection the connection + * @param name the name to remove + * @param error location to store the error + * @returns a result code, -1 if error is set + */ +int +dbus_bus_release_name (DBusConnection *connection, + const char *name, + DBusError *error) +{ + DBusMessage *message, *reply; + dbus_uint32_t result; + + _dbus_return_val_if_fail (connection != NULL, 0); + _dbus_return_val_if_fail (name != NULL, 0); + _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), 0); + _dbus_return_val_if_error_is_set (error, 0); + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "ReleaseName"); + + if (message == NULL) + { + _DBUS_SET_OOM (error); + return -1; + } + + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + _DBUS_SET_OOM (error); + return -1; + } + + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, + error); + + dbus_message_unref (message); + + if (reply == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return -1; + } + + if (dbus_set_error_from_message (error, reply)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_message_unref (reply); + return -1; + } + + if (!dbus_message_get_args (reply, error, + DBUS_TYPE_UINT32, &result, + DBUS_TYPE_INVALID)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_message_unref (reply); + return -1; + } + + dbus_message_unref (reply); + + return result; +} + +/** + * Asks the bus whether a certain name has an owner. + * + * Using this can easily result in a race condition, + * since an owner can appear or disappear after you + * call this. + * + * If you want to request a name, just request it; + * if you want to avoid replacing a current owner, + * don't specify #DBUS_NAME_FLAG_REPLACE_EXISTING and + * you will get an error if there's already an owner. + * + * @param connection the connection + * @param name the name + * @param error location to store any errors + * @returns #TRUE if the name exists, #FALSE if not or on error + */ +dbus_bool_t +dbus_bus_name_has_owner (DBusConnection *connection, + const char *name, + DBusError *error) +{ + DBusMessage *message, *reply; + dbus_bool_t exists; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (name != NULL, FALSE); + _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), FALSE); + _dbus_return_val_if_error_is_set (error, FALSE); + + message = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "NameHasOwner"); + if (message == NULL) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + _DBUS_SET_OOM (error); + return FALSE; + } + + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error); + dbus_message_unref (message); + + if (reply == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return FALSE; + } + + if (!dbus_message_get_args (reply, error, + DBUS_TYPE_BOOLEAN, &exists, + DBUS_TYPE_INVALID)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_message_unref (reply); + return FALSE; + } + + dbus_message_unref (reply); + return exists; +} + +/** + * Starts a service that will request ownership of the given name. + * The returned result will be one of be one of + * #DBUS_START_REPLY_SUCCESS or #DBUS_START_REPLY_ALREADY_RUNNING if + * successful. Pass #NULL if you don't care about the result. + * + * The flags parameter is for future expansion, currently you should + * specify 0. + * + * It's often easier to avoid explicitly starting services, and + * just send a method call to the service's bus name instead. + * Method calls start a service to handle them by default + * unless you call dbus_message_set_auto_start() to disable this + * behavior. + * + * @param connection the connection + * @param name the name we want the new service to request + * @param flags the flags (should always be 0 for now) + * @param result a place to store the result or #NULL + * @param error location to store any errors + * @returns #TRUE if the activation succeeded, #FALSE if not + */ +dbus_bool_t +dbus_bus_start_service_by_name (DBusConnection *connection, + const char *name, + dbus_uint32_t flags, + dbus_uint32_t *result, + DBusError *error) +{ + DBusMessage *msg; + DBusMessage *reply; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (_dbus_check_is_valid_bus_name (name), FALSE); + + msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "StartServiceByName"); + + if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &name, + DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID)) + { + dbus_message_unref (msg); + _DBUS_SET_OOM (error); + return FALSE; + } + + reply = dbus_connection_send_with_reply_and_block (connection, msg, + -1, error); + dbus_message_unref (msg); + + if (reply == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return FALSE; + } + + if (dbus_set_error_from_message (error, reply)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_message_unref (reply); + return FALSE; + } + + if (result != NULL && + !dbus_message_get_args (reply, error, DBUS_TYPE_UINT32, + result, DBUS_TYPE_INVALID)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + dbus_message_unref (reply); + return FALSE; + } + + dbus_message_unref (reply); + return TRUE; +} + +static void +send_no_return_values (DBusConnection *connection, + DBusMessage *msg, + DBusError *error) +{ + if (error) + { + /* Block to check success codepath */ + DBusMessage *reply; + + reply = dbus_connection_send_with_reply_and_block (connection, msg, + -1, error); + + if (reply == NULL) + _DBUS_ASSERT_ERROR_IS_SET (error); + else + dbus_message_unref (reply); + } + else + { + /* Silently-fail nonblocking codepath */ + dbus_message_set_no_reply (msg, TRUE); + dbus_connection_send (connection, msg, NULL); + } +} + +/** + * Adds a match rule to match messages going through the message bus. + * The "rule" argument is the string form of a match rule. + * + * If you pass #NULL for the error, this function will not + * block; the match thus won't be added until you flush the + * connection, and if there's an error adding the match + * (only possible error is lack of resources in the bus), + * you won't find out about it. + * + * If you pass non-#NULL for the error this function will + * block until it gets a reply. + * + * Normal API conventions would have the function return + * a boolean value indicating whether the error was set, + * but that would require blocking always to determine + * the return value. + * + * The AddMatch method is fully documented in the D-Bus + * specification. For quick reference, the format of the + * match rules is discussed here, but the specification + * is the canonical version of this information. + * + * Rules are specified as a string of comma separated + * key/value pairs. An example is + * "type='signal',sender='org.freedesktop.DBus', + * interface='org.freedesktop.DBus',member='Foo', + * path='/bar/foo',destination=':452345.34'" + * + * Possible keys you can match on are type, sender, + * interface, member, path, destination and numbered + * keys to match message args (keys are 'arg0', 'arg1', etc.). + * Omitting a key from the rule indicates + * a wildcard match. For instance omitting + * the member from a match rule but adding a sender would + * let all messages from that sender through regardless of + * the member. + * + * Matches are inclusive not exclusive so as long as one + * rule matches the message will get through. It is important + * to note this because every time a message is received the + * application will be paged into memory to process it. This + * can cause performance problems such as draining batteries + * on embedded platforms. + * + * If you match message args ('arg0', 'arg1', and so forth) + * only string arguments will match. That is, arg0='5' means + * match the string "5" not the integer 5. + * + * Currently there is no way to match against non-string arguments. + * + * A specialised form of wildcard matching on arguments is + * supported for path-like namespaces. If your argument match has + * a 'path' suffix (eg: "arg0path='/some/path/'") then it is + * considered a match if the argument exactly matches the given + * string or if one of them ends in a '/' and is a prefix of the + * other. + * + * Matching on interface is tricky because method call + * messages only optionally specify the interface. + * If a message omits the interface, then it will NOT match + * if the rule specifies an interface name. This means match + * rules on method calls should not usually give an interface. + * + * However, signal messages are required to include the interface + * so when matching signals usually you should specify the interface + * in the match rule. + * + * For security reasons, you can match arguments only up to + * #DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER. + * + * Match rules have a maximum length of #DBUS_MAXIMUM_MATCH_RULE_LENGTH + * bytes. + * + * Both of these maximums are much higher than you're likely to need, + * they only exist because the D-Bus bus daemon has fixed limits on + * all resource usage. + * + * @param connection connection to the message bus + * @param rule textual form of match rule + * @param error location to store any errors + */ +void +dbus_bus_add_match (DBusConnection *connection, + const char *rule, + DBusError *error) +{ + DBusMessage *msg; + + _dbus_return_if_fail (rule != NULL); + + msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "AddMatch"); + + if (msg == NULL) + { + _DBUS_SET_OOM (error); + return; + } + + if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &rule, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (msg); + _DBUS_SET_OOM (error); + return; + } + + send_no_return_values (connection, msg, error); + + dbus_message_unref (msg); +} + +/** + * Removes a previously-added match rule "by value" (the most + * recently-added identical rule gets removed). The "rule" argument + * is the string form of a match rule. + * + * The bus compares match rules semantically, not textually, so + * whitespace and ordering don't have to be identical to + * the rule you passed to dbus_bus_add_match(). + * + * If you pass #NULL for the error, this function will not + * block; otherwise it will. See detailed explanation in + * docs for dbus_bus_add_match(). + * + * @param connection connection to the message bus + * @param rule textual form of match rule + * @param error location to store any errors + */ +void +dbus_bus_remove_match (DBusConnection *connection, + const char *rule, + DBusError *error) +{ + DBusMessage *msg; + + _dbus_return_if_fail (rule != NULL); + + msg = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "RemoveMatch"); + + if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, &rule, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (msg); + _DBUS_SET_OOM (error); + return; + } + + send_no_return_values (connection, msg, error); + + dbus_message_unref (msg); +} + +/** @} */ diff --git a/dbus/dbus-bus.h b/dbus/dbus-bus.h new file mode 100644 index 00000000..e36449c7 --- /dev/null +++ b/dbus/dbus-bus.h @@ -0,0 +1,82 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-bus.h Convenience functions for communicating with the bus. + * + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_BUS_H +#define DBUS_BUS_H + +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusBus + * @{ + */ + +DBusConnection *dbus_bus_get (DBusBusType type, + DBusError *error); +DBusConnection *dbus_bus_get_private (DBusBusType type, + DBusError *error); + +dbus_bool_t dbus_bus_register (DBusConnection *connection, + DBusError *error); +dbus_bool_t dbus_bus_set_unique_name (DBusConnection *connection, + const char *unique_name); +const char* dbus_bus_get_unique_name (DBusConnection *connection); +unsigned long dbus_bus_get_unix_user (DBusConnection *connection, + const char *name, + DBusError *error); +char* dbus_bus_get_id (DBusConnection *connection, + DBusError *error); +int dbus_bus_request_name (DBusConnection *connection, + const char *name, + unsigned int flags, + DBusError *error); +int dbus_bus_release_name (DBusConnection *connection, + const char *name, + DBusError *error); +dbus_bool_t dbus_bus_name_has_owner (DBusConnection *connection, + const char *name, + DBusError *error); + +dbus_bool_t dbus_bus_start_service_by_name (DBusConnection *connection, + const char *name, + dbus_uint32_t flags, + dbus_uint32_t *reply, + DBusError *error); + +void dbus_bus_add_match (DBusConnection *connection, + const char *rule, + DBusError *error); +void dbus_bus_remove_match (DBusConnection *connection, + const char *rule, + DBusError *error); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_BUS_H */ diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h new file mode 100644 index 00000000..721b5d73 --- /dev/null +++ b/dbus/dbus-connection-internal.h @@ -0,0 +1,120 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-connection-internal.h DBusConnection internal interfaces + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_CONNECTION_INTERNAL_H +#define DBUS_CONNECTION_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +typedef enum +{ + DBUS_ITERATION_DO_WRITING = 1 << 0, /**< Write messages out. */ + DBUS_ITERATION_DO_READING = 1 << 1, /**< Read messages in. */ + DBUS_ITERATION_BLOCK = 1 << 2 /**< Block if nothing to do. */ +} DBusIterationFlags; + +/** default timeout value when waiting for a message reply, 25 seconds */ +#define _DBUS_DEFAULT_TIMEOUT_VALUE (25 * 1000) + +void _dbus_connection_lock (DBusConnection *connection); +void _dbus_connection_unlock (DBusConnection *connection); +DBusConnection * _dbus_connection_ref_unlocked (DBusConnection *connection); +void _dbus_connection_unref_unlocked (DBusConnection *connection); +dbus_bool_t _dbus_connection_queue_received_message (DBusConnection *connection, + DBusMessage *message); +void _dbus_connection_queue_received_message_link (DBusConnection *connection, + DBusList *link); +dbus_bool_t _dbus_connection_has_messages_to_send_unlocked (DBusConnection *connection); +DBusMessage* _dbus_connection_get_message_to_send (DBusConnection *connection); +void _dbus_connection_message_sent (DBusConnection *connection, + DBusMessage *message); +dbus_bool_t _dbus_connection_add_watch_unlocked (DBusConnection *connection, + DBusWatch *watch); +void _dbus_connection_remove_watch_unlocked (DBusConnection *connection, + DBusWatch *watch); +void _dbus_connection_toggle_watch_unlocked (DBusConnection *connection, + DBusWatch *watch, + dbus_bool_t enabled); +dbus_bool_t _dbus_connection_handle_watch (DBusWatch *watch, + unsigned int condition, + void *data); +dbus_bool_t _dbus_connection_add_timeout_unlocked (DBusConnection *connection, + DBusTimeout *timeout); +void _dbus_connection_remove_timeout_unlocked (DBusConnection *connection, + DBusTimeout *timeout); +void _dbus_connection_toggle_timeout_unlocked (DBusConnection *connection, + DBusTimeout *timeout, + dbus_bool_t enabled); +DBusConnection* _dbus_connection_new_for_transport (DBusTransport *transport); +void _dbus_connection_do_iteration_unlocked (DBusConnection *connection, + unsigned int flags, + int timeout_milliseconds); +void _dbus_connection_close_possibly_shared (DBusConnection *connection); +void _dbus_connection_close_if_only_one_ref (DBusConnection *connection); + +DBusPendingCall* _dbus_pending_call_new (DBusConnection *connection, + int timeout_milliseconds, + DBusTimeoutHandler timeout_handler); +void _dbus_pending_call_notify (DBusPendingCall *pending); +void _dbus_connection_remove_pending_call (DBusConnection *connection, + DBusPendingCall *pending); +void _dbus_connection_block_pending_call (DBusPendingCall *pending); +void _dbus_pending_call_complete_and_unlock (DBusPendingCall *pending, + DBusMessage *message); +dbus_bool_t _dbus_connection_send_and_unlock (DBusConnection *connection, + DBusMessage *message, + dbus_uint32_t *client_serial); + +void _dbus_connection_queue_synthesized_message_link (DBusConnection *connection, + DBusList *link); +void _dbus_connection_test_get_locks (DBusConnection *conn, + DBusMutex **mutex_loc, + DBusMutex **dispatch_mutex_loc, + DBusMutex **io_path_mutex_loc, + DBusCondVar **dispatch_cond_loc, + DBusCondVar **io_path_cond_loc); + +/* This _dbus_bus_* stuff doesn't really belong here, but dbus-bus-internal.h seems + * silly for one function + */ +/** + * @addtogroup DBusBusInternals + * @{ + */ + +void _dbus_bus_notify_shared_connection_disconnected_unlocked (DBusConnection *connection); + +/** @} */ + + +DBUS_END_DECLS + +#endif /* DBUS_CONNECTION_INTERNAL_H */ diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c new file mode 100644 index 00000000..9526d3cc --- /dev/null +++ b/dbus/dbus-connection.c @@ -0,0 +1,5947 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-connection.c DBusConnection object + * + * Copyright (C) 2002-2006 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include "dbus-shared.h" +#include "dbus-connection.h" +#include "dbus-list.h" +#include "dbus-timeout.h" +#include "dbus-transport.h" +#include "dbus-watch.h" +#include "dbus-connection-internal.h" +#include "dbus-pending-call-internal.h" +#include "dbus-list.h" +#include "dbus-hash.h" +#include "dbus-message-internal.h" +#include "dbus-threads.h" +#include "dbus-protocol.h" +#include "dbus-dataslot.h" +#include "dbus-string.h" +#include "dbus-pending-call.h" +#include "dbus-object-tree.h" +#include "dbus-threads-internal.h" +#include "dbus-bus.h" + +#ifdef DBUS_DISABLE_CHECKS +#define TOOK_LOCK_CHECK(connection) +#define RELEASING_LOCK_CHECK(connection) +#define HAVE_LOCK_CHECK(connection) +#else +#define TOOK_LOCK_CHECK(connection) do { \ + _dbus_assert (!(connection)->have_connection_lock); \ + (connection)->have_connection_lock = TRUE; \ + } while (0) +#define RELEASING_LOCK_CHECK(connection) do { \ + _dbus_assert ((connection)->have_connection_lock); \ + (connection)->have_connection_lock = FALSE; \ + } while (0) +#define HAVE_LOCK_CHECK(connection) _dbus_assert ((connection)->have_connection_lock) +/* A "DO_NOT_HAVE_LOCK_CHECK" is impossible since we need the lock to check the flag */ +#endif + +#define TRACE_LOCKS 1 + +#define CONNECTION_LOCK(connection) do { \ + if (TRACE_LOCKS) { _dbus_verbose (" LOCK: %s\n", _DBUS_FUNCTION_NAME); } \ + _dbus_mutex_lock ((connection)->mutex); \ + TOOK_LOCK_CHECK (connection); \ + } while (0) + +#define CONNECTION_UNLOCK(connection) do { \ + if (TRACE_LOCKS) { _dbus_verbose (" UNLOCK: %s\n", _DBUS_FUNCTION_NAME); } \ + RELEASING_LOCK_CHECK (connection); \ + _dbus_mutex_unlock ((connection)->mutex); \ + } while (0) + +#define DISPATCH_STATUS_NAME(s) \ + ((s) == DBUS_DISPATCH_COMPLETE ? "complete" : \ + (s) == DBUS_DISPATCH_DATA_REMAINS ? "data remains" : \ + (s) == DBUS_DISPATCH_NEED_MEMORY ? "need memory" : \ + "???") + +/** + * @defgroup DBusConnection DBusConnection + * @ingroup DBus + * @brief Connection to another application + * + * A DBusConnection represents a connection to another + * application. Messages can be sent and received via this connection. + * The other application may be a message bus; for convenience, the + * function dbus_bus_get() is provided to automatically open a + * connection to the well-known message buses. + * + * In brief a DBusConnection is a message queue associated with some + * message transport mechanism such as a socket. The connection + * maintains a queue of incoming messages and a queue of outgoing + * messages. + * + * Several functions use the following terms: + *
    + *
  • read means to fill the incoming message queue by reading from the socket
  • + *
  • write means to drain the outgoing queue by writing to the socket
  • + *
  • dispatch means to drain the incoming queue by invoking application-provided message handlers
  • + *
+ * + * The function dbus_connection_read_write_dispatch() for example does all + * three of these things, offering a simple alternative to a main loop. + * + * In an application with a main loop, the read/write/dispatch + * operations are usually separate. + * + * The connection provides #DBusWatch and #DBusTimeout objects to + * the main loop. These are used to know when reading, writing, or + * dispatching should be performed. + * + * Incoming messages are processed + * by calling dbus_connection_dispatch(). dbus_connection_dispatch() + * runs any handlers registered for the topmost message in the message + * queue, then discards the message, then returns. + * + * dbus_connection_get_dispatch_status() indicates whether + * messages are currently in the queue that need dispatching. + * dbus_connection_set_dispatch_status_function() allows + * you to set a function to be used to monitor the dispatch status. + * + * If you're using GLib or Qt add-on libraries for D-Bus, there are + * special convenience APIs in those libraries that hide + * all the details of dispatch and watch/timeout monitoring. + * For example, dbus_connection_setup_with_g_main(). + * + * If you aren't using these add-on libraries, but want to process + * messages asynchronously, you must manually call + * dbus_connection_set_dispatch_status_function(), + * dbus_connection_set_watch_functions(), + * dbus_connection_set_timeout_functions() providing appropriate + * functions to integrate the connection with your application's main + * loop. This can be tricky to get right; main loops are not simple. + * + * If you don't need to be asynchronous, you can ignore #DBusWatch, + * #DBusTimeout, and dbus_connection_dispatch(). Instead, + * dbus_connection_read_write_dispatch() can be used. + * + * Or, in very simple applications, + * dbus_connection_pop_message() may be all you need, allowing you to + * avoid setting up any handler functions (see + * dbus_connection_add_filter(), + * dbus_connection_register_object_path() for more on handlers). + * + * When you use dbus_connection_send() or one of its variants to send + * a message, the message is added to the outgoing queue. It's + * actually written to the network later; either in + * dbus_watch_handle() invoked by your main loop, or in + * dbus_connection_flush() which blocks until it can write out the + * entire outgoing queue. The GLib/Qt add-on libraries again + * handle the details here for you by setting up watch functions. + * + * When a connection is disconnected, you are guaranteed to get a + * signal "Disconnected" from the interface + * #DBUS_INTERFACE_LOCAL, path + * #DBUS_PATH_LOCAL. + * + * You may not drop the last reference to a #DBusConnection + * until that connection has been disconnected. + * + * You may dispatch the unprocessed incoming message queue even if the + * connection is disconnected. However, "Disconnected" will always be + * the last message in the queue (obviously no messages are received + * after disconnection). + * + * After calling dbus_threads_init(), #DBusConnection has thread + * locks and drops them when invoking user callbacks, so in general is + * transparently threadsafe. However, #DBusMessage does NOT have + * thread locks; you must not send the same message to multiple + * #DBusConnection if those connections will be used from different threads, + * for example. + * + * Also, if you dispatch or pop messages from multiple threads, it + * may work in the sense that it won't crash, but it's tough to imagine + * sane results; it will be completely unpredictable which messages + * go to which threads. + * + * It's recommended to dispatch from a single thread. + * + * The most useful function to call from multiple threads at once + * is dbus_connection_send_with_reply_and_block(). That is, + * multiple threads can make method calls at the same time. + * + * If you aren't using threads, you can use a main loop and + * dbus_pending_call_set_notify() to achieve a similar result. + */ + +/** + * @defgroup DBusConnectionInternals DBusConnection implementation details + * @ingroup DBusInternals + * @brief Implementation details of DBusConnection + * + * @{ + */ + +/** + * Internal struct representing a message filter function + */ +typedef struct DBusMessageFilter DBusMessageFilter; + +/** + * Internal struct representing a message filter function + */ +struct DBusMessageFilter +{ + DBusAtomic refcount; /**< Reference count */ + DBusHandleMessageFunction function; /**< Function to call to filter */ + void *user_data; /**< User data for the function */ + DBusFreeFunction free_user_data_function; /**< Function to free the user data */ +}; + + +/** + * Internals of DBusPreallocatedSend + */ +struct DBusPreallocatedSend +{ + DBusConnection *connection; /**< Connection we'd send the message to */ + DBusList *queue_link; /**< Preallocated link in the queue */ + DBusList *counter_link; /**< Preallocated link in the resource counter */ +}; + +static dbus_bool_t _dbus_modify_sigpipe = TRUE; + +/** + * Implementation details of DBusConnection. All fields are private. + */ +struct DBusConnection +{ + DBusAtomic refcount; /**< Reference count. */ + + DBusMutex *mutex; /**< Lock on the entire DBusConnection */ + + DBusMutex *dispatch_mutex; /**< Protects dispatch_acquired */ + DBusCondVar *dispatch_cond; /**< Notify when dispatch_acquired is available */ + DBusMutex *io_path_mutex; /**< Protects io_path_acquired */ + DBusCondVar *io_path_cond; /**< Notify when io_path_acquired is available */ + + DBusList *outgoing_messages; /**< Queue of messages we need to send, send the end of the list first. */ + DBusList *incoming_messages; /**< Queue of messages we have received, end of the list received most recently. */ + + DBusMessage *message_borrowed; /**< Filled in if the first incoming message has been borrowed; + * dispatch_acquired will be set by the borrower + */ + + int n_outgoing; /**< Length of outgoing queue. */ + int n_incoming; /**< Length of incoming queue. */ + + DBusCounter *outgoing_counter; /**< Counts size of outgoing messages. */ + + DBusTransport *transport; /**< Object that sends/receives messages over network. */ + DBusWatchList *watches; /**< Stores active watches. */ + DBusTimeoutList *timeouts; /**< Stores active timeouts. */ + + DBusList *filter_list; /**< List of filters. */ + + DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ + + DBusHashTable *pending_replies; /**< Hash of message serials to #DBusPendingCall. */ + + dbus_uint32_t client_serial; /**< Client serial. Increments each time a message is sent */ + DBusList *disconnect_message_link; /**< Preallocated list node for queueing the disconnection message */ + + DBusWakeupMainFunction wakeup_main_function; /**< Function to wake up the mainloop */ + void *wakeup_main_data; /**< Application data for wakeup_main_function */ + DBusFreeFunction free_wakeup_main_data; /**< free wakeup_main_data */ + + DBusDispatchStatusFunction dispatch_status_function; /**< Function on dispatch status changes */ + void *dispatch_status_data; /**< Application data for dispatch_status_function */ + DBusFreeFunction free_dispatch_status_data; /**< free dispatch_status_data */ + + DBusDispatchStatus last_dispatch_status; /**< The last dispatch status we reported to the application. */ + + DBusList *link_cache; /**< A cache of linked list links to prevent contention + * for the global linked list mempool lock + */ + DBusObjectTree *objects; /**< Object path handlers registered with this connection */ + + char *server_guid; /**< GUID of server if we are in shared_connections, #NULL if server GUID is unknown or connection is private */ + + /* These two MUST be bools and not bitfields, because they are protected by a separate lock + * from connection->mutex and all bitfields in a word have to be read/written together. + * So you can't have a different lock for different bitfields in the same word. + */ + dbus_bool_t dispatch_acquired; /**< Someone has dispatch path (can drain incoming queue) */ + dbus_bool_t io_path_acquired; /**< Someone has transport io path (can use the transport to read/write messages) */ + + unsigned int shareable : 1; /**< #TRUE if libdbus owns a reference to the connection and can return it from dbus_connection_open() more than once */ + + unsigned int exit_on_disconnect : 1; /**< If #TRUE, exit after handling disconnect signal */ + + unsigned int route_peer_messages : 1; /**< If #TRUE, if org.freedesktop.DBus.Peer messages have a bus name, don't handle them automatically */ + + unsigned int disconnected_message_arrived : 1; /**< We popped or are dispatching the disconnected message. + * if the disconnect_message_link is NULL then we queued it, but + * this flag is whether it got to the head of the queue. + */ + unsigned int disconnected_message_processed : 1; /**< We did our default handling of the disconnected message, + * such as closing the connection. + */ + +#ifndef DBUS_DISABLE_CHECKS + unsigned int have_connection_lock : 1; /**< Used to check locking */ +#endif + +#ifndef DBUS_DISABLE_CHECKS + int generation; /**< _dbus_current_generation that should correspond to this connection */ +#endif +}; + +static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection); +static void _dbus_connection_update_dispatch_status_and_unlock (DBusConnection *connection, + DBusDispatchStatus new_status); +static void _dbus_connection_last_unref (DBusConnection *connection); +static void _dbus_connection_acquire_dispatch (DBusConnection *connection); +static void _dbus_connection_release_dispatch (DBusConnection *connection); +static DBusDispatchStatus _dbus_connection_flush_unlocked (DBusConnection *connection); +static void _dbus_connection_close_possibly_shared_and_unlock (DBusConnection *connection); +static dbus_bool_t _dbus_connection_get_is_connected_unlocked (DBusConnection *connection); + +static DBusMessageFilter * +_dbus_message_filter_ref (DBusMessageFilter *filter) +{ + _dbus_assert (filter->refcount.value > 0); + _dbus_atomic_inc (&filter->refcount); + + return filter; +} + +static void +_dbus_message_filter_unref (DBusMessageFilter *filter) +{ + _dbus_assert (filter->refcount.value > 0); + + if (_dbus_atomic_dec (&filter->refcount) == 1) + { + if (filter->free_user_data_function) + (* filter->free_user_data_function) (filter->user_data); + + dbus_free (filter); + } +} + +/** + * Acquires the connection lock. + * + * @param connection the connection. + */ +void +_dbus_connection_lock (DBusConnection *connection) +{ + CONNECTION_LOCK (connection); +} + +/** + * Releases the connection lock. + * + * @param connection the connection. + */ +void +_dbus_connection_unlock (DBusConnection *connection) +{ + CONNECTION_UNLOCK (connection); +} + +/** + * Wakes up the main loop if it is sleeping + * Needed if we're e.g. queueing outgoing messages + * on a thread while the mainloop sleeps. + * + * @param connection the connection. + */ +static void +_dbus_connection_wakeup_mainloop (DBusConnection *connection) +{ + if (connection->wakeup_main_function) + (*connection->wakeup_main_function) (connection->wakeup_main_data); +} + +#ifdef DBUS_BUILD_TESTS +/* For now this function isn't used */ +/** + * Adds a message to the incoming message queue, returning #FALSE + * if there's insufficient memory to queue the message. + * Does not take over refcount of the message. + * + * @param connection the connection. + * @param message the message to queue. + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_connection_queue_received_message (DBusConnection *connection, + DBusMessage *message) +{ + DBusList *link; + + link = _dbus_list_alloc_link (message); + if (link == NULL) + return FALSE; + + dbus_message_ref (message); + _dbus_connection_queue_received_message_link (connection, link); + + return TRUE; +} + +/** + * Gets the locks so we can examine them + * + * @param connection the connection. + * @param mutex_loc return for the location of the main mutex pointer + * @param dispatch_mutex_loc return location of the dispatch mutex pointer + * @param io_path_mutex_loc return location of the io_path mutex pointer + * @param dispatch_cond_loc return location of the dispatch conditional + * variable pointer + * @param io_path_cond_loc return location of the io_path conditional + * variable pointer + */ +void +_dbus_connection_test_get_locks (DBusConnection *connection, + DBusMutex **mutex_loc, + DBusMutex **dispatch_mutex_loc, + DBusMutex **io_path_mutex_loc, + DBusCondVar **dispatch_cond_loc, + DBusCondVar **io_path_cond_loc) +{ + *mutex_loc = connection->mutex; + *dispatch_mutex_loc = connection->dispatch_mutex; + *io_path_mutex_loc = connection->io_path_mutex; + *dispatch_cond_loc = connection->dispatch_cond; + *io_path_cond_loc = connection->io_path_cond; +} +#endif + +/** + * Adds a message-containing list link to the incoming message queue, + * taking ownership of the link and the message's current refcount. + * Cannot fail due to lack of memory. + * + * @param connection the connection. + * @param link the message link to queue. + */ +void +_dbus_connection_queue_received_message_link (DBusConnection *connection, + DBusList *link) +{ + DBusPendingCall *pending; + dbus_uint32_t reply_serial; + DBusMessage *message; + + _dbus_assert (_dbus_transport_get_is_authenticated (connection->transport)); + + _dbus_list_append_link (&connection->incoming_messages, + link); + message = link->data; + + /* If this is a reply we're waiting on, remove timeout for it */ + reply_serial = dbus_message_get_reply_serial (message); + if (reply_serial != 0) + { + pending = _dbus_hash_table_lookup_int (connection->pending_replies, + reply_serial); + if (pending != NULL) + { + if (_dbus_pending_call_is_timeout_added_unlocked (pending)) + _dbus_connection_remove_timeout_unlocked (connection, + _dbus_pending_call_get_timeout_unlocked (pending)); + + _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); + } + } + + + + connection->n_incoming += 1; + + _dbus_connection_wakeup_mainloop (connection); + + _dbus_verbose ("Message %p (%d %s %s %s '%s' reply to %u) added to incoming queue %p, %d incoming\n", + message, + dbus_message_get_type (message), + dbus_message_get_path (message) ? + dbus_message_get_path (message) : + "no path", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : + "no interface", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : + "no member", + dbus_message_get_signature (message), + dbus_message_get_reply_serial (message), + connection, + connection->n_incoming);} + +/** + * Adds a link + message to the incoming message queue. + * Can't fail. Takes ownership of both link and message. + * + * @param connection the connection. + * @param link the list node and message to queue. + * + */ +void +_dbus_connection_queue_synthesized_message_link (DBusConnection *connection, + DBusList *link) +{ + HAVE_LOCK_CHECK (connection); + + _dbus_list_append_link (&connection->incoming_messages, link); + + connection->n_incoming += 1; + + _dbus_connection_wakeup_mainloop (connection); + + _dbus_verbose ("Synthesized message %p added to incoming queue %p, %d incoming\n", + link->data, connection, connection->n_incoming); +} + + +/** + * Checks whether there are messages in the outgoing message queue. + * Called with connection lock held. + * + * @param connection the connection. + * @returns #TRUE if the outgoing queue is non-empty. + */ +dbus_bool_t +_dbus_connection_has_messages_to_send_unlocked (DBusConnection *connection) +{ + HAVE_LOCK_CHECK (connection); + return connection->outgoing_messages != NULL; +} + +/** + * Checks whether there are messages in the outgoing message queue. + * Use dbus_connection_flush() to block until all outgoing + * messages have been written to the underlying transport + * (such as a socket). + * + * @param connection the connection. + * @returns #TRUE if the outgoing queue is non-empty. + */ +dbus_bool_t +dbus_connection_has_messages_to_send (DBusConnection *connection) +{ + dbus_bool_t v; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + + CONNECTION_LOCK (connection); + v = _dbus_connection_has_messages_to_send_unlocked (connection); + CONNECTION_UNLOCK (connection); + + return v; +} + +/** + * Gets the next outgoing message. The message remains in the + * queue, and the caller does not own a reference to it. + * + * @param connection the connection. + * @returns the message to be sent. + */ +DBusMessage* +_dbus_connection_get_message_to_send (DBusConnection *connection) +{ + HAVE_LOCK_CHECK (connection); + + return _dbus_list_get_last (&connection->outgoing_messages); +} + +/** + * Notifies the connection that a message has been sent, so the + * message can be removed from the outgoing queue. + * Called with the connection lock held. + * + * @param connection the connection. + * @param message the message that was sent. + */ +void +_dbus_connection_message_sent (DBusConnection *connection, + DBusMessage *message) +{ + DBusList *link; + + HAVE_LOCK_CHECK (connection); + + /* This can be called before we even complete authentication, since + * it's called on disconnect to clean up the outgoing queue. + * It's also called as we successfully send each message. + */ + + link = _dbus_list_get_last_link (&connection->outgoing_messages); + _dbus_assert (link != NULL); + _dbus_assert (link->data == message); + + /* Save this link in the link cache */ + _dbus_list_unlink (&connection->outgoing_messages, + link); + _dbus_list_prepend_link (&connection->link_cache, link); + + connection->n_outgoing -= 1; + + _dbus_verbose ("Message %p (%d %s %s %s '%s') removed from outgoing queue %p, %d left to send\n", + message, + dbus_message_get_type (message), + dbus_message_get_path (message) ? + dbus_message_get_path (message) : + "no path", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : + "no interface", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : + "no member", + dbus_message_get_signature (message), + connection, connection->n_outgoing); + + /* Save this link in the link cache also */ + _dbus_message_remove_size_counter (message, connection->outgoing_counter, + &link); + _dbus_list_prepend_link (&connection->link_cache, link); + + dbus_message_unref (message); +} + +/** Function to be called in protected_change_watch() with refcount held */ +typedef dbus_bool_t (* DBusWatchAddFunction) (DBusWatchList *list, + DBusWatch *watch); +/** Function to be called in protected_change_watch() with refcount held */ +typedef void (* DBusWatchRemoveFunction) (DBusWatchList *list, + DBusWatch *watch); +/** Function to be called in protected_change_watch() with refcount held */ +typedef void (* DBusWatchToggleFunction) (DBusWatchList *list, + DBusWatch *watch, + dbus_bool_t enabled); + +static dbus_bool_t +protected_change_watch (DBusConnection *connection, + DBusWatch *watch, + DBusWatchAddFunction add_function, + DBusWatchRemoveFunction remove_function, + DBusWatchToggleFunction toggle_function, + dbus_bool_t enabled) +{ + DBusWatchList *watches; + dbus_bool_t retval; + + HAVE_LOCK_CHECK (connection); + + /* This isn't really safe or reasonable; a better pattern is the "do everything, then + * drop lock and call out" one; but it has to be propagated up through all callers + */ + + watches = connection->watches; + if (watches) + { + connection->watches = NULL; + _dbus_connection_ref_unlocked (connection); + CONNECTION_UNLOCK (connection); + + if (add_function) + retval = (* add_function) (watches, watch); + else if (remove_function) + { + retval = TRUE; + (* remove_function) (watches, watch); + } + else + { + retval = TRUE; + (* toggle_function) (watches, watch, enabled); + } + + CONNECTION_LOCK (connection); + connection->watches = watches; + _dbus_connection_unref_unlocked (connection); + + return retval; + } + else + return FALSE; +} + + +/** + * Adds a watch using the connection's DBusAddWatchFunction if + * available. Otherwise records the watch to be added when said + * function is available. Also re-adds the watch if the + * DBusAddWatchFunction changes. May fail due to lack of memory. + * Connection lock should be held when calling this. + * + * @param connection the connection. + * @param watch the watch to add. + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_connection_add_watch_unlocked (DBusConnection *connection, + DBusWatch *watch) +{ + return protected_change_watch (connection, watch, + _dbus_watch_list_add_watch, + NULL, NULL, FALSE); +} + +/** + * Removes a watch using the connection's DBusRemoveWatchFunction + * if available. It's an error to call this function on a watch + * that was not previously added. + * Connection lock should be held when calling this. + * + * @param connection the connection. + * @param watch the watch to remove. + */ +void +_dbus_connection_remove_watch_unlocked (DBusConnection *connection, + DBusWatch *watch) +{ + protected_change_watch (connection, watch, + NULL, + _dbus_watch_list_remove_watch, + NULL, FALSE); +} + +/** + * Toggles a watch and notifies app via connection's + * DBusWatchToggledFunction if available. It's an error to call this + * function on a watch that was not previously added. + * Connection lock should be held when calling this. + * + * @param connection the connection. + * @param watch the watch to toggle. + * @param enabled whether to enable or disable + */ +void +_dbus_connection_toggle_watch_unlocked (DBusConnection *connection, + DBusWatch *watch, + dbus_bool_t enabled) +{ + _dbus_assert (watch != NULL); + + protected_change_watch (connection, watch, + NULL, NULL, + _dbus_watch_list_toggle_watch, + enabled); +} + +/** Function to be called in protected_change_timeout() with refcount held */ +typedef dbus_bool_t (* DBusTimeoutAddFunction) (DBusTimeoutList *list, + DBusTimeout *timeout); +/** Function to be called in protected_change_timeout() with refcount held */ +typedef void (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list, + DBusTimeout *timeout); +/** Function to be called in protected_change_timeout() with refcount held */ +typedef void (* DBusTimeoutToggleFunction) (DBusTimeoutList *list, + DBusTimeout *timeout, + dbus_bool_t enabled); + +static dbus_bool_t +protected_change_timeout (DBusConnection *connection, + DBusTimeout *timeout, + DBusTimeoutAddFunction add_function, + DBusTimeoutRemoveFunction remove_function, + DBusTimeoutToggleFunction toggle_function, + dbus_bool_t enabled) +{ + DBusTimeoutList *timeouts; + dbus_bool_t retval; + + HAVE_LOCK_CHECK (connection); + + /* This isn't really safe or reasonable; a better pattern is the "do everything, then + * drop lock and call out" one; but it has to be propagated up through all callers + */ + + timeouts = connection->timeouts; + if (timeouts) + { + connection->timeouts = NULL; + _dbus_connection_ref_unlocked (connection); + CONNECTION_UNLOCK (connection); + + if (add_function) + retval = (* add_function) (timeouts, timeout); + else if (remove_function) + { + retval = TRUE; + (* remove_function) (timeouts, timeout); + } + else + { + retval = TRUE; + (* toggle_function) (timeouts, timeout, enabled); + } + + CONNECTION_LOCK (connection); + connection->timeouts = timeouts; + _dbus_connection_unref_unlocked (connection); + + return retval; + } + else + return FALSE; +} + +/** + * Adds a timeout using the connection's DBusAddTimeoutFunction if + * available. Otherwise records the timeout to be added when said + * function is available. Also re-adds the timeout if the + * DBusAddTimeoutFunction changes. May fail due to lack of memory. + * The timeout will fire repeatedly until removed. + * Connection lock should be held when calling this. + * + * @param connection the connection. + * @param timeout the timeout to add. + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_connection_add_timeout_unlocked (DBusConnection *connection, + DBusTimeout *timeout) +{ + return protected_change_timeout (connection, timeout, + _dbus_timeout_list_add_timeout, + NULL, NULL, FALSE); +} + +/** + * Removes a timeout using the connection's DBusRemoveTimeoutFunction + * if available. It's an error to call this function on a timeout + * that was not previously added. + * Connection lock should be held when calling this. + * + * @param connection the connection. + * @param timeout the timeout to remove. + */ +void +_dbus_connection_remove_timeout_unlocked (DBusConnection *connection, + DBusTimeout *timeout) +{ + protected_change_timeout (connection, timeout, + NULL, + _dbus_timeout_list_remove_timeout, + NULL, FALSE); +} + +/** + * Toggles a timeout and notifies app via connection's + * DBusTimeoutToggledFunction if available. It's an error to call this + * function on a timeout that was not previously added. + * Connection lock should be held when calling this. + * + * @param connection the connection. + * @param timeout the timeout to toggle. + * @param enabled whether to enable or disable + */ +void +_dbus_connection_toggle_timeout_unlocked (DBusConnection *connection, + DBusTimeout *timeout, + dbus_bool_t enabled) +{ + protected_change_timeout (connection, timeout, + NULL, NULL, + _dbus_timeout_list_toggle_timeout, + enabled); +} + +static dbus_bool_t +_dbus_connection_attach_pending_call_unlocked (DBusConnection *connection, + DBusPendingCall *pending) +{ + dbus_uint32_t reply_serial; + DBusTimeout *timeout; + + HAVE_LOCK_CHECK (connection); + + reply_serial = _dbus_pending_call_get_reply_serial_unlocked (pending); + + _dbus_assert (reply_serial != 0); + + timeout = _dbus_pending_call_get_timeout_unlocked (pending); + + if (timeout) + { + if (!_dbus_connection_add_timeout_unlocked (connection, timeout)) + return FALSE; + + if (!_dbus_hash_table_insert_int (connection->pending_replies, + reply_serial, + pending)) + { + _dbus_connection_remove_timeout_unlocked (connection, timeout); + + _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); + HAVE_LOCK_CHECK (connection); + return FALSE; + } + + _dbus_pending_call_set_timeout_added_unlocked (pending, TRUE); + } + else + { + if (!_dbus_hash_table_insert_int (connection->pending_replies, + reply_serial, + pending)) + { + HAVE_LOCK_CHECK (connection); + return FALSE; + } + } + + _dbus_pending_call_ref_unlocked (pending); + + HAVE_LOCK_CHECK (connection); + + return TRUE; +} + +static void +free_pending_call_on_hash_removal (void *data) +{ + DBusPendingCall *pending; + DBusConnection *connection; + + if (data == NULL) + return; + + pending = data; + + connection = _dbus_pending_call_get_connection_unlocked (pending); + + HAVE_LOCK_CHECK (connection); + + if (_dbus_pending_call_is_timeout_added_unlocked (pending)) + { + _dbus_connection_remove_timeout_unlocked (connection, + _dbus_pending_call_get_timeout_unlocked (pending)); + + _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); + } + + /* FIXME 1.0? this is sort of dangerous and undesirable to drop the lock + * here, but the pending call finalizer could in principle call out to + * application code so we pretty much have to... some larger code reorg + * might be needed. + */ + _dbus_connection_ref_unlocked (connection); + _dbus_pending_call_unref_and_unlock (pending); + CONNECTION_LOCK (connection); + _dbus_connection_unref_unlocked (connection); +} + +static void +_dbus_connection_detach_pending_call_unlocked (DBusConnection *connection, + DBusPendingCall *pending) +{ + /* This ends up unlocking to call the pending call finalizer, which is unexpected to + * say the least. + */ + _dbus_hash_table_remove_int (connection->pending_replies, + _dbus_pending_call_get_reply_serial_unlocked (pending)); +} + +static void +_dbus_connection_detach_pending_call_and_unlock (DBusConnection *connection, + DBusPendingCall *pending) +{ + /* The idea here is to avoid finalizing the pending call + * with the lock held, since there's a destroy notifier + * in pending call that goes out to application code. + * + * There's an extra unlock inside the hash table + * "free pending call" function FIXME... + */ + _dbus_pending_call_ref_unlocked (pending); + _dbus_hash_table_remove_int (connection->pending_replies, + _dbus_pending_call_get_reply_serial_unlocked (pending)); + + if (_dbus_pending_call_is_timeout_added_unlocked (pending)) + _dbus_connection_remove_timeout_unlocked (connection, + _dbus_pending_call_get_timeout_unlocked (pending)); + + _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); + + _dbus_pending_call_unref_and_unlock (pending); +} + +/** + * Removes a pending call from the connection, such that + * the pending reply will be ignored. May drop the last + * reference to the pending call. + * + * @param connection the connection + * @param pending the pending call + */ +void +_dbus_connection_remove_pending_call (DBusConnection *connection, + DBusPendingCall *pending) +{ + CONNECTION_LOCK (connection); + _dbus_connection_detach_pending_call_and_unlock (connection, pending); +} + +/** + * Acquire the transporter I/O path. This must be done before + * doing any I/O in the transporter. May sleep and drop the + * IO path mutex while waiting for the I/O path. + * + * @param connection the connection. + * @param timeout_milliseconds maximum blocking time, or -1 for no limit. + * @returns TRUE if the I/O path was acquired. + */ +static dbus_bool_t +_dbus_connection_acquire_io_path (DBusConnection *connection, + int timeout_milliseconds) +{ + dbus_bool_t we_acquired; + + HAVE_LOCK_CHECK (connection); + + /* We don't want the connection to vanish */ + _dbus_connection_ref_unlocked (connection); + + /* We will only touch io_path_acquired which is protected by our mutex */ + CONNECTION_UNLOCK (connection); + + _dbus_verbose ("%s locking io_path_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_mutex_lock (connection->io_path_mutex); + + _dbus_verbose ("%s start connection->io_path_acquired = %d timeout = %d\n", + _DBUS_FUNCTION_NAME, connection->io_path_acquired, timeout_milliseconds); + + we_acquired = FALSE; + + if (connection->io_path_acquired) + { + if (timeout_milliseconds != -1) + { + _dbus_verbose ("%s waiting %d for IO path to be acquirable\n", + _DBUS_FUNCTION_NAME, timeout_milliseconds); + + if (!_dbus_condvar_wait_timeout (connection->io_path_cond, + connection->io_path_mutex, + timeout_milliseconds)) + { + /* We timed out before anyone signaled. */ + /* (writing the loop to handle the !timedout case by + * waiting longer if needed is a pain since dbus + * wraps pthread_cond_timedwait to take a relative + * time instead of absolute, something kind of stupid + * on our part. for now it doesn't matter, we will just + * end up back here eventually.) + */ + } + } + else + { + while (connection->io_path_acquired) + { + _dbus_verbose ("%s waiting for IO path to be acquirable\n", _DBUS_FUNCTION_NAME); + _dbus_condvar_wait (connection->io_path_cond, + connection->io_path_mutex); + } + } + } + + if (!connection->io_path_acquired) + { + we_acquired = TRUE; + connection->io_path_acquired = TRUE; + } + + _dbus_verbose ("%s end connection->io_path_acquired = %d we_acquired = %d\n", + _DBUS_FUNCTION_NAME, connection->io_path_acquired, we_acquired); + + _dbus_verbose ("%s unlocking io_path_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_mutex_unlock (connection->io_path_mutex); + + CONNECTION_LOCK (connection); + + HAVE_LOCK_CHECK (connection); + + _dbus_connection_unref_unlocked (connection); + + return we_acquired; +} + +/** + * Release the I/O path when you're done with it. Only call + * after you've acquired the I/O. Wakes up at most one thread + * currently waiting to acquire the I/O path. + * + * @param connection the connection. + */ +static void +_dbus_connection_release_io_path (DBusConnection *connection) +{ + HAVE_LOCK_CHECK (connection); + + _dbus_verbose ("%s locking io_path_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_mutex_lock (connection->io_path_mutex); + + _dbus_assert (connection->io_path_acquired); + + _dbus_verbose ("%s start connection->io_path_acquired = %d\n", + _DBUS_FUNCTION_NAME, connection->io_path_acquired); + + connection->io_path_acquired = FALSE; + _dbus_condvar_wake_one (connection->io_path_cond); + + _dbus_verbose ("%s unlocking io_path_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_mutex_unlock (connection->io_path_mutex); +} + +/** + * Queues incoming messages and sends outgoing messages for this + * connection, optionally blocking in the process. Each call to + * _dbus_connection_do_iteration_unlocked() will call select() or poll() one + * time and then read or write data if possible. + * + * The purpose of this function is to be able to flush outgoing + * messages or queue up incoming messages without returning + * control to the application and causing reentrancy weirdness. + * + * The flags parameter allows you to specify whether to + * read incoming messages, write outgoing messages, or both, + * and whether to block if no immediate action is possible. + * + * The timeout_milliseconds parameter does nothing unless the + * iteration is blocking. + * + * If there are no outgoing messages and DBUS_ITERATION_DO_READING + * wasn't specified, then it's impossible to block, even if + * you specify DBUS_ITERATION_BLOCK; in that case the function + * returns immediately. + * + * Called with connection lock held. + * + * @param connection the connection. + * @param flags iteration flags. + * @param timeout_milliseconds maximum blocking time, or -1 for no limit. + */ +void +_dbus_connection_do_iteration_unlocked (DBusConnection *connection, + unsigned int flags, + int timeout_milliseconds) +{ + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + + HAVE_LOCK_CHECK (connection); + + if (connection->n_outgoing == 0) + flags &= ~DBUS_ITERATION_DO_WRITING; + + if (_dbus_connection_acquire_io_path (connection, + (flags & DBUS_ITERATION_BLOCK) ? timeout_milliseconds : 0)) + { + HAVE_LOCK_CHECK (connection); + + _dbus_transport_do_iteration (connection->transport, + flags, timeout_milliseconds); + _dbus_connection_release_io_path (connection); + } + + HAVE_LOCK_CHECK (connection); + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); +} + +/** + * Creates a new connection for the given transport. A transport + * represents a message stream that uses some concrete mechanism, such + * as UNIX domain sockets. May return #NULL if insufficient + * memory exists to create the connection. + * + * @param transport the transport. + * @returns the new connection, or #NULL on failure. + */ +DBusConnection* +_dbus_connection_new_for_transport (DBusTransport *transport) +{ + DBusConnection *connection; + DBusWatchList *watch_list; + DBusTimeoutList *timeout_list; + DBusHashTable *pending_replies; + DBusList *disconnect_link; + DBusMessage *disconnect_message; + DBusCounter *outgoing_counter; + DBusObjectTree *objects; + + watch_list = NULL; + connection = NULL; + pending_replies = NULL; + timeout_list = NULL; + disconnect_link = NULL; + disconnect_message = NULL; + outgoing_counter = NULL; + objects = NULL; + + watch_list = _dbus_watch_list_new (); + if (watch_list == NULL) + goto error; + + timeout_list = _dbus_timeout_list_new (); + if (timeout_list == NULL) + goto error; + + pending_replies = + _dbus_hash_table_new (DBUS_HASH_INT, + NULL, + (DBusFreeFunction)free_pending_call_on_hash_removal); + if (pending_replies == NULL) + goto error; + + connection = dbus_new0 (DBusConnection, 1); + if (connection == NULL) + goto error; + + _dbus_mutex_new_at_location (&connection->mutex); + if (connection->mutex == NULL) + goto error; + + _dbus_mutex_new_at_location (&connection->io_path_mutex); + if (connection->io_path_mutex == NULL) + goto error; + + _dbus_mutex_new_at_location (&connection->dispatch_mutex); + if (connection->dispatch_mutex == NULL) + goto error; + + _dbus_condvar_new_at_location (&connection->dispatch_cond); + if (connection->dispatch_cond == NULL) + goto error; + + _dbus_condvar_new_at_location (&connection->io_path_cond); + if (connection->io_path_cond == NULL) + goto error; + + disconnect_message = dbus_message_new_signal (DBUS_PATH_LOCAL, + DBUS_INTERFACE_LOCAL, + "Disconnected"); + + if (disconnect_message == NULL) + goto error; + + disconnect_link = _dbus_list_alloc_link (disconnect_message); + if (disconnect_link == NULL) + goto error; + + outgoing_counter = _dbus_counter_new (); + if (outgoing_counter == NULL) + goto error; + + objects = _dbus_object_tree_new (connection); + if (objects == NULL) + goto error; + + if (_dbus_modify_sigpipe) + _dbus_disable_sigpipe (); + + connection->refcount.value = 1; + connection->transport = transport; + connection->watches = watch_list; + connection->timeouts = timeout_list; + connection->pending_replies = pending_replies; + connection->outgoing_counter = outgoing_counter; + connection->filter_list = NULL; + connection->last_dispatch_status = DBUS_DISPATCH_COMPLETE; /* so we're notified first time there's data */ + connection->objects = objects; + connection->exit_on_disconnect = FALSE; + connection->shareable = FALSE; + connection->route_peer_messages = FALSE; + connection->disconnected_message_arrived = FALSE; + connection->disconnected_message_processed = FALSE; + +#ifndef DBUS_DISABLE_CHECKS + connection->generation = _dbus_current_generation; +#endif + + _dbus_data_slot_list_init (&connection->slot_list); + + connection->client_serial = 1; + + connection->disconnect_message_link = disconnect_link; + + CONNECTION_LOCK (connection); + + if (!_dbus_transport_set_connection (transport, connection)) + { + CONNECTION_UNLOCK (connection); + + goto error; + } + + _dbus_transport_ref (transport); + + CONNECTION_UNLOCK (connection); + + return connection; + + error: + if (disconnect_message != NULL) + dbus_message_unref (disconnect_message); + + if (disconnect_link != NULL) + _dbus_list_free_link (disconnect_link); + + if (connection != NULL) + { + _dbus_condvar_free_at_location (&connection->io_path_cond); + _dbus_condvar_free_at_location (&connection->dispatch_cond); + _dbus_mutex_free_at_location (&connection->mutex); + _dbus_mutex_free_at_location (&connection->io_path_mutex); + _dbus_mutex_free_at_location (&connection->dispatch_mutex); + dbus_free (connection); + } + if (pending_replies) + _dbus_hash_table_unref (pending_replies); + + if (watch_list) + _dbus_watch_list_free (watch_list); + + if (timeout_list) + _dbus_timeout_list_free (timeout_list); + + if (outgoing_counter) + _dbus_counter_unref (outgoing_counter); + + if (objects) + _dbus_object_tree_unref (objects); + + return NULL; +} + +/** + * Increments the reference count of a DBusConnection. + * Requires that the caller already holds the connection lock. + * + * @param connection the connection. + * @returns the connection. + */ +DBusConnection * +_dbus_connection_ref_unlocked (DBusConnection *connection) +{ + _dbus_assert (connection != NULL); + _dbus_assert (connection->generation == _dbus_current_generation); + + HAVE_LOCK_CHECK (connection); + +#ifdef DBUS_HAVE_ATOMIC_INT + _dbus_atomic_inc (&connection->refcount); +#else + _dbus_assert (connection->refcount.value > 0); + connection->refcount.value += 1; +#endif + + return connection; +} + +/** + * Decrements the reference count of a DBusConnection. + * Requires that the caller already holds the connection lock. + * + * @param connection the connection. + */ +void +_dbus_connection_unref_unlocked (DBusConnection *connection) +{ + dbus_bool_t last_unref; + + HAVE_LOCK_CHECK (connection); + + _dbus_assert (connection != NULL); + + /* The connection lock is better than the global + * lock in the atomic increment fallback + */ + +#ifdef DBUS_HAVE_ATOMIC_INT + last_unref = (_dbus_atomic_dec (&connection->refcount) == 1); +#else + _dbus_assert (connection->refcount.value > 0); + + connection->refcount.value -= 1; + last_unref = (connection->refcount.value == 0); +#if 0 + printf ("unref_unlocked() connection %p count = %d\n", connection, connection->refcount.value); +#endif +#endif + + if (last_unref) + _dbus_connection_last_unref (connection); +} + +static dbus_uint32_t +_dbus_connection_get_next_client_serial (DBusConnection *connection) +{ + dbus_uint32_t serial; + + serial = connection->client_serial++; + + if (connection->client_serial == 0) + connection->client_serial = 1; + + return serial; +} + +/** + * A callback for use with dbus_watch_new() to create a DBusWatch. + * + * @todo This is basically a hack - we could delete _dbus_transport_handle_watch() + * and the virtual handle_watch in DBusTransport if we got rid of it. + * The reason this is some work is threading, see the _dbus_connection_handle_watch() + * implementation. + * + * @param watch the watch. + * @param condition the current condition of the file descriptors being watched. + * @param data must be a pointer to a #DBusConnection + * @returns #FALSE if the IO condition may not have been fully handled due to lack of memory + */ +dbus_bool_t +_dbus_connection_handle_watch (DBusWatch *watch, + unsigned int condition, + void *data) +{ + DBusConnection *connection; + dbus_bool_t retval; + DBusDispatchStatus status; + + connection = data; + + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + + CONNECTION_LOCK (connection); + + if (!_dbus_connection_acquire_io_path (connection, 1)) + { + /* another thread is handling the message */ + CONNECTION_UNLOCK (connection); + return TRUE; + } + + HAVE_LOCK_CHECK (connection); + retval = _dbus_transport_handle_watch (connection->transport, + watch, condition); + + _dbus_connection_release_io_path (connection); + + HAVE_LOCK_CHECK (connection); + + _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); + + status = _dbus_connection_get_dispatch_status_unlocked (connection); + + /* this calls out to user code */ + _dbus_connection_update_dispatch_status_and_unlock (connection, status); + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); + + return retval; +} + +_DBUS_DEFINE_GLOBAL_LOCK (shared_connections); +static DBusHashTable *shared_connections = NULL; +static DBusList *shared_connections_no_guid = NULL; + +static void +close_connection_on_shutdown (DBusConnection *connection) +{ + DBusMessage *message; + + dbus_connection_ref (connection); + _dbus_connection_close_possibly_shared (connection); + + /* Churn through to the Disconnected message */ + while ((message = dbus_connection_pop_message (connection))) + { + dbus_message_unref (message); + } + dbus_connection_unref (connection); +} + +static void +shared_connections_shutdown (void *data) +{ + int n_entries; + + _DBUS_LOCK (shared_connections); + + /* This is a little bit unpleasant... better ideas? */ + while ((n_entries = _dbus_hash_table_get_n_entries (shared_connections)) > 0) + { + DBusConnection *connection; + DBusHashIter iter; + + _dbus_hash_iter_init (shared_connections, &iter); + _dbus_hash_iter_next (&iter); + + connection = _dbus_hash_iter_get_value (&iter); + + _DBUS_UNLOCK (shared_connections); + close_connection_on_shutdown (connection); + _DBUS_LOCK (shared_connections); + + /* The connection should now be dead and not in our hash ... */ + _dbus_assert (_dbus_hash_table_get_n_entries (shared_connections) < n_entries); + } + + _dbus_assert (_dbus_hash_table_get_n_entries (shared_connections) == 0); + + _dbus_hash_table_unref (shared_connections); + shared_connections = NULL; + + if (shared_connections_no_guid != NULL) + { + DBusConnection *connection; + connection = _dbus_list_pop_first (&shared_connections_no_guid); + while (connection != NULL) + { + _DBUS_UNLOCK (shared_connections); + close_connection_on_shutdown (connection); + _DBUS_LOCK (shared_connections); + connection = _dbus_list_pop_first (&shared_connections_no_guid); + } + } + + shared_connections_no_guid = NULL; + + _DBUS_UNLOCK (shared_connections); +} + +static dbus_bool_t +connection_lookup_shared (DBusAddressEntry *entry, + DBusConnection **result) +{ + _dbus_verbose ("checking for existing connection\n"); + + *result = NULL; + + _DBUS_LOCK (shared_connections); + + if (shared_connections == NULL) + { + _dbus_verbose ("creating shared_connections hash table\n"); + + shared_connections = _dbus_hash_table_new (DBUS_HASH_STRING, + dbus_free, + NULL); + if (shared_connections == NULL) + { + _DBUS_UNLOCK (shared_connections); + return FALSE; + } + + if (!_dbus_register_shutdown_func (shared_connections_shutdown, NULL)) + { + _dbus_hash_table_unref (shared_connections); + shared_connections = NULL; + _DBUS_UNLOCK (shared_connections); + return FALSE; + } + + _dbus_verbose (" successfully created shared_connections\n"); + + _DBUS_UNLOCK (shared_connections); + return TRUE; /* no point looking up in the hash we just made */ + } + else + { + const char *guid; + + guid = dbus_address_entry_get_value (entry, "guid"); + + if (guid != NULL) + { + DBusConnection *connection; + + connection = _dbus_hash_table_lookup_string (shared_connections, + guid); + + if (connection) + { + /* The DBusConnection can't be finalized without taking + * the shared_connections lock to remove it from the + * hash. So it's safe to ref the connection here. + * However, it may be disconnected if the Disconnected + * message hasn't been processed yet, in which case we + * want to pretend it isn't in the hash and avoid + * returning it. + * + * The idea is to avoid ever returning a disconnected connection + * from dbus_connection_open(). We could just synchronously + * drop our shared ref to the connection on connection disconnect, + * and then assert here that the connection is connected, but + * that causes reentrancy headaches. + */ + CONNECTION_LOCK (connection); + if (_dbus_connection_get_is_connected_unlocked (connection)) + { + _dbus_connection_ref_unlocked (connection); + *result = connection; + _dbus_verbose ("looked up existing connection to server guid %s\n", + guid); + } + else + { + _dbus_verbose ("looked up existing connection to server guid %s but it was disconnected so ignoring it\n", + guid); + } + CONNECTION_UNLOCK (connection); + } + } + + _DBUS_UNLOCK (shared_connections); + return TRUE; + } +} + +static dbus_bool_t +connection_record_shared_unlocked (DBusConnection *connection, + const char *guid) +{ + char *guid_key; + char *guid_in_connection; + + HAVE_LOCK_CHECK (connection); + _dbus_assert (connection->server_guid == NULL); + _dbus_assert (connection->shareable); + + /* get a hard ref on this connection, even if + * we won't in fact store it in the hash, we still + * need to hold a ref on it until it's disconnected. + */ + _dbus_connection_ref_unlocked (connection); + + if (guid == NULL) + { + _DBUS_LOCK (shared_connections); + + if (!_dbus_list_prepend (&shared_connections_no_guid, connection)) + { + _DBUS_UNLOCK (shared_connections); + return FALSE; + } + + _DBUS_UNLOCK (shared_connections); + return TRUE; /* don't store in the hash */ + } + + /* A separate copy of the key is required in the hash table, because + * we don't have a lock on the connection when we are doing a hash + * lookup. + */ + + guid_key = _dbus_strdup (guid); + if (guid_key == NULL) + return FALSE; + + guid_in_connection = _dbus_strdup (guid); + if (guid_in_connection == NULL) + { + dbus_free (guid_key); + return FALSE; + } + + _DBUS_LOCK (shared_connections); + _dbus_assert (shared_connections != NULL); + + if (!_dbus_hash_table_insert_string (shared_connections, + guid_key, connection)) + { + dbus_free (guid_key); + dbus_free (guid_in_connection); + _DBUS_UNLOCK (shared_connections); + return FALSE; + } + + connection->server_guid = guid_in_connection; + + _dbus_verbose ("stored connection to %s to be shared\n", + connection->server_guid); + + _DBUS_UNLOCK (shared_connections); + + _dbus_assert (connection->server_guid != NULL); + + return TRUE; +} + +static void +connection_forget_shared_unlocked (DBusConnection *connection) +{ + HAVE_LOCK_CHECK (connection); + + if (!connection->shareable) + return; + + _DBUS_LOCK (shared_connections); + + if (connection->server_guid != NULL) + { + _dbus_verbose ("dropping connection to %s out of the shared table\n", + connection->server_guid); + + if (!_dbus_hash_table_remove_string (shared_connections, + connection->server_guid)) + _dbus_assert_not_reached ("connection was not in the shared table"); + + dbus_free (connection->server_guid); + connection->server_guid = NULL; + } + else + { + _dbus_list_remove (&shared_connections_no_guid, connection); + } + + _DBUS_UNLOCK (shared_connections); + + /* remove our reference held on all shareable connections */ + _dbus_connection_unref_unlocked (connection); +} + +static DBusConnection* +connection_try_from_address_entry (DBusAddressEntry *entry, + DBusError *error) +{ + DBusTransport *transport; + DBusConnection *connection; + + transport = _dbus_transport_open (entry, error); + + if (transport == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return NULL; + } + + connection = _dbus_connection_new_for_transport (transport); + + _dbus_transport_unref (transport); + + if (connection == NULL) + { + _DBUS_SET_OOM (error); + return NULL; + } + +#ifndef DBUS_DISABLE_CHECKS + _dbus_assert (!connection->have_connection_lock); +#endif + return connection; +} + +/* + * If the shared parameter is true, then any existing connection will + * be used (and if a new connection is created, it will be available + * for use by others). If the shared parameter is false, a new + * connection will always be created, and the new connection will + * never be returned to other callers. + * + * @param address the address + * @param shared whether the connection is shared or private + * @param error error return + * @returns the connection or #NULL on error + */ +static DBusConnection* +_dbus_connection_open_internal (const char *address, + dbus_bool_t shared, + DBusError *error) +{ + DBusConnection *connection; + DBusAddressEntry **entries; + DBusError tmp_error = DBUS_ERROR_INIT; + DBusError first_error = DBUS_ERROR_INIT; + int len, i; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_verbose ("opening %s connection to: %s\n", + shared ? "shared" : "private", address); + + if (!dbus_parse_address (address, &entries, &len, error)) + return NULL; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + connection = NULL; + + for (i = 0; i < len; i++) + { + if (shared) + { + if (!connection_lookup_shared (entries[i], &connection)) + _DBUS_SET_OOM (&tmp_error); + } + + if (connection == NULL) + { + connection = connection_try_from_address_entry (entries[i], + &tmp_error); + + if (connection != NULL && shared) + { + const char *guid; + + connection->shareable = TRUE; + + /* guid may be NULL */ + guid = dbus_address_entry_get_value (entries[i], "guid"); + + CONNECTION_LOCK (connection); + + if (!connection_record_shared_unlocked (connection, guid)) + { + _DBUS_SET_OOM (&tmp_error); + _dbus_connection_close_possibly_shared_and_unlock (connection); + dbus_connection_unref (connection); + connection = NULL; + } + else + CONNECTION_UNLOCK (connection); + } + } + + if (connection) + break; + + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + + if (i == 0) + dbus_move_error (&tmp_error, &first_error); + else + dbus_error_free (&tmp_error); + } + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); + + if (connection == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (&first_error); + dbus_move_error (&first_error, error); + } + else + dbus_error_free (&first_error); + + dbus_address_entries_free (entries); + return connection; +} + +/** + * Closes a shared OR private connection, while dbus_connection_close() can + * only be used on private connections. Should only be called by the + * dbus code that owns the connection - an owner must be known, + * the open/close state is like malloc/free, not like ref/unref. + * + * @param connection the connection + */ +void +_dbus_connection_close_possibly_shared (DBusConnection *connection) +{ + _dbus_assert (connection != NULL); + _dbus_assert (connection->generation == _dbus_current_generation); + + CONNECTION_LOCK (connection); + _dbus_connection_close_possibly_shared_and_unlock (connection); +} + +static DBusPreallocatedSend* +_dbus_connection_preallocate_send_unlocked (DBusConnection *connection) +{ + DBusPreallocatedSend *preallocated; + + HAVE_LOCK_CHECK (connection); + + _dbus_assert (connection != NULL); + + preallocated = dbus_new (DBusPreallocatedSend, 1); + if (preallocated == NULL) + return NULL; + + if (connection->link_cache != NULL) + { + preallocated->queue_link = + _dbus_list_pop_first_link (&connection->link_cache); + preallocated->queue_link->data = NULL; + } + else + { + preallocated->queue_link = _dbus_list_alloc_link (NULL); + if (preallocated->queue_link == NULL) + goto failed_0; + } + + if (connection->link_cache != NULL) + { + preallocated->counter_link = + _dbus_list_pop_first_link (&connection->link_cache); + preallocated->counter_link->data = connection->outgoing_counter; + } + else + { + preallocated->counter_link = _dbus_list_alloc_link (connection->outgoing_counter); + if (preallocated->counter_link == NULL) + goto failed_1; + } + + _dbus_counter_ref (preallocated->counter_link->data); + + preallocated->connection = connection; + + return preallocated; + + failed_1: + _dbus_list_free_link (preallocated->queue_link); + failed_0: + dbus_free (preallocated); + + return NULL; +} + +/* Called with lock held, does not update dispatch status */ +static void +_dbus_connection_send_preallocated_unlocked_no_update (DBusConnection *connection, + DBusPreallocatedSend *preallocated, + DBusMessage *message, + dbus_uint32_t *client_serial) +{ + dbus_uint32_t serial; + const char *sig; + + preallocated->queue_link->data = message; + _dbus_list_prepend_link (&connection->outgoing_messages, + preallocated->queue_link); + + _dbus_message_add_size_counter_link (message, + preallocated->counter_link); + + dbus_free (preallocated); + preallocated = NULL; + + dbus_message_ref (message); + + connection->n_outgoing += 1; + + sig = dbus_message_get_signature (message); + + _dbus_verbose ("Message %p (%d %s %s %s '%s') for %s added to outgoing queue %p, %d pending to send\n", + message, + dbus_message_get_type (message), + dbus_message_get_path (message) ? + dbus_message_get_path (message) : + "no path", + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : + "no interface", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : + "no member", + sig, + dbus_message_get_destination (message) ? + dbus_message_get_destination (message) : + "null", + connection, + connection->n_outgoing); + + if (dbus_message_get_serial (message) == 0) + { + serial = _dbus_connection_get_next_client_serial (connection); + dbus_message_set_serial (message, serial); + if (client_serial) + *client_serial = serial; + } + else + { + if (client_serial) + *client_serial = dbus_message_get_serial (message); + } + + _dbus_verbose ("Message %p serial is %u\n", + message, dbus_message_get_serial (message)); + + dbus_message_lock (message); + + /* Now we need to run an iteration to hopefully just write the messages + * out immediately, and otherwise get them queued up + */ + _dbus_connection_do_iteration_unlocked (connection, + DBUS_ITERATION_DO_WRITING, + -1); + + /* If stuff is still queued up, be sure we wake up the main loop */ + if (connection->n_outgoing > 0) + _dbus_connection_wakeup_mainloop (connection); +} + +static void +_dbus_connection_send_preallocated_and_unlock (DBusConnection *connection, + DBusPreallocatedSend *preallocated, + DBusMessage *message, + dbus_uint32_t *client_serial) +{ + DBusDispatchStatus status; + + HAVE_LOCK_CHECK (connection); + + _dbus_connection_send_preallocated_unlocked_no_update (connection, + preallocated, + message, client_serial); + + _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); + status = _dbus_connection_get_dispatch_status_unlocked (connection); + + /* this calls out to user code */ + _dbus_connection_update_dispatch_status_and_unlock (connection, status); +} + +/** + * Like dbus_connection_send(), but assumes the connection + * is already locked on function entry, and unlocks before returning. + * + * @param connection the connection + * @param message the message to send + * @param client_serial return location for client serial of sent message + * @returns #FALSE on out-of-memory + */ +dbus_bool_t +_dbus_connection_send_and_unlock (DBusConnection *connection, + DBusMessage *message, + dbus_uint32_t *client_serial) +{ + DBusPreallocatedSend *preallocated; + + _dbus_assert (connection != NULL); + _dbus_assert (message != NULL); + + preallocated = _dbus_connection_preallocate_send_unlocked (connection); + if (preallocated == NULL) + { + CONNECTION_UNLOCK (connection); + return FALSE; + } + + _dbus_connection_send_preallocated_and_unlock (connection, + preallocated, + message, + client_serial); + return TRUE; +} + +/** + * Used internally to handle the semantics of dbus_server_set_new_connection_function(). + * If the new connection function does not ref the connection, we want to close it. + * + * A bit of a hack, probably the new connection function should have returned a value + * for whether to close, or should have had to close the connection itself if it + * didn't want it. + * + * But, this works OK as long as the new connection function doesn't do anything + * crazy like keep the connection around without ref'ing it. + * + * We have to lock the connection across refcount check and close in case + * the new connection function spawns a thread that closes and unrefs. + * In that case, if the app thread + * closes and unrefs first, we'll harmlessly close again; if the app thread + * still has the ref, we'll close and then the app will close harmlessly. + * If the app unrefs without closing, the app is broken since if the + * app refs from the new connection function it is supposed to also close. + * + * If we didn't atomically check the refcount and close with the lock held + * though, we could screw this up. + * + * @param connection the connection + */ +void +_dbus_connection_close_if_only_one_ref (DBusConnection *connection) +{ + CONNECTION_LOCK (connection); + + _dbus_assert (connection->refcount.value > 0); + + if (connection->refcount.value == 1) + _dbus_connection_close_possibly_shared_and_unlock (connection); + else + CONNECTION_UNLOCK (connection); +} + + +/** + * When a function that blocks has been called with a timeout, and we + * run out of memory, the time to wait for memory is based on the + * timeout. If the caller was willing to block a long time we wait a + * relatively long time for memory, if they were only willing to block + * briefly then we retry for memory at a rapid rate. + * + * @timeout_milliseconds the timeout requested for blocking + */ +static void +_dbus_memory_pause_based_on_timeout (int timeout_milliseconds) +{ + if (timeout_milliseconds == -1) + _dbus_sleep_milliseconds (1000); + else if (timeout_milliseconds < 100) + ; /* just busy loop */ + else if (timeout_milliseconds <= 1000) + _dbus_sleep_milliseconds (timeout_milliseconds / 3); + else + _dbus_sleep_milliseconds (1000); +} + +static DBusMessage * +generate_local_error_message (dbus_uint32_t serial, + char *error_name, + char *error_msg) +{ + DBusMessage *message; + message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); + if (!message) + goto out; + + if (!dbus_message_set_error_name (message, error_name)) + { + dbus_message_unref (message); + message = NULL; + goto out; + } + + dbus_message_set_no_reply (message, TRUE); + + if (!dbus_message_set_reply_serial (message, + serial)) + { + dbus_message_unref (message); + message = NULL; + goto out; + } + + if (error_msg != NULL) + { + DBusMessageIter iter; + + dbus_message_iter_init_append (message, &iter); + if (!dbus_message_iter_append_basic (&iter, + DBUS_TYPE_STRING, + &error_msg)) + { + dbus_message_unref (message); + message = NULL; + goto out; + } + } + + out: + return message; +} + + +/* This is slightly strange since we can pop a message here without + * the dispatch lock. + */ +static DBusMessage* +check_for_reply_unlocked (DBusConnection *connection, + dbus_uint32_t client_serial) +{ + DBusList *link; + + HAVE_LOCK_CHECK (connection); + + link = _dbus_list_get_first_link (&connection->incoming_messages); + + while (link != NULL) + { + DBusMessage *reply = link->data; + + if (dbus_message_get_reply_serial (reply) == client_serial) + { + _dbus_list_remove_link (&connection->incoming_messages, link); + connection->n_incoming -= 1; + return reply; + } + link = _dbus_list_get_next_link (&connection->incoming_messages, link); + } + + return NULL; +} + +static void +connection_timeout_and_complete_all_pending_calls_unlocked (DBusConnection *connection) +{ + /* We can't iterate over the hash in the normal way since we'll be + * dropping the lock for each item. So we restart the + * iter each time as we drain the hash table. + */ + + while (_dbus_hash_table_get_n_entries (connection->pending_replies) > 0) + { + DBusPendingCall *pending; + DBusHashIter iter; + + _dbus_hash_iter_init (connection->pending_replies, &iter); + _dbus_hash_iter_next (&iter); + + pending = _dbus_hash_iter_get_value (&iter); + _dbus_pending_call_ref_unlocked (pending); + + _dbus_pending_call_queue_timeout_error_unlocked (pending, + connection); + + if (_dbus_pending_call_is_timeout_added_unlocked (pending)) + _dbus_connection_remove_timeout_unlocked (connection, + _dbus_pending_call_get_timeout_unlocked (pending)); + _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); + _dbus_hash_iter_remove_entry (&iter); + + _dbus_pending_call_unref_and_unlock (pending); + CONNECTION_LOCK (connection); + } + HAVE_LOCK_CHECK (connection); +} + +static void +complete_pending_call_and_unlock (DBusConnection *connection, + DBusPendingCall *pending, + DBusMessage *message) +{ + _dbus_pending_call_set_reply_unlocked (pending, message); + _dbus_pending_call_ref_unlocked (pending); /* in case there's no app with a ref held */ + _dbus_connection_detach_pending_call_and_unlock (connection, pending); + + /* Must be called unlocked since it invokes app callback */ + _dbus_pending_call_complete (pending); + dbus_pending_call_unref (pending); +} + +static dbus_bool_t +check_for_reply_and_update_dispatch_unlocked (DBusConnection *connection, + DBusPendingCall *pending) +{ + DBusMessage *reply; + DBusDispatchStatus status; + + reply = check_for_reply_unlocked (connection, + _dbus_pending_call_get_reply_serial_unlocked (pending)); + if (reply != NULL) + { + _dbus_verbose ("%s checked for reply\n", _DBUS_FUNCTION_NAME); + + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply\n"); + + complete_pending_call_and_unlock (connection, pending, reply); + dbus_message_unref (reply); + + CONNECTION_LOCK (connection); + status = _dbus_connection_get_dispatch_status_unlocked (connection); + _dbus_connection_update_dispatch_status_and_unlock (connection, status); + dbus_pending_call_unref (pending); + + return TRUE; + } + + return FALSE; +} + +/** + * Blocks until a pending call times out or gets a reply. + * + * Does not re-enter the main loop or run filter/path-registered + * callbacks. The reply to the message will not be seen by + * filter callbacks. + * + * Returns immediately if pending call already got a reply. + * + * @todo could use performance improvements (it keeps scanning + * the whole message queue for example) + * + * @param pending the pending call we block for a reply on + */ +void +_dbus_connection_block_pending_call (DBusPendingCall *pending) +{ + long start_tv_sec, start_tv_usec; + long tv_sec, tv_usec; + DBusDispatchStatus status; + DBusConnection *connection; + dbus_uint32_t client_serial; + DBusTimeout *timeout; + int timeout_milliseconds, elapsed_milliseconds; + + _dbus_assert (pending != NULL); + + if (dbus_pending_call_get_completed (pending)) + return; + + dbus_pending_call_ref (pending); /* necessary because the call could be canceled */ + + connection = _dbus_pending_call_get_connection_and_lock (pending); + + /* Flush message queue - note, can affect dispatch status */ + _dbus_connection_flush_unlocked (connection); + + client_serial = _dbus_pending_call_get_reply_serial_unlocked (pending); + + /* note that timeout_milliseconds is limited to a smallish value + * in _dbus_pending_call_new() so overflows aren't possible + * below + */ + timeout = _dbus_pending_call_get_timeout_unlocked (pending); + if (timeout) + { + timeout_milliseconds = dbus_timeout_get_interval (timeout); + _dbus_get_current_time (&start_tv_sec, &start_tv_usec); + + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): will block %d milliseconds for reply serial %u from %ld sec %ld usec\n", + timeout_milliseconds, + client_serial, + start_tv_sec, start_tv_usec); + } + else + { + timeout_milliseconds = -1; + + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): will block for reply serial %u\n", client_serial); + } + + /* check to see if we already got the data off the socket */ + /* from another blocked pending call */ + if (check_for_reply_and_update_dispatch_unlocked (connection, pending)) + return; + + /* Now we wait... */ + /* always block at least once as we know we don't have the reply yet */ + _dbus_connection_do_iteration_unlocked (connection, + DBUS_ITERATION_DO_READING | + DBUS_ITERATION_BLOCK, + timeout_milliseconds); + + recheck_status: + + _dbus_verbose ("%s top of recheck\n", _DBUS_FUNCTION_NAME); + + HAVE_LOCK_CHECK (connection); + + /* queue messages and get status */ + + status = _dbus_connection_get_dispatch_status_unlocked (connection); + + /* the get_completed() is in case a dispatch() while we were blocking + * got the reply instead of us. + */ + if (_dbus_pending_call_get_completed_unlocked (pending)) + { + _dbus_verbose ("Pending call completed by dispatch in %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_update_dispatch_status_and_unlock (connection, status); + dbus_pending_call_unref (pending); + return; + } + + if (status == DBUS_DISPATCH_DATA_REMAINS) + { + if (check_for_reply_and_update_dispatch_unlocked (connection, pending)) + return; + } + + _dbus_get_current_time (&tv_sec, &tv_usec); + elapsed_milliseconds = (tv_sec - start_tv_sec) * 1000 + + (tv_usec - start_tv_usec) / 1000; + + if (!_dbus_connection_get_is_connected_unlocked (connection)) + { + DBusMessage *error_msg; + + error_msg = generate_local_error_message (client_serial, + DBUS_ERROR_DISCONNECTED, + "Connection was disconnected before a reply was received"); + + /* on OOM error_msg is set to NULL */ + complete_pending_call_and_unlock (connection, pending, error_msg); + dbus_pending_call_unref (pending); + return; + } + else if (connection->disconnect_message_link == NULL) + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): disconnected\n"); + else if (timeout == NULL) + { + if (status == DBUS_DISPATCH_NEED_MEMORY) + { + /* Try sleeping a bit, as we aren't sure we need to block for reading, + * we may already have a reply in the buffer and just can't process + * it. + */ + _dbus_verbose ("dbus_connection_send_with_reply_and_block() waiting for more memory\n"); + + _dbus_memory_pause_based_on_timeout (timeout_milliseconds - elapsed_milliseconds); + } + else + { + /* block again, we don't have the reply buffered yet. */ + _dbus_connection_do_iteration_unlocked (connection, + DBUS_ITERATION_DO_READING | + DBUS_ITERATION_BLOCK, + timeout_milliseconds - elapsed_milliseconds); + } + + goto recheck_status; + } + else if (tv_sec < start_tv_sec) + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): clock set backward\n"); + else if (elapsed_milliseconds < timeout_milliseconds) + { + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): %d milliseconds remain\n", timeout_milliseconds - elapsed_milliseconds); + + if (status == DBUS_DISPATCH_NEED_MEMORY) + { + /* Try sleeping a bit, as we aren't sure we need to block for reading, + * we may already have a reply in the buffer and just can't process + * it. + */ + _dbus_verbose ("dbus_connection_send_with_reply_and_block() waiting for more memory\n"); + + _dbus_memory_pause_based_on_timeout (timeout_milliseconds - elapsed_milliseconds); + } + else + { + /* block again, we don't have the reply buffered yet. */ + _dbus_connection_do_iteration_unlocked (connection, + DBUS_ITERATION_DO_READING | + DBUS_ITERATION_BLOCK, + timeout_milliseconds - elapsed_milliseconds); + } + + goto recheck_status; + } + + _dbus_verbose ("dbus_connection_send_with_reply_and_block(): Waited %d milliseconds and got no reply\n", + elapsed_milliseconds); + + _dbus_assert (!_dbus_pending_call_get_completed_unlocked (pending)); + + /* unlock and call user code */ + complete_pending_call_and_unlock (connection, pending, NULL); + + /* update user code on dispatch status */ + CONNECTION_LOCK (connection); + status = _dbus_connection_get_dispatch_status_unlocked (connection); + _dbus_connection_update_dispatch_status_and_unlock (connection, status); + dbus_pending_call_unref (pending); +} + +/** @} */ + +/** + * @addtogroup DBusConnection + * + * @{ + */ + +/** + * Gets a connection to a remote address. If a connection to the given + * address already exists, returns the existing connection with its + * reference count incremented. Otherwise, returns a new connection + * and saves the new connection for possible re-use if a future call + * to dbus_connection_open() asks to connect to the same server. + * + * Use dbus_connection_open_private() to get a dedicated connection + * not shared with other callers of dbus_connection_open(). + * + * If the open fails, the function returns #NULL, and provides a + * reason for the failure in the error parameter. Pass #NULL for the + * error parameter if you aren't interested in the reason for + * failure. + * + * Because this connection is shared, no user of the connection + * may call dbus_connection_close(). However, when you are done with the + * connection you should call dbus_connection_unref(). + * + * @note Prefer dbus_connection_open() to dbus_connection_open_private() + * unless you have good reason; connections are expensive enough + * that it's wasteful to create lots of connections to the same + * server. + * + * @param address the address. + * @param error address where an error can be returned. + * @returns new connection, or #NULL on failure. + */ +DBusConnection* +dbus_connection_open (const char *address, + DBusError *error) +{ + DBusConnection *connection; + + _dbus_return_val_if_fail (address != NULL, NULL); + _dbus_return_val_if_error_is_set (error, NULL); + + connection = _dbus_connection_open_internal (address, + TRUE, + error); + + return connection; +} + +/** + * Opens a new, dedicated connection to a remote address. Unlike + * dbus_connection_open(), always creates a new connection. + * This connection will not be saved or recycled by libdbus. + * + * If the open fails, the function returns #NULL, and provides a + * reason for the failure in the error parameter. Pass #NULL for the + * error parameter if you aren't interested in the reason for + * failure. + * + * When you are done with this connection, you must + * dbus_connection_close() to disconnect it, + * and dbus_connection_unref() to free the connection object. + * + * (The dbus_connection_close() can be skipped if the + * connection is already known to be disconnected, for example + * if you are inside a handler for the Disconnected signal.) + * + * @note Prefer dbus_connection_open() to dbus_connection_open_private() + * unless you have good reason; connections are expensive enough + * that it's wasteful to create lots of connections to the same + * server. + * + * @param address the address. + * @param error address where an error can be returned. + * @returns new connection, or #NULL on failure. + */ +DBusConnection* +dbus_connection_open_private (const char *address, + DBusError *error) +{ + DBusConnection *connection; + + _dbus_return_val_if_fail (address != NULL, NULL); + _dbus_return_val_if_error_is_set (error, NULL); + + connection = _dbus_connection_open_internal (address, + FALSE, + error); + + return connection; +} + +/** + * Increments the reference count of a DBusConnection. + * + * @param connection the connection. + * @returns the connection. + */ +DBusConnection * +dbus_connection_ref (DBusConnection *connection) +{ + _dbus_return_val_if_fail (connection != NULL, NULL); + _dbus_return_val_if_fail (connection->generation == _dbus_current_generation, NULL); + + /* The connection lock is better than the global + * lock in the atomic increment fallback + */ + +#ifdef DBUS_HAVE_ATOMIC_INT + _dbus_atomic_inc (&connection->refcount); +#else + CONNECTION_LOCK (connection); + _dbus_assert (connection->refcount.value > 0); + + connection->refcount.value += 1; + CONNECTION_UNLOCK (connection); +#endif + + return connection; +} + +static void +free_outgoing_message (void *element, + void *data) +{ + DBusMessage *message = element; + DBusConnection *connection = data; + + _dbus_message_remove_size_counter (message, + connection->outgoing_counter, + NULL); + dbus_message_unref (message); +} + +/* This is run without the mutex held, but after the last reference + * to the connection has been dropped we should have no thread-related + * problems + */ +static void +_dbus_connection_last_unref (DBusConnection *connection) +{ + DBusList *link; + + _dbus_verbose ("Finalizing connection %p\n", connection); + + _dbus_assert (connection->refcount.value == 0); + + /* You have to disconnect the connection before unref:ing it. Otherwise + * you won't get the disconnected message. + */ + _dbus_assert (!_dbus_transport_get_is_connected (connection->transport)); + _dbus_assert (connection->server_guid == NULL); + + /* ---- We're going to call various application callbacks here, hope it doesn't break anything... */ + _dbus_object_tree_free_all_unlocked (connection->objects); + + dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); + dbus_connection_set_wakeup_main_function (connection, NULL, NULL, NULL); + dbus_connection_set_unix_user_function (connection, NULL, NULL, NULL); + + _dbus_watch_list_free (connection->watches); + connection->watches = NULL; + + _dbus_timeout_list_free (connection->timeouts); + connection->timeouts = NULL; + + _dbus_data_slot_list_free (&connection->slot_list); + + link = _dbus_list_get_first_link (&connection->filter_list); + while (link != NULL) + { + DBusMessageFilter *filter = link->data; + DBusList *next = _dbus_list_get_next_link (&connection->filter_list, link); + + filter->function = NULL; + _dbus_message_filter_unref (filter); /* calls app callback */ + link->data = NULL; + + link = next; + } + _dbus_list_clear (&connection->filter_list); + + /* ---- Done with stuff that invokes application callbacks */ + + _dbus_object_tree_unref (connection->objects); + + _dbus_hash_table_unref (connection->pending_replies); + connection->pending_replies = NULL; + + _dbus_list_clear (&connection->filter_list); + + _dbus_list_foreach (&connection->outgoing_messages, + free_outgoing_message, + connection); + _dbus_list_clear (&connection->outgoing_messages); + + _dbus_list_foreach (&connection->incoming_messages, + (DBusForeachFunction) dbus_message_unref, + NULL); + _dbus_list_clear (&connection->incoming_messages); + + _dbus_counter_unref (connection->outgoing_counter); + + _dbus_transport_unref (connection->transport); + + if (connection->disconnect_message_link) + { + DBusMessage *message = connection->disconnect_message_link->data; + dbus_message_unref (message); + _dbus_list_free_link (connection->disconnect_message_link); + } + + _dbus_list_clear (&connection->link_cache); + + _dbus_condvar_free_at_location (&connection->dispatch_cond); + _dbus_condvar_free_at_location (&connection->io_path_cond); + + _dbus_mutex_free_at_location (&connection->io_path_mutex); + _dbus_mutex_free_at_location (&connection->dispatch_mutex); + + _dbus_mutex_free_at_location (&connection->mutex); + + dbus_free (connection); +} + +/** + * Decrements the reference count of a DBusConnection, and finalizes + * it if the count reaches zero. + * + * Note: it is a bug to drop the last reference to a connection that + * is still connected. + * + * For shared connections, libdbus will own a reference + * as long as the connection is connected, so you can know that either + * you don't have the last reference, or it's OK to drop the last reference. + * Most connections are shared. dbus_connection_open() and dbus_bus_get() + * return shared connections. + * + * For private connections, the creator of the connection must arrange for + * dbus_connection_close() to be called prior to dropping the last reference. + * Private connections come from dbus_connection_open_private() or dbus_bus_get_private(). + * + * @param connection the connection. + */ +void +dbus_connection_unref (DBusConnection *connection) +{ + dbus_bool_t last_unref; + + _dbus_return_if_fail (connection != NULL); + _dbus_return_if_fail (connection->generation == _dbus_current_generation); + + /* The connection lock is better than the global + * lock in the atomic increment fallback + */ + +#ifdef DBUS_HAVE_ATOMIC_INT + last_unref = (_dbus_atomic_dec (&connection->refcount) == 1); +#else + CONNECTION_LOCK (connection); + + _dbus_assert (connection->refcount.value > 0); + + connection->refcount.value -= 1; + last_unref = (connection->refcount.value == 0); + +#if 0 + printf ("unref() connection %p count = %d\n", connection, connection->refcount.value); +#endif + + CONNECTION_UNLOCK (connection); +#endif + + if (last_unref) + { +#ifndef DBUS_DISABLE_CHECKS + if (_dbus_transport_get_is_connected (connection->transport)) + { + _dbus_warn_check_failed ("The last reference on a connection was dropped without closing the connection. This is a bug in an application. See dbus_connection_unref() documentation for details.\n%s", + connection->shareable ? + "Most likely, the application called unref() too many times and removed a reference belonging to libdbus, since this is a shared connection.\n" : + "Most likely, the application was supposed to call dbus_connection_close(), since this is a private connection.\n"); + return; + } +#endif + _dbus_connection_last_unref (connection); + } +} + +/* + * Note that the transport can disconnect itself (other end drops us) + * and in that case this function never runs. So this function must + * not do anything more than disconnect the transport and update the + * dispatch status. + * + * If the transport self-disconnects, then we assume someone will + * dispatch the connection to cause the dispatch status update. + */ +static void +_dbus_connection_close_possibly_shared_and_unlock (DBusConnection *connection) +{ + DBusDispatchStatus status; + + HAVE_LOCK_CHECK (connection); + + _dbus_verbose ("Disconnecting %p\n", connection); + + /* We need to ref because update_dispatch_status_and_unlock will unref + * the connection if it was shared and libdbus was the only remaining + * refcount holder. + */ + _dbus_connection_ref_unlocked (connection); + + _dbus_transport_disconnect (connection->transport); + + /* This has the side effect of queuing the disconnect message link + * (unless we don't have enough memory, possibly, so don't assert it). + * After the disconnect message link is queued, dbus_bus_get/dbus_connection_open + * should never again return the newly-disconnected connection. + * + * However, we only unref the shared connection and exit_on_disconnect when + * the disconnect message reaches the head of the message queue, + * NOT when it's first queued. + */ + status = _dbus_connection_get_dispatch_status_unlocked (connection); + + /* This calls out to user code */ + _dbus_connection_update_dispatch_status_and_unlock (connection, status); + + /* Could also call out to user code */ + dbus_connection_unref (connection); +} + +/** + * Closes a private connection, so no further data can be sent or received. + * This disconnects the transport (such as a socket) underlying the + * connection. + * + * Attempts to send messages after closing a connection are safe, but will result in + * error replies generated locally in libdbus. + * + * This function does not affect the connection's reference count. It's + * safe to close a connection more than once; all calls after the + * first do nothing. It's impossible to "reopen" a connection, a + * new connection must be created. This function may result in a call + * to the DBusDispatchStatusFunction set with + * dbus_connection_set_dispatch_status_function(), as the disconnect + * message it generates needs to be dispatched. + * + * If a connection is dropped by the remote application, it will + * close itself. + * + * You must close a connection prior to releasing the last reference to + * the connection. If you dbus_connection_unref() for the last time + * without closing the connection, the results are undefined; it + * is a bug in your program and libdbus will try to print a warning. + * + * You may not close a shared connection. Connections created with + * dbus_connection_open() or dbus_bus_get() are shared. + * These connections are owned by libdbus, and applications should + * only unref them, never close them. Applications can know it is + * safe to unref these connections because libdbus will be holding a + * reference as long as the connection is open. Thus, either the + * connection is closed and it is OK to drop the last reference, + * or the connection is open and the app knows it does not have the + * last reference. + * + * Connections created with dbus_connection_open_private() or + * dbus_bus_get_private() are not kept track of or referenced by + * libdbus. The creator of these connections is responsible for + * calling dbus_connection_close() prior to releasing the last + * reference, if the connection is not already disconnected. + * + * @param connection the private (unshared) connection to close + */ +void +dbus_connection_close (DBusConnection *connection) +{ + _dbus_return_if_fail (connection != NULL); + _dbus_return_if_fail (connection->generation == _dbus_current_generation); + + CONNECTION_LOCK (connection); + +#ifndef DBUS_DISABLE_CHECKS + if (connection->shareable) + { + CONNECTION_UNLOCK (connection); + + _dbus_warn_check_failed ("Applications must not close shared connections - see dbus_connection_close() docs. This is a bug in the application.\n"); + return; + } +#endif + + _dbus_connection_close_possibly_shared_and_unlock (connection); +} + +static dbus_bool_t +_dbus_connection_get_is_connected_unlocked (DBusConnection *connection) +{ + HAVE_LOCK_CHECK (connection); + return _dbus_transport_get_is_connected (connection->transport); +} + +/** + * Gets whether the connection is currently open. A connection may + * become disconnected when the remote application closes its end, or + * exits; a connection may also be disconnected with + * dbus_connection_close(). + * + * There are not separate states for "closed" and "disconnected," the two + * terms are synonymous. This function should really be called + * get_is_open() but for historical reasons is not. + * + * @param connection the connection. + * @returns #TRUE if the connection is still alive. + */ +dbus_bool_t +dbus_connection_get_is_connected (DBusConnection *connection) +{ + dbus_bool_t res; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + + CONNECTION_LOCK (connection); + res = _dbus_connection_get_is_connected_unlocked (connection); + CONNECTION_UNLOCK (connection); + + return res; +} + +/** + * Gets whether the connection was authenticated. (Note that + * if the connection was authenticated then disconnected, + * this function still returns #TRUE) + * + * @param connection the connection + * @returns #TRUE if the connection was ever authenticated + */ +dbus_bool_t +dbus_connection_get_is_authenticated (DBusConnection *connection) +{ + dbus_bool_t res; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + + CONNECTION_LOCK (connection); + res = _dbus_transport_get_is_authenticated (connection->transport); + CONNECTION_UNLOCK (connection); + + return res; +} + +/** + * Gets whether the connection is not authenticated as a specific + * user. If the connection is not authenticated, this function + * returns #TRUE, and if it is authenticated but as an anonymous user, + * it returns #TRUE. If it is authenticated as a specific user, then + * this returns #FALSE. (Note that if the connection was authenticated + * as anonymous then disconnected, this function still returns #TRUE.) + * + * If the connection is not anonymous, you can use + * dbus_connection_get_unix_user() and + * dbus_connection_get_windows_user() to see who it's authorized as. + * + * If you want to prevent non-anonymous authorization, use + * dbus_server_set_auth_mechanisms() to remove the mechanisms that + * allow proving user identity (i.e. only allow the ANONYMOUS + * mechanism). + * + * @param connection the connection + * @returns #TRUE if not authenticated or authenticated as anonymous + */ +dbus_bool_t +dbus_connection_get_is_anonymous (DBusConnection *connection) +{ + dbus_bool_t res; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + + CONNECTION_LOCK (connection); + res = _dbus_transport_get_is_anonymous (connection->transport); + CONNECTION_UNLOCK (connection); + + return res; +} + +/** + * Gets the ID of the server address we are authenticated to, if this + * connection is on the client side. If the connection is on the + * server side, this will always return #NULL - use dbus_server_get_id() + * to get the ID of your own server, if you are the server side. + * + * If a client-side connection is not authenticated yet, the ID may be + * available if it was included in the server address, but may not be + * available. The only way to be sure the server ID is available + * is to wait for authentication to complete. + * + * In general, each mode of connecting to a given server will have + * its own ID. So for example, if the session bus daemon is listening + * on UNIX domain sockets and on TCP, then each of those modalities + * will have its own server ID. + * + * If you want an ID that identifies an entire session bus, look at + * dbus_bus_get_id() instead (which is just a convenience wrapper + * around the org.freedesktop.DBus.GetId method invoked on the bus). + * + * You can also get a machine ID; see dbus_get_local_machine_id() to + * get the machine you are on. There isn't a convenience wrapper, but + * you can invoke org.freedesktop.DBus.Peer.GetMachineId on any peer + * to get the machine ID on the other end. + * + * The D-Bus specification describes the server ID and other IDs in a + * bit more detail. + * + * @param connection the connection + * @returns the server ID or #NULL if no memory or the connection is server-side + */ +char* +dbus_connection_get_server_id (DBusConnection *connection) +{ + char *id; + + _dbus_return_val_if_fail (connection != NULL, NULL); + + CONNECTION_LOCK (connection); + id = _dbus_strdup (_dbus_transport_get_server_id (connection->transport)); + CONNECTION_UNLOCK (connection); + + return id; +} + +/** + * Set whether _exit() should be called when the connection receives a + * disconnect signal. The call to _exit() comes after any handlers for + * the disconnect signal run; handlers can cancel the exit by calling + * this function. + * + * By default, exit_on_disconnect is #FALSE; but for message bus + * connections returned from dbus_bus_get() it will be toggled on + * by default. + * + * @param connection the connection + * @param exit_on_disconnect #TRUE if _exit() should be called after a disconnect signal + */ +void +dbus_connection_set_exit_on_disconnect (DBusConnection *connection, + dbus_bool_t exit_on_disconnect) +{ + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + connection->exit_on_disconnect = exit_on_disconnect != FALSE; + CONNECTION_UNLOCK (connection); +} + +/** + * Preallocates resources needed to send a message, allowing the message + * to be sent without the possibility of memory allocation failure. + * Allows apps to create a future guarantee that they can send + * a message regardless of memory shortages. + * + * @param connection the connection we're preallocating for. + * @returns the preallocated resources, or #NULL + */ +DBusPreallocatedSend* +dbus_connection_preallocate_send (DBusConnection *connection) +{ + DBusPreallocatedSend *preallocated; + + _dbus_return_val_if_fail (connection != NULL, NULL); + + CONNECTION_LOCK (connection); + + preallocated = + _dbus_connection_preallocate_send_unlocked (connection); + + CONNECTION_UNLOCK (connection); + + return preallocated; +} + +/** + * Frees preallocated message-sending resources from + * dbus_connection_preallocate_send(). Should only + * be called if the preallocated resources are not used + * to send a message. + * + * @param connection the connection + * @param preallocated the resources + */ +void +dbus_connection_free_preallocated_send (DBusConnection *connection, + DBusPreallocatedSend *preallocated) +{ + _dbus_return_if_fail (connection != NULL); + _dbus_return_if_fail (preallocated != NULL); + _dbus_return_if_fail (connection == preallocated->connection); + + _dbus_list_free_link (preallocated->queue_link); + _dbus_counter_unref (preallocated->counter_link->data); + _dbus_list_free_link (preallocated->counter_link); + dbus_free (preallocated); +} + +/** + * Sends a message using preallocated resources. This function cannot fail. + * It works identically to dbus_connection_send() in other respects. + * Preallocated resources comes from dbus_connection_preallocate_send(). + * This function "consumes" the preallocated resources, they need not + * be freed separately. + * + * @param connection the connection + * @param preallocated the preallocated resources + * @param message the message to send + * @param client_serial return location for client serial assigned to the message + */ +void +dbus_connection_send_preallocated (DBusConnection *connection, + DBusPreallocatedSend *preallocated, + DBusMessage *message, + dbus_uint32_t *client_serial) +{ + _dbus_return_if_fail (connection != NULL); + _dbus_return_if_fail (preallocated != NULL); + _dbus_return_if_fail (message != NULL); + _dbus_return_if_fail (preallocated->connection == connection); + _dbus_return_if_fail (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL || + dbus_message_get_member (message) != NULL); + _dbus_return_if_fail (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL || + (dbus_message_get_interface (message) != NULL && + dbus_message_get_member (message) != NULL)); + + CONNECTION_LOCK (connection); + _dbus_connection_send_preallocated_and_unlock (connection, + preallocated, + message, client_serial); +} + +static dbus_bool_t +_dbus_connection_send_unlocked_no_update (DBusConnection *connection, + DBusMessage *message, + dbus_uint32_t *client_serial) +{ + DBusPreallocatedSend *preallocated; + + _dbus_assert (connection != NULL); + _dbus_assert (message != NULL); + + preallocated = _dbus_connection_preallocate_send_unlocked (connection); + if (preallocated == NULL) + return FALSE; + + _dbus_connection_send_preallocated_unlocked_no_update (connection, + preallocated, + message, + client_serial); + return TRUE; +} + +/** + * Adds a message to the outgoing message queue. Does not block to + * write the message to the network; that happens asynchronously. To + * force the message to be written, call dbus_connection_flush() however + * it is not necessary to call dbus_connection_flush() by hand; the + * message will be sent the next time the main loop is run. + * dbus_connection_flush() should only be used, for example, if + * the application was expected to exit before running the main loop. + * + * Because this only queues the message, the only reason it can + * fail is lack of memory. Even if the connection is disconnected, + * no error will be returned. If the function fails due to lack of memory, + * it returns #FALSE. The function will never fail for other reasons; even + * if the connection is disconnected, you can queue an outgoing message, + * though obviously it won't be sent. + * + * The message serial is used by the remote application to send a + * reply; see dbus_message_get_serial() or the D-Bus specification. + * + * dbus_message_unref() can be called as soon as this method returns + * as the message queue will hold its own ref until the message is sent. + * + * @param connection the connection. + * @param message the message to write. + * @param serial return location for message serial, or #NULL if you don't care + * @returns #TRUE on success. + */ +dbus_bool_t +dbus_connection_send (DBusConnection *connection, + DBusMessage *message, + dbus_uint32_t *serial) +{ + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (message != NULL, FALSE); + + CONNECTION_LOCK (connection); + + return _dbus_connection_send_and_unlock (connection, + message, + serial); +} + +static dbus_bool_t +reply_handler_timeout (void *data) +{ + DBusConnection *connection; + DBusDispatchStatus status; + DBusPendingCall *pending = data; + + connection = _dbus_pending_call_get_connection_and_lock (pending); + + _dbus_pending_call_queue_timeout_error_unlocked (pending, + connection); + _dbus_connection_remove_timeout_unlocked (connection, + _dbus_pending_call_get_timeout_unlocked (pending)); + _dbus_pending_call_set_timeout_added_unlocked (pending, FALSE); + + _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); + status = _dbus_connection_get_dispatch_status_unlocked (connection); + + /* Unlocks, and calls out to user code */ + _dbus_connection_update_dispatch_status_and_unlock (connection, status); + + return TRUE; +} + +/** + * Queues a message to send, as with dbus_connection_send(), + * but also returns a #DBusPendingCall used to receive a reply to the + * message. If no reply is received in the given timeout_milliseconds, + * this function expires the pending reply and generates a synthetic + * error reply (generated in-process, not by the remote application) + * indicating that a timeout occurred. + * + * A #DBusPendingCall will see a reply message before any filters or + * registered object path handlers. See dbus_connection_dispatch() for + * details on when handlers are run. + * + * A #DBusPendingCall will always see exactly one reply message, + * unless it's cancelled with dbus_pending_call_cancel(). + * + * If #NULL is passed for the pending_return, the #DBusPendingCall + * will still be generated internally, and used to track + * the message reply timeout. This means a timeout error will + * occur if no reply arrives, unlike with dbus_connection_send(). + * + * If -1 is passed for the timeout, a sane default timeout is used. -1 + * is typically the best value for the timeout for this reason, unless + * you want a very short or very long timeout. If INT_MAX is passed for + * the timeout, no timeout will be set and the call will block forever. + * + * @warning if the connection is disconnected, the #DBusPendingCall + * will be set to #NULL, so be careful with this. + * + * @param connection the connection + * @param message the message to send + * @param pending_return return location for a #DBusPendingCall object, or #NULL if connection is disconnected + * @param timeout_milliseconds timeout in milliseconds, -1 for default or INT_MAX for no timeout + * @returns #FALSE if no memory, #TRUE otherwise. + * + */ +dbus_bool_t +dbus_connection_send_with_reply (DBusConnection *connection, + DBusMessage *message, + DBusPendingCall **pending_return, + int timeout_milliseconds) +{ + DBusPendingCall *pending; + dbus_int32_t serial = -1; + DBusDispatchStatus status; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); + + if (pending_return) + *pending_return = NULL; + + CONNECTION_LOCK (connection); + + if (!_dbus_connection_get_is_connected_unlocked (connection)) + { + CONNECTION_UNLOCK (connection); + + return TRUE; + } + + pending = _dbus_pending_call_new_unlocked (connection, + timeout_milliseconds, + reply_handler_timeout); + + if (pending == NULL) + { + CONNECTION_UNLOCK (connection); + return FALSE; + } + + /* Assign a serial to the message */ + serial = dbus_message_get_serial (message); + if (serial == 0) + { + serial = _dbus_connection_get_next_client_serial (connection); + dbus_message_set_serial (message, serial); + } + + if (!_dbus_pending_call_set_timeout_error_unlocked (pending, message, serial)) + goto error; + + /* Insert the serial in the pending replies hash; + * hash takes a refcount on DBusPendingCall. + * Also, add the timeout. + */ + if (!_dbus_connection_attach_pending_call_unlocked (connection, + pending)) + goto error; + + if (!_dbus_connection_send_unlocked_no_update (connection, message, NULL)) + { + _dbus_connection_detach_pending_call_and_unlock (connection, + pending); + goto error_unlocked; + } + + if (pending_return) + *pending_return = pending; /* hand off refcount */ + else + { + _dbus_connection_detach_pending_call_unlocked (connection, pending); + /* we still have a ref to the pending call in this case, we unref + * after unlocking, below + */ + } + + status = _dbus_connection_get_dispatch_status_unlocked (connection); + + /* this calls out to user code */ + _dbus_connection_update_dispatch_status_and_unlock (connection, status); + + if (pending_return == NULL) + dbus_pending_call_unref (pending); + + return TRUE; + + error: + CONNECTION_UNLOCK (connection); + error_unlocked: + dbus_pending_call_unref (pending); + return FALSE; +} + +/** + * Sends a message and blocks a certain time period while waiting for + * a reply. This function does not reenter the main loop, + * i.e. messages other than the reply are queued up but not + * processed. This function is used to invoke method calls on a + * remote object. + * + * If a normal reply is received, it is returned, and removed from the + * incoming message queue. If it is not received, #NULL is returned + * and the error is set to #DBUS_ERROR_NO_REPLY. If an error reply is + * received, it is converted to a #DBusError and returned as an error, + * then the reply message is deleted and #NULL is returned. If + * something else goes wrong, result is set to whatever is + * appropriate, such as #DBUS_ERROR_NO_MEMORY or + * #DBUS_ERROR_DISCONNECTED. + * + * @warning While this function blocks the calling thread will not be + * processing the incoming message queue. This means you can end up + * deadlocked if the application you're talking to needs you to reply + * to a method. To solve this, either avoid the situation, block in a + * separate thread from the main connection-dispatching thread, or use + * dbus_pending_call_set_notify() to avoid blocking. + * + * @param connection the connection + * @param message the message to send + * @param timeout_milliseconds timeout in milliseconds, -1 for default or INT_MAX for no timeout. + * @param error return location for error message + * @returns the message that is the reply or #NULL with an error code if the + * function fails. + */ +DBusMessage* +dbus_connection_send_with_reply_and_block (DBusConnection *connection, + DBusMessage *message, + int timeout_milliseconds, + DBusError *error) +{ + DBusMessage *reply; + DBusPendingCall *pending; + + _dbus_return_val_if_fail (connection != NULL, NULL); + _dbus_return_val_if_fail (message != NULL, NULL); + _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, NULL); + _dbus_return_val_if_error_is_set (error, NULL); + + if (!dbus_connection_send_with_reply (connection, message, + &pending, timeout_milliseconds)) + { + _DBUS_SET_OOM (error); + return NULL; + } + + if (pending == NULL) + { + dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Connection is closed"); + return NULL; + } + + dbus_pending_call_block (pending); + + reply = dbus_pending_call_steal_reply (pending); + dbus_pending_call_unref (pending); + + /* call_complete_and_unlock() called from pending_call_block() should + * always fill this in. + */ + _dbus_assert (reply != NULL); + + if (dbus_set_error_from_message (error, reply)) + { + dbus_message_unref (reply); + return NULL; + } + else + return reply; +} + +/** + * Blocks until the outgoing message queue is empty. + * Assumes connection lock already held. + * + * If you call this, you MUST call update_dispatch_status afterword... + * + * @param connection the connection. + */ +static DBusDispatchStatus +_dbus_connection_flush_unlocked (DBusConnection *connection) +{ + /* We have to specify DBUS_ITERATION_DO_READING here because + * otherwise we could have two apps deadlock if they are both doing + * a flush(), and the kernel buffers fill up. This could change the + * dispatch status. + */ + DBusDispatchStatus status; + + HAVE_LOCK_CHECK (connection); + + while (connection->n_outgoing > 0 && + _dbus_connection_get_is_connected_unlocked (connection)) + { + _dbus_verbose ("doing iteration in %s\n", _DBUS_FUNCTION_NAME); + HAVE_LOCK_CHECK (connection); + _dbus_connection_do_iteration_unlocked (connection, + DBUS_ITERATION_DO_READING | + DBUS_ITERATION_DO_WRITING | + DBUS_ITERATION_BLOCK, + -1); + } + + HAVE_LOCK_CHECK (connection); + _dbus_verbose ("%s middle\n", _DBUS_FUNCTION_NAME); + status = _dbus_connection_get_dispatch_status_unlocked (connection); + + HAVE_LOCK_CHECK (connection); + return status; +} + +/** + * Blocks until the outgoing message queue is empty. + * + * @param connection the connection. + */ +void +dbus_connection_flush (DBusConnection *connection) +{ + /* We have to specify DBUS_ITERATION_DO_READING here because + * otherwise we could have two apps deadlock if they are both doing + * a flush(), and the kernel buffers fill up. This could change the + * dispatch status. + */ + DBusDispatchStatus status; + + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + + status = _dbus_connection_flush_unlocked (connection); + + HAVE_LOCK_CHECK (connection); + /* Unlocks and calls out to user code */ + _dbus_connection_update_dispatch_status_and_unlock (connection, status); + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); +} + +/** + * This function implements dbus_connection_read_write_dispatch() and + * dbus_connection_read_write() (they pass a different value for the + * dispatch parameter). + * + * @param connection the connection + * @param timeout_milliseconds max time to block or -1 for infinite + * @param dispatch dispatch new messages or leave them on the incoming queue + * @returns #TRUE if the disconnect message has not been processed + */ +static dbus_bool_t +_dbus_connection_read_write_dispatch (DBusConnection *connection, + int timeout_milliseconds, + dbus_bool_t dispatch) +{ + DBusDispatchStatus dstatus; + dbus_bool_t progress_possible; + + /* Need to grab a ref here in case we're a private connection and + * the user drops the last ref in a handler we call; see bug + * https://bugs.freedesktop.org/show_bug.cgi?id=15635 + */ + dbus_connection_ref (connection); + dstatus = dbus_connection_get_dispatch_status (connection); + + if (dispatch && dstatus == DBUS_DISPATCH_DATA_REMAINS) + { + _dbus_verbose ("doing dispatch in %s\n", _DBUS_FUNCTION_NAME); + dbus_connection_dispatch (connection); + CONNECTION_LOCK (connection); + } + else if (dstatus == DBUS_DISPATCH_NEED_MEMORY) + { + _dbus_verbose ("pausing for memory in %s\n", _DBUS_FUNCTION_NAME); + _dbus_memory_pause_based_on_timeout (timeout_milliseconds); + CONNECTION_LOCK (connection); + } + else + { + CONNECTION_LOCK (connection); + if (_dbus_connection_get_is_connected_unlocked (connection)) + { + _dbus_verbose ("doing iteration in %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_do_iteration_unlocked (connection, + DBUS_ITERATION_DO_READING | + DBUS_ITERATION_DO_WRITING | + DBUS_ITERATION_BLOCK, + timeout_milliseconds); + } + } + + HAVE_LOCK_CHECK (connection); + /* If we can dispatch, we can make progress until the Disconnected message + * has been processed; if we can only read/write, we can make progress + * as long as the transport is open. + */ + if (dispatch) + progress_possible = connection->n_incoming != 0 || + connection->disconnect_message_link != NULL; + else + progress_possible = _dbus_connection_get_is_connected_unlocked (connection); + + CONNECTION_UNLOCK (connection); + + dbus_connection_unref (connection); + + return progress_possible; /* TRUE if we can make more progress */ +} + + +/** + * This function is intended for use with applications that don't want + * to write a main loop and deal with #DBusWatch and #DBusTimeout. An + * example usage would be: + * + * @code + * while (dbus_connection_read_write_dispatch (connection, -1)) + * ; // empty loop body + * @endcode + * + * In this usage you would normally have set up a filter function to look + * at each message as it is dispatched. The loop terminates when the last + * message from the connection (the disconnected signal) is processed. + * + * If there are messages to dispatch, this function will + * dbus_connection_dispatch() once, and return. If there are no + * messages to dispatch, this function will block until it can read or + * write, then read or write, then return. + * + * The way to think of this function is that it either makes some sort + * of progress, or it blocks. Note that, while it is blocked on I/O, it + * cannot be interrupted (even by other threads), which makes this function + * unsuitable for applications that do more than just react to received + * messages. + * + * The return value indicates whether the disconnect message has been + * processed, NOT whether the connection is connected. This is + * important because even after disconnecting, you want to process any + * messages you received prior to the disconnect. + * + * @param connection the connection + * @param timeout_milliseconds max time to block or -1 for infinite + * @returns #TRUE if the disconnect message has not been processed + */ +dbus_bool_t +dbus_connection_read_write_dispatch (DBusConnection *connection, + int timeout_milliseconds) +{ + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); + return _dbus_connection_read_write_dispatch(connection, timeout_milliseconds, TRUE); +} + +/** + * This function is intended for use with applications that don't want to + * write a main loop and deal with #DBusWatch and #DBusTimeout. See also + * dbus_connection_read_write_dispatch(). + * + * As long as the connection is open, this function will block until it can + * read or write, then read or write, then return #TRUE. + * + * If the connection is closed, the function returns #FALSE. + * + * The return value indicates whether reading or writing is still + * possible, i.e. whether the connection is connected. + * + * Note that even after disconnection, messages may remain in the + * incoming queue that need to be + * processed. dbus_connection_read_write_dispatch() dispatches + * incoming messages for you; with dbus_connection_read_write() you + * have to arrange to drain the incoming queue yourself. + * + * @param connection the connection + * @param timeout_milliseconds max time to block or -1 for infinite + * @returns #TRUE if still connected + */ +dbus_bool_t +dbus_connection_read_write (DBusConnection *connection, + int timeout_milliseconds) +{ + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE); + return _dbus_connection_read_write_dispatch(connection, timeout_milliseconds, FALSE); +} + +/* We need to call this anytime we pop the head of the queue, and then + * update_dispatch_status_and_unlock needs to be called afterward + * which will "process" the disconnected message and set + * disconnected_message_processed. + */ +static void +check_disconnected_message_arrived_unlocked (DBusConnection *connection, + DBusMessage *head_of_queue) +{ + HAVE_LOCK_CHECK (connection); + + /* checking that the link is NULL is an optimization to avoid the is_signal call */ + if (connection->disconnect_message_link == NULL && + dbus_message_is_signal (head_of_queue, + DBUS_INTERFACE_LOCAL, + "Disconnected")) + { + connection->disconnected_message_arrived = TRUE; + } +} + +/** + * Returns the first-received message from the incoming message queue, + * leaving it in the queue. If the queue is empty, returns #NULL. + * + * The caller does not own a reference to the returned message, and + * must either return it using dbus_connection_return_message() or + * keep it after calling dbus_connection_steal_borrowed_message(). No + * one can get at the message while its borrowed, so return it as + * quickly as possible and don't keep a reference to it after + * returning it. If you need to keep the message, make a copy of it. + * + * dbus_connection_dispatch() will block if called while a borrowed + * message is outstanding; only one piece of code can be playing with + * the incoming queue at a time. This function will block if called + * during a dbus_connection_dispatch(). + * + * @param connection the connection. + * @returns next message in the incoming queue. + */ +DBusMessage* +dbus_connection_borrow_message (DBusConnection *connection) +{ + DBusDispatchStatus status; + DBusMessage *message; + + _dbus_return_val_if_fail (connection != NULL, NULL); + + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + + /* this is called for the side effect that it queues + * up any messages from the transport + */ + status = dbus_connection_get_dispatch_status (connection); + if (status != DBUS_DISPATCH_DATA_REMAINS) + return NULL; + + CONNECTION_LOCK (connection); + + _dbus_connection_acquire_dispatch (connection); + + /* While a message is outstanding, the dispatch lock is held */ + _dbus_assert (connection->message_borrowed == NULL); + + connection->message_borrowed = _dbus_list_get_first (&connection->incoming_messages); + + message = connection->message_borrowed; + + check_disconnected_message_arrived_unlocked (connection, message); + + /* Note that we KEEP the dispatch lock until the message is returned */ + if (message == NULL) + _dbus_connection_release_dispatch (connection); + + CONNECTION_UNLOCK (connection); + + /* We don't update dispatch status until it's returned or stolen */ + + return message; +} + +/** + * Used to return a message after peeking at it using + * dbus_connection_borrow_message(). Only called if + * message from dbus_connection_borrow_message() was non-#NULL. + * + * @param connection the connection + * @param message the message from dbus_connection_borrow_message() + */ +void +dbus_connection_return_message (DBusConnection *connection, + DBusMessage *message) +{ + DBusDispatchStatus status; + + _dbus_return_if_fail (connection != NULL); + _dbus_return_if_fail (message != NULL); + _dbus_return_if_fail (message == connection->message_borrowed); + _dbus_return_if_fail (connection->dispatch_acquired); + + CONNECTION_LOCK (connection); + + _dbus_assert (message == connection->message_borrowed); + + connection->message_borrowed = NULL; + + _dbus_connection_release_dispatch (connection); + + status = _dbus_connection_get_dispatch_status_unlocked (connection); + _dbus_connection_update_dispatch_status_and_unlock (connection, status); +} + +/** + * Used to keep a message after peeking at it using + * dbus_connection_borrow_message(). Before using this function, see + * the caveats/warnings in the documentation for + * dbus_connection_pop_message(). + * + * @param connection the connection + * @param message the message from dbus_connection_borrow_message() + */ +void +dbus_connection_steal_borrowed_message (DBusConnection *connection, + DBusMessage *message) +{ + DBusMessage *pop_message; + DBusDispatchStatus status; + + _dbus_return_if_fail (connection != NULL); + _dbus_return_if_fail (message != NULL); + _dbus_return_if_fail (message == connection->message_borrowed); + _dbus_return_if_fail (connection->dispatch_acquired); + + CONNECTION_LOCK (connection); + + _dbus_assert (message == connection->message_borrowed); + + pop_message = _dbus_list_pop_first (&connection->incoming_messages); + _dbus_assert (message == pop_message); + + connection->n_incoming -= 1; + + _dbus_verbose ("Incoming message %p stolen from queue, %d incoming\n", + message, connection->n_incoming); + + connection->message_borrowed = NULL; + + _dbus_connection_release_dispatch (connection); + + status = _dbus_connection_get_dispatch_status_unlocked (connection); + _dbus_connection_update_dispatch_status_and_unlock (connection, status); +} + +/* See dbus_connection_pop_message, but requires the caller to own + * the lock before calling. May drop the lock while running. + */ +static DBusList* +_dbus_connection_pop_message_link_unlocked (DBusConnection *connection) +{ + HAVE_LOCK_CHECK (connection); + + _dbus_assert (connection->message_borrowed == NULL); + + if (connection->n_incoming > 0) + { + DBusList *link; + + link = _dbus_list_pop_first_link (&connection->incoming_messages); + connection->n_incoming -= 1; + + _dbus_verbose ("Message %p (%d %s %s %s '%s') removed from incoming queue %p, %d incoming\n", + link->data, + dbus_message_get_type (link->data), + dbus_message_get_path (link->data) ? + dbus_message_get_path (link->data) : + "no path", + dbus_message_get_interface (link->data) ? + dbus_message_get_interface (link->data) : + "no interface", + dbus_message_get_member (link->data) ? + dbus_message_get_member (link->data) : + "no member", + dbus_message_get_signature (link->data), + connection, connection->n_incoming); + + check_disconnected_message_arrived_unlocked (connection, link->data); + + return link; + } + else + return NULL; +} + +/* See dbus_connection_pop_message, but requires the caller to own + * the lock before calling. May drop the lock while running. + */ +static DBusMessage* +_dbus_connection_pop_message_unlocked (DBusConnection *connection) +{ + DBusList *link; + + HAVE_LOCK_CHECK (connection); + + link = _dbus_connection_pop_message_link_unlocked (connection); + + if (link != NULL) + { + DBusMessage *message; + + message = link->data; + + _dbus_list_free_link (link); + + return message; + } + else + return NULL; +} + +static void +_dbus_connection_putback_message_link_unlocked (DBusConnection *connection, + DBusList *message_link) +{ + HAVE_LOCK_CHECK (connection); + + _dbus_assert (message_link != NULL); + /* You can't borrow a message while a link is outstanding */ + _dbus_assert (connection->message_borrowed == NULL); + /* We had to have the dispatch lock across the pop/putback */ + _dbus_assert (connection->dispatch_acquired); + + _dbus_list_prepend_link (&connection->incoming_messages, + message_link); + connection->n_incoming += 1; + + _dbus_verbose ("Message %p (%d %s %s '%s') put back into queue %p, %d incoming\n", + message_link->data, + dbus_message_get_type (message_link->data), + dbus_message_get_interface (message_link->data) ? + dbus_message_get_interface (message_link->data) : + "no interface", + dbus_message_get_member (message_link->data) ? + dbus_message_get_member (message_link->data) : + "no member", + dbus_message_get_signature (message_link->data), + connection, connection->n_incoming); +} + +/** + * Returns the first-received message from the incoming message queue, + * removing it from the queue. The caller owns a reference to the + * returned message. If the queue is empty, returns #NULL. + * + * This function bypasses any message handlers that are registered, + * and so using it is usually wrong. Instead, let the main loop invoke + * dbus_connection_dispatch(). Popping messages manually is only + * useful in very simple programs that don't share a #DBusConnection + * with any libraries or other modules. + * + * There is a lock that covers all ways of accessing the incoming message + * queue, so dbus_connection_dispatch(), dbus_connection_pop_message(), + * dbus_connection_borrow_message(), etc. will all block while one of the others + * in the group is running. + * + * @param connection the connection. + * @returns next message in the incoming queue. + */ +DBusMessage* +dbus_connection_pop_message (DBusConnection *connection) +{ + DBusMessage *message; + DBusDispatchStatus status; + + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + + /* this is called for the side effect that it queues + * up any messages from the transport + */ + status = dbus_connection_get_dispatch_status (connection); + if (status != DBUS_DISPATCH_DATA_REMAINS) + return NULL; + + CONNECTION_LOCK (connection); + _dbus_connection_acquire_dispatch (connection); + HAVE_LOCK_CHECK (connection); + + message = _dbus_connection_pop_message_unlocked (connection); + + _dbus_verbose ("Returning popped message %p\n", message); + + _dbus_connection_release_dispatch (connection); + + status = _dbus_connection_get_dispatch_status_unlocked (connection); + _dbus_connection_update_dispatch_status_and_unlock (connection, status); + + return message; +} + +/** + * Acquire the dispatcher. This is a separate lock so the main + * connection lock can be dropped to call out to application dispatch + * handlers. + * + * @param connection the connection. + */ +static void +_dbus_connection_acquire_dispatch (DBusConnection *connection) +{ + HAVE_LOCK_CHECK (connection); + + _dbus_connection_ref_unlocked (connection); + CONNECTION_UNLOCK (connection); + + _dbus_verbose ("%s locking dispatch_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_mutex_lock (connection->dispatch_mutex); + + while (connection->dispatch_acquired) + { + _dbus_verbose ("%s waiting for dispatch to be acquirable\n", _DBUS_FUNCTION_NAME); + _dbus_condvar_wait (connection->dispatch_cond, + connection->dispatch_mutex); + } + + _dbus_assert (!connection->dispatch_acquired); + + connection->dispatch_acquired = TRUE; + + _dbus_verbose ("%s unlocking dispatch_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_mutex_unlock (connection->dispatch_mutex); + + CONNECTION_LOCK (connection); + _dbus_connection_unref_unlocked (connection); +} + +/** + * Release the dispatcher when you're done with it. Only call + * after you've acquired the dispatcher. Wakes up at most one + * thread currently waiting to acquire the dispatcher. + * + * @param connection the connection. + */ +static void +_dbus_connection_release_dispatch (DBusConnection *connection) +{ + HAVE_LOCK_CHECK (connection); + + _dbus_verbose ("%s locking dispatch_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_mutex_lock (connection->dispatch_mutex); + + _dbus_assert (connection->dispatch_acquired); + + connection->dispatch_acquired = FALSE; + _dbus_condvar_wake_one (connection->dispatch_cond); + + _dbus_verbose ("%s unlocking dispatch_mutex\n", _DBUS_FUNCTION_NAME); + _dbus_mutex_unlock (connection->dispatch_mutex); +} + +static void +_dbus_connection_failed_pop (DBusConnection *connection, + DBusList *message_link) +{ + _dbus_list_prepend_link (&connection->incoming_messages, + message_link); + connection->n_incoming += 1; +} + +/* Note this may be called multiple times since we don't track whether we already did it */ +static void +notify_disconnected_unlocked (DBusConnection *connection) +{ + HAVE_LOCK_CHECK (connection); + + /* Set the weakref in dbus-bus.c to NULL, so nobody will get a disconnected + * connection from dbus_bus_get(). We make the same guarantee for + * dbus_connection_open() but in a different way since we don't want to + * unref right here; we instead check for connectedness before returning + * the connection from the hash. + */ + _dbus_bus_notify_shared_connection_disconnected_unlocked (connection); + + /* Dump the outgoing queue, we aren't going to be able to + * send it now, and we'd like accessors like + * dbus_connection_get_outgoing_size() to be accurate. + */ + if (connection->n_outgoing > 0) + { + DBusList *link; + + _dbus_verbose ("Dropping %d outgoing messages since we're disconnected\n", + connection->n_outgoing); + + while ((link = _dbus_list_get_last_link (&connection->outgoing_messages))) + { + _dbus_connection_message_sent (connection, link->data); + } + } +} + +/* Note this may be called multiple times since we don't track whether we already did it */ +static DBusDispatchStatus +notify_disconnected_and_dispatch_complete_unlocked (DBusConnection *connection) +{ + HAVE_LOCK_CHECK (connection); + + if (connection->disconnect_message_link != NULL) + { + _dbus_verbose ("Sending disconnect message from %s\n", + _DBUS_FUNCTION_NAME); + + /* If we have pending calls, queue their timeouts - we want the Disconnected + * to be the last message, after these timeouts. + */ + connection_timeout_and_complete_all_pending_calls_unlocked (connection); + + /* We haven't sent the disconnect message already, + * and all real messages have been queued up. + */ + _dbus_connection_queue_synthesized_message_link (connection, + connection->disconnect_message_link); + connection->disconnect_message_link = NULL; + + return DBUS_DISPATCH_DATA_REMAINS; + } + + return DBUS_DISPATCH_COMPLETE; +} + +static DBusDispatchStatus +_dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection) +{ + HAVE_LOCK_CHECK (connection); + + if (connection->n_incoming > 0) + return DBUS_DISPATCH_DATA_REMAINS; + else if (!_dbus_transport_queue_messages (connection->transport)) + return DBUS_DISPATCH_NEED_MEMORY; + else + { + DBusDispatchStatus status; + dbus_bool_t is_connected; + + status = _dbus_transport_get_dispatch_status (connection->transport); + is_connected = _dbus_transport_get_is_connected (connection->transport); + + _dbus_verbose ("dispatch status = %s is_connected = %d\n", + DISPATCH_STATUS_NAME (status), is_connected); + + if (!is_connected) + { + /* It's possible this would be better done by having an explicit + * notification from _dbus_transport_disconnect() that would + * synchronously do this, instead of waiting for the next dispatch + * status check. However, probably not good to change until it causes + * a problem. + */ + notify_disconnected_unlocked (connection); + + /* I'm not sure this is needed; the idea is that we want to + * queue the Disconnected only after we've read all the + * messages, but if we're disconnected maybe we are guaranteed + * to have read them all ? + */ + if (status == DBUS_DISPATCH_COMPLETE) + status = notify_disconnected_and_dispatch_complete_unlocked (connection); + } + + if (status != DBUS_DISPATCH_COMPLETE) + return status; + else if (connection->n_incoming > 0) + return DBUS_DISPATCH_DATA_REMAINS; + else + return DBUS_DISPATCH_COMPLETE; + } +} + +static void +_dbus_connection_update_dispatch_status_and_unlock (DBusConnection *connection, + DBusDispatchStatus new_status) +{ + dbus_bool_t changed; + DBusDispatchStatusFunction function; + void *data; + + HAVE_LOCK_CHECK (connection); + + _dbus_connection_ref_unlocked (connection); + + changed = new_status != connection->last_dispatch_status; + + connection->last_dispatch_status = new_status; + + function = connection->dispatch_status_function; + data = connection->dispatch_status_data; + + if (connection->disconnected_message_arrived && + !connection->disconnected_message_processed) + { + connection->disconnected_message_processed = TRUE; + + /* this does an unref, but we have a ref + * so we should not run the finalizer here + * inside the lock. + */ + connection_forget_shared_unlocked (connection); + + if (connection->exit_on_disconnect) + { + CONNECTION_UNLOCK (connection); + + _dbus_verbose ("Exiting on Disconnected signal\n"); + _dbus_exit (1); + _dbus_assert_not_reached ("Call to exit() returned"); + } + } + + /* We drop the lock */ + CONNECTION_UNLOCK (connection); + + if (changed && function) + { + _dbus_verbose ("Notifying of change to dispatch status of %p now %d (%s)\n", + connection, new_status, + DISPATCH_STATUS_NAME (new_status)); + (* function) (connection, new_status, data); + } + + dbus_connection_unref (connection); +} + +/** + * Gets the current state of the incoming message queue. + * #DBUS_DISPATCH_DATA_REMAINS indicates that the message queue + * may contain messages. #DBUS_DISPATCH_COMPLETE indicates that the + * incoming queue is empty. #DBUS_DISPATCH_NEED_MEMORY indicates that + * there could be data, but we can't know for sure without more + * memory. + * + * To process the incoming message queue, use dbus_connection_dispatch() + * or (in rare cases) dbus_connection_pop_message(). + * + * Note, #DBUS_DISPATCH_DATA_REMAINS really means that either we + * have messages in the queue, or we have raw bytes buffered up + * that need to be parsed. When these bytes are parsed, they + * may not add up to an entire message. Thus, it's possible + * to see a status of #DBUS_DISPATCH_DATA_REMAINS but not + * have a message yet. + * + * In particular this happens on initial connection, because all sorts + * of authentication protocol stuff has to be parsed before the + * first message arrives. + * + * @param connection the connection. + * @returns current dispatch status + */ +DBusDispatchStatus +dbus_connection_get_dispatch_status (DBusConnection *connection) +{ + DBusDispatchStatus status; + + _dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE); + + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + + CONNECTION_LOCK (connection); + + status = _dbus_connection_get_dispatch_status_unlocked (connection); + + CONNECTION_UNLOCK (connection); + + return status; +} + +/** + * Filter funtion for handling the Peer standard interface. + */ +static DBusHandlerResult +_dbus_connection_peer_filter_unlocked_no_update (DBusConnection *connection, + DBusMessage *message) +{ + if (connection->route_peer_messages && dbus_message_get_destination (message) != NULL) + { + /* This means we're letting the bus route this message */ + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + else if (dbus_message_is_method_call (message, + DBUS_INTERFACE_PEER, + "Ping")) + { + DBusMessage *ret; + dbus_bool_t sent; + + ret = dbus_message_new_method_return (message); + if (ret == NULL) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL); + + dbus_message_unref (ret); + + if (!sent) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + return DBUS_HANDLER_RESULT_HANDLED; + } + else if (dbus_message_is_method_call (message, + DBUS_INTERFACE_PEER, + "GetMachineId")) + { + DBusMessage *ret; + dbus_bool_t sent; + DBusString uuid; + + ret = dbus_message_new_method_return (message); + if (ret == NULL) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + sent = FALSE; + _dbus_string_init (&uuid); + if (_dbus_get_local_machine_uuid_encoded (&uuid)) + { + const char *v_STRING = _dbus_string_get_const_data (&uuid); + if (dbus_message_append_args (ret, + DBUS_TYPE_STRING, &v_STRING, + DBUS_TYPE_INVALID)) + { + sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL); + } + } + _dbus_string_free (&uuid); + + dbus_message_unref (ret); + + if (!sent) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + return DBUS_HANDLER_RESULT_HANDLED; + } + else if (dbus_message_has_interface (message, DBUS_INTERFACE_PEER)) + { + /* We need to bounce anything else with this interface, otherwise apps + * could start extending the interface and when we added extensions + * here to DBusConnection we'd break those apps. + */ + + DBusMessage *ret; + dbus_bool_t sent; + + ret = dbus_message_new_error (message, + DBUS_ERROR_UNKNOWN_METHOD, + "Unknown method invoked on org.freedesktop.DBus.Peer interface"); + if (ret == NULL) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL); + + dbus_message_unref (ret); + + if (!sent) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + + return DBUS_HANDLER_RESULT_HANDLED; + } + else + { + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } +} + +/** +* Processes all builtin filter functions +* +* If the spec specifies a standard interface +* they should be processed from this method +**/ +static DBusHandlerResult +_dbus_connection_run_builtin_filters_unlocked_no_update (DBusConnection *connection, + DBusMessage *message) +{ + /* We just run one filter for now but have the option to run more + if the spec calls for it in the future */ + + return _dbus_connection_peer_filter_unlocked_no_update (connection, message); +} + +/** + * Processes any incoming data. + * + * If there's incoming raw data that has not yet been parsed, it is + * parsed, which may or may not result in adding messages to the + * incoming queue. + * + * The incoming data buffer is filled when the connection reads from + * its underlying transport (such as a socket). Reading usually + * happens in dbus_watch_handle() or dbus_connection_read_write(). + * + * If there are complete messages in the incoming queue, + * dbus_connection_dispatch() removes one message from the queue and + * processes it. Processing has three steps. + * + * First, any method replies are passed to #DBusPendingCall or + * dbus_connection_send_with_reply_and_block() in order to + * complete the pending method call. + * + * Second, any filters registered with dbus_connection_add_filter() + * are run. If any filter returns #DBUS_HANDLER_RESULT_HANDLED + * then processing stops after that filter. + * + * Third, if the message is a method call it is forwarded to + * any registered object path handlers added with + * dbus_connection_register_object_path() or + * dbus_connection_register_fallback(). + * + * A single call to dbus_connection_dispatch() will process at most + * one message; it will not clear the entire message queue. + * + * Be careful about calling dbus_connection_dispatch() from inside a + * message handler, i.e. calling dbus_connection_dispatch() + * recursively. If threads have been initialized with a recursive + * mutex function, then this will not deadlock; however, it can + * certainly confuse your application. + * + * @todo some FIXME in here about handling DBUS_HANDLER_RESULT_NEED_MEMORY + * + * @param connection the connection + * @returns dispatch status, see dbus_connection_get_dispatch_status() + */ +DBusDispatchStatus +dbus_connection_dispatch (DBusConnection *connection) +{ + DBusMessage *message; + DBusList *link, *filter_list_copy, *message_link; + DBusHandlerResult result; + DBusPendingCall *pending; + dbus_int32_t reply_serial; + DBusDispatchStatus status; + + _dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE); + + _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + + CONNECTION_LOCK (connection); + status = _dbus_connection_get_dispatch_status_unlocked (connection); + if (status != DBUS_DISPATCH_DATA_REMAINS) + { + /* unlocks and calls out to user code */ + _dbus_connection_update_dispatch_status_and_unlock (connection, status); + return status; + } + + /* We need to ref the connection since the callback could potentially + * drop the last ref to it + */ + _dbus_connection_ref_unlocked (connection); + + _dbus_connection_acquire_dispatch (connection); + HAVE_LOCK_CHECK (connection); + + message_link = _dbus_connection_pop_message_link_unlocked (connection); + if (message_link == NULL) + { + /* another thread dispatched our stuff */ + + _dbus_verbose ("another thread dispatched message (during acquire_dispatch above)\n"); + + _dbus_connection_release_dispatch (connection); + + status = _dbus_connection_get_dispatch_status_unlocked (connection); + + _dbus_connection_update_dispatch_status_and_unlock (connection, status); + + dbus_connection_unref (connection); + + return status; + } + + message = message_link->data; + + _dbus_verbose (" dispatching message %p (%d %s %s '%s')\n", + message, + dbus_message_get_type (message), + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : + "no interface", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : + "no member", + dbus_message_get_signature (message)); + + result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + /* Pending call handling must be first, because if you do + * dbus_connection_send_with_reply_and_block() or + * dbus_pending_call_block() then no handlers/filters will be run on + * the reply. We want consistent semantics in the case where we + * dbus_connection_dispatch() the reply. + */ + + reply_serial = dbus_message_get_reply_serial (message); + pending = _dbus_hash_table_lookup_int (connection->pending_replies, + reply_serial); + if (pending) + { + _dbus_verbose ("Dispatching a pending reply\n"); + complete_pending_call_and_unlock (connection, pending, message); + pending = NULL; /* it's probably unref'd */ + + CONNECTION_LOCK (connection); + _dbus_verbose ("pending call completed in dispatch\n"); + result = DBUS_HANDLER_RESULT_HANDLED; + goto out; + } + + result = _dbus_connection_run_builtin_filters_unlocked_no_update (connection, message); + if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) + goto out; + + if (!_dbus_list_copy (&connection->filter_list, &filter_list_copy)) + { + _dbus_connection_release_dispatch (connection); + HAVE_LOCK_CHECK (connection); + + _dbus_connection_failed_pop (connection, message_link); + + /* unlocks and calls user code */ + _dbus_connection_update_dispatch_status_and_unlock (connection, + DBUS_DISPATCH_NEED_MEMORY); + + if (pending) + dbus_pending_call_unref (pending); + dbus_connection_unref (connection); + + return DBUS_DISPATCH_NEED_MEMORY; + } + + _dbus_list_foreach (&filter_list_copy, + (DBusForeachFunction)_dbus_message_filter_ref, + NULL); + + /* We're still protected from dispatch() reentrancy here + * since we acquired the dispatcher + */ + CONNECTION_UNLOCK (connection); + + link = _dbus_list_get_first_link (&filter_list_copy); + while (link != NULL) + { + DBusMessageFilter *filter = link->data; + DBusList *next = _dbus_list_get_next_link (&filter_list_copy, link); + + if (filter->function == NULL) + { + _dbus_verbose (" filter was removed in a callback function\n"); + link = next; + continue; + } + + _dbus_verbose (" running filter on message %p\n", message); + result = (* filter->function) (connection, message, filter->user_data); + + if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) + break; + + link = next; + } + + _dbus_list_foreach (&filter_list_copy, + (DBusForeachFunction)_dbus_message_filter_unref, + NULL); + _dbus_list_clear (&filter_list_copy); + + CONNECTION_LOCK (connection); + + if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) + { + _dbus_verbose ("No memory in %s\n", _DBUS_FUNCTION_NAME); + goto out; + } + else if (result == DBUS_HANDLER_RESULT_HANDLED) + { + _dbus_verbose ("filter handled message in dispatch\n"); + goto out; + } + + /* We're still protected from dispatch() reentrancy here + * since we acquired the dispatcher + */ + _dbus_verbose (" running object path dispatch on message %p (%d %s %s '%s')\n", + message, + dbus_message_get_type (message), + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : + "no interface", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : + "no member", + dbus_message_get_signature (message)); + + HAVE_LOCK_CHECK (connection); + result = _dbus_object_tree_dispatch_and_unlock (connection->objects, + message); + + CONNECTION_LOCK (connection); + + if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) + { + _dbus_verbose ("object tree handled message in dispatch\n"); + goto out; + } + + if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL) + { + DBusMessage *reply; + DBusString str; + DBusPreallocatedSend *preallocated; + + _dbus_verbose (" sending error %s\n", + DBUS_ERROR_UNKNOWN_METHOD); + + if (!_dbus_string_init (&str)) + { + result = DBUS_HANDLER_RESULT_NEED_MEMORY; + _dbus_verbose ("no memory for error string in dispatch\n"); + goto out; + } + + if (!_dbus_string_append_printf (&str, + "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist\n", + dbus_message_get_member (message), + dbus_message_get_signature (message), + dbus_message_get_interface (message))) + { + _dbus_string_free (&str); + result = DBUS_HANDLER_RESULT_NEED_MEMORY; + _dbus_verbose ("no memory for error string in dispatch\n"); + goto out; + } + + reply = dbus_message_new_error (message, + DBUS_ERROR_UNKNOWN_METHOD, + _dbus_string_get_const_data (&str)); + _dbus_string_free (&str); + + if (reply == NULL) + { + result = DBUS_HANDLER_RESULT_NEED_MEMORY; + _dbus_verbose ("no memory for error reply in dispatch\n"); + goto out; + } + + preallocated = _dbus_connection_preallocate_send_unlocked (connection); + + if (preallocated == NULL) + { + dbus_message_unref (reply); + result = DBUS_HANDLER_RESULT_NEED_MEMORY; + _dbus_verbose ("no memory for error send in dispatch\n"); + goto out; + } + + _dbus_connection_send_preallocated_unlocked_no_update (connection, preallocated, + reply, NULL); + + dbus_message_unref (reply); + + result = DBUS_HANDLER_RESULT_HANDLED; + } + + _dbus_verbose (" done dispatching %p (%d %s %s '%s') on connection %p\n", message, + dbus_message_get_type (message), + dbus_message_get_interface (message) ? + dbus_message_get_interface (message) : + "no interface", + dbus_message_get_member (message) ? + dbus_message_get_member (message) : + "no member", + dbus_message_get_signature (message), + connection); + + out: + if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) + { + _dbus_verbose ("out of memory in %s\n", _DBUS_FUNCTION_NAME); + + /* Put message back, and we'll start over. + * Yes this means handlers must be idempotent if they + * don't return HANDLED; c'est la vie. + */ + _dbus_connection_putback_message_link_unlocked (connection, + message_link); + } + else + { + _dbus_verbose (" ... done dispatching in %s\n", _DBUS_FUNCTION_NAME); + + _dbus_list_free_link (message_link); + dbus_message_unref (message); /* don't want the message to count in max message limits + * in computing dispatch status below + */ + } + + _dbus_connection_release_dispatch (connection); + HAVE_LOCK_CHECK (connection); + + _dbus_verbose ("%s before final status update\n", _DBUS_FUNCTION_NAME); + status = _dbus_connection_get_dispatch_status_unlocked (connection); + + /* unlocks and calls user code */ + _dbus_connection_update_dispatch_status_and_unlock (connection, status); + + dbus_connection_unref (connection); + + return status; +} + +/** + * Sets the watch functions for the connection. These functions are + * responsible for making the application's main loop aware of file + * descriptors that need to be monitored for events, using select() or + * poll(). When using Qt, typically the DBusAddWatchFunction would + * create a QSocketNotifier. When using GLib, the DBusAddWatchFunction + * could call g_io_add_watch(), or could be used as part of a more + * elaborate GSource. Note that when a watch is added, it may + * not be enabled. + * + * The DBusWatchToggledFunction notifies the application that the + * watch has been enabled or disabled. Call dbus_watch_get_enabled() + * to check this. A disabled watch should have no effect, and enabled + * watch should be added to the main loop. This feature is used + * instead of simply adding/removing the watch because + * enabling/disabling can be done without memory allocation. The + * toggled function may be NULL if a main loop re-queries + * dbus_watch_get_enabled() every time anyway. + * + * The DBusWatch can be queried for the file descriptor to watch using + * dbus_watch_get_unix_fd() or dbus_watch_get_socket(), and for the + * events to watch for using dbus_watch_get_flags(). The flags + * returned by dbus_watch_get_flags() will only contain + * DBUS_WATCH_READABLE and DBUS_WATCH_WRITABLE, never + * DBUS_WATCH_HANGUP or DBUS_WATCH_ERROR; all watches implicitly + * include a watch for hangups, errors, and other exceptional + * conditions. + * + * Once a file descriptor becomes readable or writable, or an exception + * occurs, dbus_watch_handle() should be called to + * notify the connection of the file descriptor's condition. + * + * dbus_watch_handle() cannot be called during the + * DBusAddWatchFunction, as the connection will not be ready to handle + * that watch yet. + * + * It is not allowed to reference a DBusWatch after it has been passed + * to remove_function. + * + * If #FALSE is returned due to lack of memory, the failure may be due + * to a #FALSE return from the new add_function. If so, the + * add_function may have been called successfully one or more times, + * but the remove_function will also have been called to remove any + * successful adds. i.e. if #FALSE is returned the net result + * should be that dbus_connection_set_watch_functions() has no effect, + * but the add_function and remove_function may have been called. + * + * @todo We need to drop the lock when we call the + * add/remove/toggled functions which can be a side effect + * of setting the watch functions. + * + * @param connection the connection. + * @param add_function function to begin monitoring a new descriptor. + * @param remove_function function to stop monitoring a descriptor. + * @param toggled_function function to notify of enable/disable + * @param data data to pass to add_function and remove_function. + * @param free_data_function function to be called to free the data. + * @returns #FALSE on failure (no memory) + */ +dbus_bool_t +dbus_connection_set_watch_functions (DBusConnection *connection, + DBusAddWatchFunction add_function, + DBusRemoveWatchFunction remove_function, + DBusWatchToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function) +{ + dbus_bool_t retval; + DBusWatchList *watches; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + + CONNECTION_LOCK (connection); + +#ifndef DBUS_DISABLE_CHECKS + if (connection->watches == NULL) + { + _dbus_warn_check_failed ("Re-entrant call to %s is not allowed\n", + _DBUS_FUNCTION_NAME); + return FALSE; + } +#endif + + /* ref connection for slightly better reentrancy */ + _dbus_connection_ref_unlocked (connection); + + /* This can call back into user code, and we need to drop the + * connection lock when it does. This is kind of a lame + * way to do it. + */ + watches = connection->watches; + connection->watches = NULL; + CONNECTION_UNLOCK (connection); + + retval = _dbus_watch_list_set_functions (watches, + add_function, remove_function, + toggled_function, + data, free_data_function); + CONNECTION_LOCK (connection); + connection->watches = watches; + + CONNECTION_UNLOCK (connection); + /* drop our paranoid refcount */ + dbus_connection_unref (connection); + + return retval; +} + +/** + * Sets the timeout functions for the connection. These functions are + * responsible for making the application's main loop aware of timeouts. + * When using Qt, typically the DBusAddTimeoutFunction would create a + * QTimer. When using GLib, the DBusAddTimeoutFunction would call + * g_timeout_add. + * + * The DBusTimeoutToggledFunction notifies the application that the + * timeout has been enabled or disabled. Call + * dbus_timeout_get_enabled() to check this. A disabled timeout should + * have no effect, and enabled timeout should be added to the main + * loop. This feature is used instead of simply adding/removing the + * timeout because enabling/disabling can be done without memory + * allocation. With Qt, QTimer::start() and QTimer::stop() can be used + * to enable and disable. The toggled function may be NULL if a main + * loop re-queries dbus_timeout_get_enabled() every time anyway. + * Whenever a timeout is toggled, its interval may change. + * + * The DBusTimeout can be queried for the timer interval using + * dbus_timeout_get_interval(). dbus_timeout_handle() should be called + * repeatedly, each time the interval elapses, starting after it has + * elapsed once. The timeout stops firing when it is removed with the + * given remove_function. The timer interval may change whenever the + * timeout is added, removed, or toggled. + * + * @param connection the connection. + * @param add_function function to add a timeout. + * @param remove_function function to remove a timeout. + * @param toggled_function function to notify of enable/disable + * @param data data to pass to add_function and remove_function. + * @param free_data_function function to be called to free the data. + * @returns #FALSE on failure (no memory) + */ +dbus_bool_t +dbus_connection_set_timeout_functions (DBusConnection *connection, + DBusAddTimeoutFunction add_function, + DBusRemoveTimeoutFunction remove_function, + DBusTimeoutToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function) +{ + dbus_bool_t retval; + DBusTimeoutList *timeouts; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + + CONNECTION_LOCK (connection); + +#ifndef DBUS_DISABLE_CHECKS + if (connection->timeouts == NULL) + { + _dbus_warn_check_failed ("Re-entrant call to %s is not allowed\n", + _DBUS_FUNCTION_NAME); + return FALSE; + } +#endif + + /* ref connection for slightly better reentrancy */ + _dbus_connection_ref_unlocked (connection); + + timeouts = connection->timeouts; + connection->timeouts = NULL; + CONNECTION_UNLOCK (connection); + + retval = _dbus_timeout_list_set_functions (timeouts, + add_function, remove_function, + toggled_function, + data, free_data_function); + CONNECTION_LOCK (connection); + connection->timeouts = timeouts; + + CONNECTION_UNLOCK (connection); + /* drop our paranoid refcount */ + dbus_connection_unref (connection); + + return retval; +} + +/** + * Sets the mainloop wakeup function for the connection. This function + * is responsible for waking up the main loop (if its sleeping in + * another thread) when some some change has happened to the + * connection that the mainloop needs to reconsider (e.g. a message + * has been queued for writing). When using Qt, this typically + * results in a call to QEventLoop::wakeUp(). When using GLib, it + * would call g_main_context_wakeup(). + * + * @param connection the connection. + * @param wakeup_main_function function to wake up the mainloop + * @param data data to pass wakeup_main_function + * @param free_data_function function to be called to free the data. + */ +void +dbus_connection_set_wakeup_main_function (DBusConnection *connection, + DBusWakeupMainFunction wakeup_main_function, + void *data, + DBusFreeFunction free_data_function) +{ + void *old_data; + DBusFreeFunction old_free_data; + + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + old_data = connection->wakeup_main_data; + old_free_data = connection->free_wakeup_main_data; + + connection->wakeup_main_function = wakeup_main_function; + connection->wakeup_main_data = data; + connection->free_wakeup_main_data = free_data_function; + + CONNECTION_UNLOCK (connection); + + /* Callback outside the lock */ + if (old_free_data) + (*old_free_data) (old_data); +} + +/** + * Set a function to be invoked when the dispatch status changes. + * If the dispatch status is #DBUS_DISPATCH_DATA_REMAINS, then + * dbus_connection_dispatch() needs to be called to process incoming + * messages. However, dbus_connection_dispatch() MUST NOT BE CALLED + * from inside the DBusDispatchStatusFunction. Indeed, almost + * any reentrancy in this function is a bad idea. Instead, + * the DBusDispatchStatusFunction should simply save an indication + * that messages should be dispatched later, when the main loop + * is re-entered. + * + * If you don't set a dispatch status function, you have to be sure to + * dispatch on every iteration of your main loop, especially if + * dbus_watch_handle() or dbus_timeout_handle() were called. + * + * @param connection the connection + * @param function function to call on dispatch status changes + * @param data data for function + * @param free_data_function free the function data + */ +void +dbus_connection_set_dispatch_status_function (DBusConnection *connection, + DBusDispatchStatusFunction function, + void *data, + DBusFreeFunction free_data_function) +{ + void *old_data; + DBusFreeFunction old_free_data; + + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + old_data = connection->dispatch_status_data; + old_free_data = connection->free_dispatch_status_data; + + connection->dispatch_status_function = function; + connection->dispatch_status_data = data; + connection->free_dispatch_status_data = free_data_function; + + CONNECTION_UNLOCK (connection); + + /* Callback outside the lock */ + if (old_free_data) + (*old_free_data) (old_data); +} + +/** + * Get the UNIX file descriptor of the connection, if any. This can + * be used for SELinux access control checks with getpeercon() for + * example. DO NOT read or write to the file descriptor, or try to + * select() on it; use DBusWatch for main loop integration. Not all + * connections will have a file descriptor. So for adding descriptors + * to the main loop, use dbus_watch_get_unix_fd() and so forth. + * + * If the connection is socket-based, you can also use + * dbus_connection_get_socket(), which will work on Windows too. + * This function always fails on Windows. + * + * Right now the returned descriptor is always a socket, but + * that is not guaranteed. + * + * @param connection the connection + * @param fd return location for the file descriptor. + * @returns #TRUE if fd is successfully obtained. + */ +dbus_bool_t +dbus_connection_get_unix_fd (DBusConnection *connection, + int *fd) +{ + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (connection->transport != NULL, FALSE); + +#ifdef DBUS_WIN + /* FIXME do this on a lower level */ + return FALSE; +#endif + + return dbus_connection_get_socket(connection, fd); +} + +/** + * Gets the underlying Windows or UNIX socket file descriptor + * of the connection, if any. DO NOT read or write to the file descriptor, or try to + * select() on it; use DBusWatch for main loop integration. Not all + * connections will have a socket. So for adding descriptors + * to the main loop, use dbus_watch_get_socket() and so forth. + * + * If the connection is not socket-based, this function will return FALSE, + * even if the connection does have a file descriptor of some kind. + * i.e. this function always returns specifically a socket file descriptor. + * + * @param connection the connection + * @param fd return location for the file descriptor. + * @returns #TRUE if fd is successfully obtained. + */ +dbus_bool_t +dbus_connection_get_socket(DBusConnection *connection, + int *fd) +{ + dbus_bool_t retval; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (connection->transport != NULL, FALSE); + + CONNECTION_LOCK (connection); + + retval = _dbus_transport_get_socket_fd (connection->transport, + fd); + + CONNECTION_UNLOCK (connection); + + return retval; +} + + +/** + * Gets the UNIX user ID of the connection if known. Returns #TRUE if + * the uid is filled in. Always returns #FALSE on non-UNIX platforms + * for now, though in theory someone could hook Windows to NIS or + * something. Always returns #FALSE prior to authenticating the + * connection. + * + * The UID is only read by servers from clients; clients can't usually + * get the UID of servers, because servers do not authenticate to + * clients. The returned UID is the UID the connection authenticated + * as. + * + * The message bus is a server and the apps connecting to the bus + * are clients. + * + * You can ask the bus to tell you the UID of another connection though + * if you like; this is done with dbus_bus_get_unix_user(). + * + * @param connection the connection + * @param uid return location for the user ID + * @returns #TRUE if uid is filled in with a valid user ID + */ +dbus_bool_t +dbus_connection_get_unix_user (DBusConnection *connection, + unsigned long *uid) +{ + dbus_bool_t result; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (uid != NULL, FALSE); + + CONNECTION_LOCK (connection); + + if (!_dbus_transport_get_is_authenticated (connection->transport)) + result = FALSE; + else + result = _dbus_transport_get_unix_user (connection->transport, + uid); + +#ifdef DBUS_WIN + _dbus_assert (!result); +#endif + + CONNECTION_UNLOCK (connection); + + return result; +} + +/** + * Gets the process ID of the connection if any. + * Returns #TRUE if the pid is filled in. + * Always returns #FALSE prior to authenticating the + * connection. + * + * @param connection the connection + * @param pid return location for the process ID + * @returns #TRUE if uid is filled in with a valid process ID + */ +dbus_bool_t +dbus_connection_get_unix_process_id (DBusConnection *connection, + unsigned long *pid) +{ + dbus_bool_t result; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (pid != NULL, FALSE); + + CONNECTION_LOCK (connection); + + if (!_dbus_transport_get_is_authenticated (connection->transport)) + result = FALSE; + else + result = _dbus_transport_get_unix_process_id (connection->transport, + pid); +#ifdef DBUS_WIN + _dbus_assert (!result); +#endif + + CONNECTION_UNLOCK (connection); + + return result; +} + +/** + * Gets the ADT audit data of the connection if any. + * Returns #TRUE if the structure pointer is returned. + * Always returns #FALSE prior to authenticating the + * connection. + * + * @param connection the connection + * @param data return location for audit data + * @returns #TRUE if audit data is filled in with a valid ucred pointer + */ +dbus_bool_t +dbus_connection_get_adt_audit_session_data (DBusConnection *connection, + void **data, + dbus_int32_t *data_size) +{ + dbus_bool_t result; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (data != NULL, FALSE); + _dbus_return_val_if_fail (data_size != NULL, FALSE); + + CONNECTION_LOCK (connection); + + if (!_dbus_transport_get_is_authenticated (connection->transport)) + result = FALSE; + else + result = _dbus_transport_get_adt_audit_session_data (connection->transport, + data, + data_size); + CONNECTION_UNLOCK (connection); + + return result; +} + +/** + * Sets a predicate function used to determine whether a given user ID + * is allowed to connect. When an incoming connection has + * authenticated with a particular user ID, this function is called; + * if it returns #TRUE, the connection is allowed to proceed, + * otherwise the connection is disconnected. + * + * If the function is set to #NULL (as it is by default), then + * only the same UID as the server process will be allowed to + * connect. Also, root is always allowed to connect. + * + * On Windows, the function will be set and its free_data_function will + * be invoked when the connection is freed or a new function is set. + * However, the function will never be called, because there are + * no UNIX user ids to pass to it, or at least none of the existing + * auth protocols would allow authenticating as a UNIX user on Windows. + * + * @param connection the connection + * @param function the predicate + * @param data data to pass to the predicate + * @param free_data_function function to free the data + */ +void +dbus_connection_set_unix_user_function (DBusConnection *connection, + DBusAllowUnixUserFunction function, + void *data, + DBusFreeFunction free_data_function) +{ + void *old_data = NULL; + DBusFreeFunction old_free_function = NULL; + + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + _dbus_transport_set_unix_user_function (connection->transport, + function, data, free_data_function, + &old_data, &old_free_function); + CONNECTION_UNLOCK (connection); + + if (old_free_function != NULL) + (* old_free_function) (old_data); +} + +/** + * Gets the Windows user SID of the connection if known. Returns + * #TRUE if the ID is filled in. Always returns #FALSE on non-Windows + * platforms for now, though in theory someone could hook UNIX to + * Active Directory or something. Always returns #FALSE prior to + * authenticating the connection. + * + * The user is only read by servers from clients; clients can't usually + * get the user of servers, because servers do not authenticate to + * clients. The returned user is the user the connection authenticated + * as. + * + * The message bus is a server and the apps connecting to the bus + * are clients. + * + * The returned user string has to be freed with dbus_free(). + * + * The return value indicates whether the user SID is available; + * if it's available but we don't have the memory to copy it, + * then the return value is #TRUE and #NULL is given as the SID. + * + * @todo We would like to be able to say "You can ask the bus to tell + * you the user of another connection though if you like; this is done + * with dbus_bus_get_windows_user()." But this has to be implemented + * in bus/driver.c and dbus/dbus-bus.c, and is pointless anyway + * since on Windows we only use the session bus for now. + * + * @param connection the connection + * @param windows_sid_p return location for an allocated copy of the user ID, or #NULL if no memory + * @returns #TRUE if user is available (returned value may be #NULL anyway if no memory) + */ +dbus_bool_t +dbus_connection_get_windows_user (DBusConnection *connection, + char **windows_sid_p) +{ + dbus_bool_t result; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (windows_sid_p != NULL, FALSE); + + CONNECTION_LOCK (connection); + + if (!_dbus_transport_get_is_authenticated (connection->transport)) + result = FALSE; + else + result = _dbus_transport_get_windows_user (connection->transport, + windows_sid_p); + +#ifdef DBUS_UNIX + _dbus_assert (!result); +#endif + + CONNECTION_UNLOCK (connection); + + return result; +} + +/** + * Sets a predicate function used to determine whether a given user ID + * is allowed to connect. When an incoming connection has + * authenticated with a particular user ID, this function is called; + * if it returns #TRUE, the connection is allowed to proceed, + * otherwise the connection is disconnected. + * + * If the function is set to #NULL (as it is by default), then + * only the same user owning the server process will be allowed to + * connect. + * + * On UNIX, the function will be set and its free_data_function will + * be invoked when the connection is freed or a new function is set. + * However, the function will never be called, because there is no + * way right now to authenticate as a Windows user on UNIX. + * + * @param connection the connection + * @param function the predicate + * @param data data to pass to the predicate + * @param free_data_function function to free the data + */ +void +dbus_connection_set_windows_user_function (DBusConnection *connection, + DBusAllowWindowsUserFunction function, + void *data, + DBusFreeFunction free_data_function) +{ + void *old_data = NULL; + DBusFreeFunction old_free_function = NULL; + + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + _dbus_transport_set_windows_user_function (connection->transport, + function, data, free_data_function, + &old_data, &old_free_function); + CONNECTION_UNLOCK (connection); + + if (old_free_function != NULL) + (* old_free_function) (old_data); +} + +/** + * This function must be called on the server side of a connection when the + * connection is first seen in the #DBusNewConnectionFunction. If set to + * #TRUE (the default is #FALSE), then the connection can proceed even if + * the client does not authenticate as some user identity, i.e. clients + * can connect anonymously. + * + * This setting interacts with the available authorization mechanisms + * (see dbus_server_set_auth_mechanisms()). Namely, an auth mechanism + * such as ANONYMOUS that supports anonymous auth must be included in + * the list of available mechanisms for anonymous login to work. + * + * This setting also changes the default rule for connections + * authorized as a user; normally, if a connection authorizes as + * a user identity, it is permitted if the user identity is + * root or the user identity matches the user identity of the server + * process. If anonymous connections are allowed, however, + * then any user identity is allowed. + * + * You can override the rules for connections authorized as a + * user identity with dbus_connection_set_unix_user_function() + * and dbus_connection_set_windows_user_function(). + * + * @param connection the connection + * @param value whether to allow authentication as an anonymous user + */ +void +dbus_connection_set_allow_anonymous (DBusConnection *connection, + dbus_bool_t value) +{ + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + _dbus_transport_set_allow_anonymous (connection->transport, value); + CONNECTION_UNLOCK (connection); +} + +/** + * + * Normally #DBusConnection automatically handles all messages to the + * org.freedesktop.DBus.Peer interface. However, the message bus wants + * to be able to route methods on that interface through the bus and + * to other applications. If routing peer messages is enabled, then + * messages with the org.freedesktop.DBus.Peer interface that also + * have a bus destination name set will not be automatically + * handled by the #DBusConnection and instead will be dispatched + * normally to the application. + * + * If a normal application sets this flag, it can break things badly. + * So don't set this unless you are the message bus. + * + * @param connection the connection + * @param value #TRUE to pass through org.freedesktop.DBus.Peer messages with a bus name set + */ +void +dbus_connection_set_route_peer_messages (DBusConnection *connection, + dbus_bool_t value) +{ + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + connection->route_peer_messages = TRUE; + CONNECTION_UNLOCK (connection); +} + +/** + * Adds a message filter. Filters are handlers that are run on all + * incoming messages, prior to the objects registered with + * dbus_connection_register_object_path(). Filters are run in the + * order that they were added. The same handler can be added as a + * filter more than once, in which case it will be run more than once. + * Filters added during a filter callback won't be run on the message + * being processed. + * + * @todo we don't run filters on messages while blocking without + * entering the main loop, since filters are run as part of + * dbus_connection_dispatch(). This is probably a feature, as filters + * could create arbitrary reentrancy. But kind of sucks if you're + * trying to filter METHOD_RETURN for some reason. + * + * @param connection the connection + * @param function function to handle messages + * @param user_data user data to pass to the function + * @param free_data_function function to use for freeing user data + * @returns #TRUE on success, #FALSE if not enough memory. + */ +dbus_bool_t +dbus_connection_add_filter (DBusConnection *connection, + DBusHandleMessageFunction function, + void *user_data, + DBusFreeFunction free_data_function) +{ + DBusMessageFilter *filter; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (function != NULL, FALSE); + + filter = dbus_new0 (DBusMessageFilter, 1); + if (filter == NULL) + return FALSE; + + filter->refcount.value = 1; + + CONNECTION_LOCK (connection); + + if (!_dbus_list_append (&connection->filter_list, + filter)) + { + _dbus_message_filter_unref (filter); + CONNECTION_UNLOCK (connection); + return FALSE; + } + + /* Fill in filter after all memory allocated, + * so we don't run the free_user_data_function + * if the add_filter() fails + */ + + filter->function = function; + filter->user_data = user_data; + filter->free_user_data_function = free_data_function; + + CONNECTION_UNLOCK (connection); + return TRUE; +} + +/** + * Removes a previously-added message filter. It is a programming + * error to call this function for a handler that has not been added + * as a filter. If the given handler was added more than once, only + * one instance of it will be removed (the most recently-added + * instance). + * + * @param connection the connection + * @param function the handler to remove + * @param user_data user data for the handler to remove + * + */ +void +dbus_connection_remove_filter (DBusConnection *connection, + DBusHandleMessageFunction function, + void *user_data) +{ + DBusList *link; + DBusMessageFilter *filter; + + _dbus_return_if_fail (connection != NULL); + _dbus_return_if_fail (function != NULL); + + CONNECTION_LOCK (connection); + + filter = NULL; + + link = _dbus_list_get_last_link (&connection->filter_list); + while (link != NULL) + { + filter = link->data; + + if (filter->function == function && + filter->user_data == user_data) + { + _dbus_list_remove_link (&connection->filter_list, link); + filter->function = NULL; + + break; + } + + link = _dbus_list_get_prev_link (&connection->filter_list, link); + filter = NULL; + } + + CONNECTION_UNLOCK (connection); + +#ifndef DBUS_DISABLE_CHECKS + if (filter == NULL) + { + _dbus_warn_check_failed ("Attempt to remove filter function %p user data %p, but no such filter has been added\n", + function, user_data); + return; + } +#endif + + /* Call application code */ + if (filter->free_user_data_function) + (* filter->free_user_data_function) (filter->user_data); + + filter->free_user_data_function = NULL; + filter->user_data = NULL; + + _dbus_message_filter_unref (filter); +} + +/** + * Registers a handler for a given path in the object hierarchy. + * The given vtable handles messages sent to exactly the given path. + * + * @param connection the connection + * @param path a '/' delimited string of path elements + * @param vtable the virtual table + * @param user_data data to pass to functions in the vtable + * @param error address where an error can be returned + * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or + * #DBUS_ERROR_ADDRESS_IN_USE) is reported + */ +dbus_bool_t +dbus_connection_try_register_object_path (DBusConnection *connection, + const char *path, + const DBusObjectPathVTable *vtable, + void *user_data, + DBusError *error) +{ + char **decomposed_path; + dbus_bool_t retval; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (path != NULL, FALSE); + _dbus_return_val_if_fail (path[0] == '/', FALSE); + _dbus_return_val_if_fail (vtable != NULL, FALSE); + + if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) + return FALSE; + + CONNECTION_LOCK (connection); + + retval = _dbus_object_tree_register (connection->objects, + FALSE, + (const char **) decomposed_path, vtable, + user_data, error); + + CONNECTION_UNLOCK (connection); + + dbus_free_string_array (decomposed_path); + + return retval; +} + +/** + * Registers a handler for a given path in the object hierarchy. + * The given vtable handles messages sent to exactly the given path. + * + * It is a bug to call this function for object paths which already + * have a handler. Use dbus_connection_try_register_object_path() if this + * might be the case. + * + * @param connection the connection + * @param path a '/' delimited string of path elements + * @param vtable the virtual table + * @param user_data data to pass to functions in the vtable + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_connection_register_object_path (DBusConnection *connection, + const char *path, + const DBusObjectPathVTable *vtable, + void *user_data) +{ + char **decomposed_path; + dbus_bool_t retval; + DBusError error = DBUS_ERROR_INIT; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (path != NULL, FALSE); + _dbus_return_val_if_fail (path[0] == '/', FALSE); + _dbus_return_val_if_fail (vtable != NULL, FALSE); + + if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) + return FALSE; + + CONNECTION_LOCK (connection); + + retval = _dbus_object_tree_register (connection->objects, + FALSE, + (const char **) decomposed_path, vtable, + user_data, &error); + + CONNECTION_UNLOCK (connection); + + dbus_free_string_array (decomposed_path); + + if (dbus_error_has_name (&error, DBUS_ERROR_ADDRESS_IN_USE)) + { + _dbus_warn ("%s\n", error.message); + dbus_error_free (&error); + return FALSE; + } + + return retval; +} + +/** + * Registers a fallback handler for a given subsection of the object + * hierarchy. The given vtable handles messages at or below the given + * path. You can use this to establish a default message handling + * policy for a whole "subdirectory." + * + * @param connection the connection + * @param path a '/' delimited string of path elements + * @param vtable the virtual table + * @param user_data data to pass to functions in the vtable + * @param error address where an error can be returned + * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or + * #DBUS_ERROR_ADDRESS_IN_USE) is reported + */ +dbus_bool_t +dbus_connection_try_register_fallback (DBusConnection *connection, + const char *path, + const DBusObjectPathVTable *vtable, + void *user_data, + DBusError *error) +{ + char **decomposed_path; + dbus_bool_t retval; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (path != NULL, FALSE); + _dbus_return_val_if_fail (path[0] == '/', FALSE); + _dbus_return_val_if_fail (vtable != NULL, FALSE); + + if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) + return FALSE; + + CONNECTION_LOCK (connection); + + retval = _dbus_object_tree_register (connection->objects, + TRUE, + (const char **) decomposed_path, vtable, + user_data, error); + + CONNECTION_UNLOCK (connection); + + dbus_free_string_array (decomposed_path); + + return retval; +} + +/** + * Registers a fallback handler for a given subsection of the object + * hierarchy. The given vtable handles messages at or below the given + * path. You can use this to establish a default message handling + * policy for a whole "subdirectory." + * + * It is a bug to call this function for object paths which already + * have a handler. Use dbus_connection_try_register_fallback() if this + * might be the case. + * + * @param connection the connection + * @param path a '/' delimited string of path elements + * @param vtable the virtual table + * @param user_data data to pass to functions in the vtable + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_connection_register_fallback (DBusConnection *connection, + const char *path, + const DBusObjectPathVTable *vtable, + void *user_data) +{ + char **decomposed_path; + dbus_bool_t retval; + DBusError error = DBUS_ERROR_INIT; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (path != NULL, FALSE); + _dbus_return_val_if_fail (path[0] == '/', FALSE); + _dbus_return_val_if_fail (vtable != NULL, FALSE); + + if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) + return FALSE; + + CONNECTION_LOCK (connection); + + retval = _dbus_object_tree_register (connection->objects, + TRUE, + (const char **) decomposed_path, vtable, + user_data, &error); + + CONNECTION_UNLOCK (connection); + + dbus_free_string_array (decomposed_path); + + if (dbus_error_has_name (&error, DBUS_ERROR_ADDRESS_IN_USE)) + { + _dbus_warn ("%s\n", error.message); + dbus_error_free (&error); + return FALSE; + } + + return retval; +} + +/** + * Unregisters the handler registered with exactly the given path. + * It's a bug to call this function for a path that isn't registered. + * Can unregister both fallback paths and object paths. + * + * @param connection the connection + * @param path a '/' delimited string of path elements + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_connection_unregister_object_path (DBusConnection *connection, + const char *path) +{ + char **decomposed_path; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (path != NULL, FALSE); + _dbus_return_val_if_fail (path[0] == '/', FALSE); + + if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) + return FALSE; + + CONNECTION_LOCK (connection); + + _dbus_object_tree_unregister_and_unlock (connection->objects, (const char **) decomposed_path); + + dbus_free_string_array (decomposed_path); + + return TRUE; +} + +/** + * Gets the user data passed to dbus_connection_register_object_path() + * or dbus_connection_register_fallback(). If nothing was registered + * at this path, the data is filled in with #NULL. + * + * @param connection the connection + * @param path the path you registered with + * @param data_p location to store the user data, or #NULL + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_connection_get_object_path_data (DBusConnection *connection, + const char *path, + void **data_p) +{ + char **decomposed_path; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (path != NULL, FALSE); + _dbus_return_val_if_fail (data_p != NULL, FALSE); + + *data_p = NULL; + + if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL)) + return FALSE; + + CONNECTION_LOCK (connection); + + *data_p = _dbus_object_tree_get_user_data_unlocked (connection->objects, (const char**) decomposed_path); + + CONNECTION_UNLOCK (connection); + + dbus_free_string_array (decomposed_path); + + return TRUE; +} + +/** + * Lists the registered fallback handlers and object path handlers at + * the given parent_path. The returned array should be freed with + * dbus_free_string_array(). + * + * @param connection the connection + * @param parent_path the path to list the child handlers of + * @param child_entries returns #NULL-terminated array of children + * @returns #FALSE if no memory to allocate the child entries + */ +dbus_bool_t +dbus_connection_list_registered (DBusConnection *connection, + const char *parent_path, + char ***child_entries) +{ + char **decomposed_path; + dbus_bool_t retval; + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (parent_path != NULL, FALSE); + _dbus_return_val_if_fail (parent_path[0] == '/', FALSE); + _dbus_return_val_if_fail (child_entries != NULL, FALSE); + + if (!_dbus_decompose_path (parent_path, strlen (parent_path), &decomposed_path, NULL)) + return FALSE; + + CONNECTION_LOCK (connection); + + retval = _dbus_object_tree_list_registered_and_unlock (connection->objects, + (const char **) decomposed_path, + child_entries); + dbus_free_string_array (decomposed_path); + + return retval; +} + +static DBusDataSlotAllocator slot_allocator; +_DBUS_DEFINE_GLOBAL_LOCK (connection_slots); + +/** + * Allocates an integer ID to be used for storing application-specific + * data on any DBusConnection. The allocated ID may then be used + * with dbus_connection_set_data() and dbus_connection_get_data(). + * The passed-in slot must be initialized to -1, and is filled in + * with the slot ID. If the passed-in slot is not -1, it's assumed + * to be already allocated, and its refcount is incremented. + * + * The allocated slot is global, i.e. all DBusConnection objects will + * have a slot with the given integer ID reserved. + * + * @param slot_p address of a global variable storing the slot + * @returns #FALSE on failure (no memory) + */ +dbus_bool_t +dbus_connection_allocate_data_slot (dbus_int32_t *slot_p) +{ + return _dbus_data_slot_allocator_alloc (&slot_allocator, + &_DBUS_LOCK_NAME (connection_slots), + slot_p); +} + +/** + * Deallocates a global ID for connection data slots. + * dbus_connection_get_data() and dbus_connection_set_data() may no + * longer be used with this slot. Existing data stored on existing + * DBusConnection objects will be freed when the connection is + * finalized, but may not be retrieved (and may only be replaced if + * someone else reallocates the slot). When the refcount on the + * passed-in slot reaches 0, it is set to -1. + * + * @param slot_p address storing the slot to deallocate + */ +void +dbus_connection_free_data_slot (dbus_int32_t *slot_p) +{ + _dbus_return_if_fail (*slot_p >= 0); + + _dbus_data_slot_allocator_free (&slot_allocator, slot_p); +} + +/** + * Stores a pointer on a DBusConnection, along + * with an optional function to be used for freeing + * the data when the data is set again, or when + * the connection is finalized. The slot number + * must have been allocated with dbus_connection_allocate_data_slot(). + * + * @param connection the connection + * @param slot the slot number + * @param data the data to store + * @param free_data_func finalizer function for the data + * @returns #TRUE if there was enough memory to store the data + */ +dbus_bool_t +dbus_connection_set_data (DBusConnection *connection, + dbus_int32_t slot, + void *data, + DBusFreeFunction free_data_func) +{ + DBusFreeFunction old_free_func; + void *old_data; + dbus_bool_t retval; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (slot >= 0, FALSE); + + CONNECTION_LOCK (connection); + + retval = _dbus_data_slot_list_set (&slot_allocator, + &connection->slot_list, + slot, data, free_data_func, + &old_free_func, &old_data); + + CONNECTION_UNLOCK (connection); + + if (retval) + { + /* Do the actual free outside the connection lock */ + if (old_free_func) + (* old_free_func) (old_data); + } + + return retval; +} + +/** + * Retrieves data previously set with dbus_connection_set_data(). + * The slot must still be allocated (must not have been freed). + * + * @param connection the connection + * @param slot the slot to get data from + * @returns the data, or #NULL if not found + */ +void* +dbus_connection_get_data (DBusConnection *connection, + dbus_int32_t slot) +{ + void *res; + + _dbus_return_val_if_fail (connection != NULL, NULL); + + CONNECTION_LOCK (connection); + + res = _dbus_data_slot_list_get (&slot_allocator, + &connection->slot_list, + slot); + + CONNECTION_UNLOCK (connection); + + return res; +} + +/** + * This function sets a global flag for whether dbus_connection_new() + * will set SIGPIPE behavior to SIG_IGN. + * + * @param will_modify_sigpipe #TRUE to allow sigpipe to be set to SIG_IGN + */ +void +dbus_connection_set_change_sigpipe (dbus_bool_t will_modify_sigpipe) +{ + _dbus_modify_sigpipe = will_modify_sigpipe != FALSE; +} + +/** + * Specifies the maximum size message this connection is allowed to + * receive. Larger messages will result in disconnecting the + * connection. + * + * @param connection a #DBusConnection + * @param size maximum message size the connection can receive, in bytes + */ +void +dbus_connection_set_max_message_size (DBusConnection *connection, + long size) +{ + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + _dbus_transport_set_max_message_size (connection->transport, + size); + CONNECTION_UNLOCK (connection); +} + +/** + * Gets the value set by dbus_connection_set_max_message_size(). + * + * @param connection the connection + * @returns the max size of a single message + */ +long +dbus_connection_get_max_message_size (DBusConnection *connection) +{ + long res; + + _dbus_return_val_if_fail (connection != NULL, 0); + + CONNECTION_LOCK (connection); + res = _dbus_transport_get_max_message_size (connection->transport); + CONNECTION_UNLOCK (connection); + return res; +} + +/** + * Sets the maximum total number of bytes that can be used for all messages + * received on this connection. Messages count toward the maximum until + * they are finalized. When the maximum is reached, the connection will + * not read more data until some messages are finalized. + * + * The semantics of the maximum are: if outstanding messages are + * already above the maximum, additional messages will not be read. + * The semantics are not: if the next message would cause us to exceed + * the maximum, we don't read it. The reason is that we don't know the + * size of a message until after we read it. + * + * Thus, the max live messages size can actually be exceeded + * by up to the maximum size of a single message. + * + * Also, if we read say 1024 bytes off the wire in a single read(), + * and that contains a half-dozen small messages, we may exceed the + * size max by that amount. But this should be inconsequential. + * + * This does imply that we can't call read() with a buffer larger + * than we're willing to exceed this limit by. + * + * @param connection the connection + * @param size the maximum size in bytes of all outstanding messages + */ +void +dbus_connection_set_max_received_size (DBusConnection *connection, + long size) +{ + _dbus_return_if_fail (connection != NULL); + + CONNECTION_LOCK (connection); + _dbus_transport_set_max_received_size (connection->transport, + size); + CONNECTION_UNLOCK (connection); +} + +/** + * Gets the value set by dbus_connection_set_max_received_size(). + * + * @param connection the connection + * @returns the max size of all live messages + */ +long +dbus_connection_get_max_received_size (DBusConnection *connection) +{ + long res; + + _dbus_return_val_if_fail (connection != NULL, 0); + + CONNECTION_LOCK (connection); + res = _dbus_transport_get_max_received_size (connection->transport); + CONNECTION_UNLOCK (connection); + return res; +} + +/** + * Gets the approximate size in bytes of all messages in the outgoing + * message queue. The size is approximate in that you shouldn't use + * it to decide how many bytes to read off the network or anything + * of that nature, as optimizations may choose to tell small white lies + * to avoid performance overhead. + * + * @param connection the connection + * @returns the number of bytes that have been queued up but not sent + */ +long +dbus_connection_get_outgoing_size (DBusConnection *connection) +{ + long res; + + _dbus_return_val_if_fail (connection != NULL, 0); + + CONNECTION_LOCK (connection); + res = _dbus_counter_get_value (connection->outgoing_counter); + CONNECTION_UNLOCK (connection); + return res; +} + +/** @} */ diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h new file mode 100644 index 00000000..29a2f5e2 --- /dev/null +++ b/dbus/dbus-connection.h @@ -0,0 +1,406 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-connection.h DBusConnection object + * + * Copyright (C) 2002, 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_CONNECTION_H +#define DBUS_CONNECTION_H + +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusConnection + * @{ + */ + +/* documented in dbus-watch.c */ +typedef struct DBusWatch DBusWatch; +/* documented in dbus-timeout.c */ +typedef struct DBusTimeout DBusTimeout; +/** Opaque type representing preallocated resources so a message can be sent without further memory allocation. */ +typedef struct DBusPreallocatedSend DBusPreallocatedSend; +/** Opaque type representing a method call that has not yet received a reply. */ +typedef struct DBusPendingCall DBusPendingCall; +/** Opaque type representing a connection to a remote application and associated incoming/outgoing message queues. */ +typedef struct DBusConnection DBusConnection; +/** Set of functions that must be implemented to handle messages sent to a particular object path. */ +typedef struct DBusObjectPathVTable DBusObjectPathVTable; + +/** + * Indicates the status of a #DBusWatch. + */ +typedef enum +{ + DBUS_WATCH_READABLE = 1 << 0, /**< As in POLLIN */ + DBUS_WATCH_WRITABLE = 1 << 1, /**< As in POLLOUT */ + DBUS_WATCH_ERROR = 1 << 2, /**< As in POLLERR (can't watch for + * this, but can be present in + * current state passed to + * dbus_watch_handle()). + */ + DBUS_WATCH_HANGUP = 1 << 3 /**< As in POLLHUP (can't watch for + * it, but can be present in current + * state passed to + * dbus_watch_handle()). + */ +} DBusWatchFlags; + +/** + * Indicates the status of incoming data on a #DBusConnection. This determines whether + * dbus_connection_dispatch() needs to be called. + */ +typedef enum +{ + DBUS_DISPATCH_DATA_REMAINS, /**< There is more data to potentially convert to messages. */ + DBUS_DISPATCH_COMPLETE, /**< All currently available data has been processed. */ + DBUS_DISPATCH_NEED_MEMORY /**< More memory is needed to continue. */ +} DBusDispatchStatus; + +/** Called when libdbus needs a new watch to be monitored by the main + * loop. Returns #FALSE if it lacks enough memory to add the + * watch. Set by dbus_connection_set_watch_functions() or + * dbus_server_set_watch_functions(). + */ +typedef dbus_bool_t (* DBusAddWatchFunction) (DBusWatch *watch, + void *data); +/** Called when dbus_watch_get_enabled() may return a different value + * than it did before. Set by dbus_connection_set_watch_functions() + * or dbus_server_set_watch_functions(). + */ +typedef void (* DBusWatchToggledFunction) (DBusWatch *watch, + void *data); +/** Called when libdbus no longer needs a watch to be monitored by the + * main loop. Set by dbus_connection_set_watch_functions() or + * dbus_server_set_watch_functions(). + */ +typedef void (* DBusRemoveWatchFunction) (DBusWatch *watch, + void *data); +/** Called when libdbus needs a new timeout to be monitored by the main + * loop. Returns #FALSE if it lacks enough memory to add the + * watch. Set by dbus_connection_set_timeout_functions() or + * dbus_server_set_timeout_functions(). + */ +typedef dbus_bool_t (* DBusAddTimeoutFunction) (DBusTimeout *timeout, + void *data); +/** Called when dbus_timeout_get_enabled() may return a different + * value than it did before. + * Set by dbus_connection_set_timeout_functions() or + * dbus_server_set_timeout_functions(). + */ +typedef void (* DBusTimeoutToggledFunction) (DBusTimeout *timeout, + void *data); +/** Called when libdbus no longer needs a timeout to be monitored by the + * main loop. Set by dbus_connection_set_timeout_functions() or + * dbus_server_set_timeout_functions(). + */ +typedef void (* DBusRemoveTimeoutFunction) (DBusTimeout *timeout, + void *data); +/** Called when the return value of dbus_connection_get_dispatch_status() + * may have changed. Set with dbus_connection_set_dispatch_status_function(). + */ +typedef void (* DBusDispatchStatusFunction) (DBusConnection *connection, + DBusDispatchStatus new_status, + void *data); +/** + * Called when the main loop's thread should be notified that there's now work + * to do. Set with dbus_connection_set_wakeup_main_function(). + */ +typedef void (* DBusWakeupMainFunction) (void *data); + +/** + * Called during authentication to check whether the given UNIX user + * ID is allowed to connect, if the client tried to auth as a UNIX + * user ID. Normally on Windows this would never happen. Set with + * dbus_connection_set_unix_user_function(). + */ +typedef dbus_bool_t (* DBusAllowUnixUserFunction) (DBusConnection *connection, + unsigned long uid, + void *data); + +/** + * Called during authentication to check whether the given Windows user + * ID is allowed to connect, if the client tried to auth as a Windows + * user ID. Normally on UNIX this would never happen. Set with + * dbus_connection_set_windows_user_function(). + */ +typedef dbus_bool_t (* DBusAllowWindowsUserFunction) (DBusConnection *connection, + const char *user_sid, + void *data); + + +/** + * Called when a pending call now has a reply available. Set with + * dbus_pending_call_set_notify(). + */ +typedef void (* DBusPendingCallNotifyFunction) (DBusPendingCall *pending, + void *user_data); + +/** + * Called when a message needs to be handled. The result indicates whether or + * not more handlers should be run. Set with dbus_connection_add_filter(). + */ +typedef DBusHandlerResult (* DBusHandleMessageFunction) (DBusConnection *connection, + DBusMessage *message, + void *user_data); + +DBusConnection* dbus_connection_open (const char *address, + DBusError *error); +DBusConnection* dbus_connection_open_private (const char *address, + DBusError *error); +DBusConnection* dbus_connection_ref (DBusConnection *connection); +void dbus_connection_unref (DBusConnection *connection); +void dbus_connection_close (DBusConnection *connection); +dbus_bool_t dbus_connection_get_is_connected (DBusConnection *connection); +dbus_bool_t dbus_connection_get_is_authenticated (DBusConnection *connection); +dbus_bool_t dbus_connection_get_is_anonymous (DBusConnection *connection); +char* dbus_connection_get_server_id (DBusConnection *connection); +void dbus_connection_set_exit_on_disconnect (DBusConnection *connection, + dbus_bool_t exit_on_disconnect); +void dbus_connection_flush (DBusConnection *connection); +dbus_bool_t dbus_connection_read_write_dispatch (DBusConnection *connection, + int timeout_milliseconds); +dbus_bool_t dbus_connection_read_write (DBusConnection *connection, + int timeout_milliseconds); +DBusMessage* dbus_connection_borrow_message (DBusConnection *connection); +void dbus_connection_return_message (DBusConnection *connection, + DBusMessage *message); +void dbus_connection_steal_borrowed_message (DBusConnection *connection, + DBusMessage *message); +DBusMessage* dbus_connection_pop_message (DBusConnection *connection); +DBusDispatchStatus dbus_connection_get_dispatch_status (DBusConnection *connection); +DBusDispatchStatus dbus_connection_dispatch (DBusConnection *connection); +dbus_bool_t dbus_connection_has_messages_to_send (DBusConnection *connection); +dbus_bool_t dbus_connection_send (DBusConnection *connection, + DBusMessage *message, + dbus_uint32_t *client_serial); +dbus_bool_t dbus_connection_send_with_reply (DBusConnection *connection, + DBusMessage *message, + DBusPendingCall **pending_return, + int timeout_milliseconds); +DBusMessage * dbus_connection_send_with_reply_and_block (DBusConnection *connection, + DBusMessage *message, + int timeout_milliseconds, + DBusError *error); +dbus_bool_t dbus_connection_set_watch_functions (DBusConnection *connection, + DBusAddWatchFunction add_function, + DBusRemoveWatchFunction remove_function, + DBusWatchToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t dbus_connection_set_timeout_functions (DBusConnection *connection, + DBusAddTimeoutFunction add_function, + DBusRemoveTimeoutFunction remove_function, + DBusTimeoutToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function); +void dbus_connection_set_wakeup_main_function (DBusConnection *connection, + DBusWakeupMainFunction wakeup_main_function, + void *data, + DBusFreeFunction free_data_function); +void dbus_connection_set_dispatch_status_function (DBusConnection *connection, + DBusDispatchStatusFunction function, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t dbus_connection_get_unix_user (DBusConnection *connection, + unsigned long *uid); +dbus_bool_t dbus_connection_get_unix_process_id (DBusConnection *connection, + unsigned long *pid); +dbus_bool_t dbus_connection_get_adt_audit_session_data (DBusConnection *connection, + void **data, + dbus_int32_t *data_size); +void dbus_connection_set_unix_user_function (DBusConnection *connection, + DBusAllowUnixUserFunction function, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t dbus_connection_get_windows_user (DBusConnection *connection, + char **windows_sid_p); +void dbus_connection_set_windows_user_function (DBusConnection *connection, + DBusAllowWindowsUserFunction function, + void *data, + DBusFreeFunction free_data_function); +void dbus_connection_set_allow_anonymous (DBusConnection *connection, + dbus_bool_t value); +void dbus_connection_set_route_peer_messages (DBusConnection *connection, + dbus_bool_t value); + + +/* Filters */ + +dbus_bool_t dbus_connection_add_filter (DBusConnection *connection, + DBusHandleMessageFunction function, + void *user_data, + DBusFreeFunction free_data_function); +void dbus_connection_remove_filter (DBusConnection *connection, + DBusHandleMessageFunction function, + void *user_data); + + +/* Other */ +dbus_bool_t dbus_connection_allocate_data_slot (dbus_int32_t *slot_p); +void dbus_connection_free_data_slot (dbus_int32_t *slot_p); +dbus_bool_t dbus_connection_set_data (DBusConnection *connection, + dbus_int32_t slot, + void *data, + DBusFreeFunction free_data_func); +void* dbus_connection_get_data (DBusConnection *connection, + dbus_int32_t slot); + +void dbus_connection_set_change_sigpipe (dbus_bool_t will_modify_sigpipe); + +void dbus_connection_set_max_message_size (DBusConnection *connection, + long size); +long dbus_connection_get_max_message_size (DBusConnection *connection); +void dbus_connection_set_max_received_size (DBusConnection *connection, + long size); +long dbus_connection_get_max_received_size (DBusConnection *connection); +long dbus_connection_get_outgoing_size (DBusConnection *connection); + +DBusPreallocatedSend* dbus_connection_preallocate_send (DBusConnection *connection); +void dbus_connection_free_preallocated_send (DBusConnection *connection, + DBusPreallocatedSend *preallocated); +void dbus_connection_send_preallocated (DBusConnection *connection, + DBusPreallocatedSend *preallocated, + DBusMessage *message, + dbus_uint32_t *client_serial); + + +/* Object tree functionality */ + +/** + * Called when a #DBusObjectPathVTable is unregistered (or its connection is freed). + * Found in #DBusObjectPathVTable. + */ +typedef void (* DBusObjectPathUnregisterFunction) (DBusConnection *connection, + void *user_data); +/** + * Called when a message is sent to a registered object path. Found in + * #DBusObjectPathVTable which is registered with dbus_connection_register_object_path() + * or dbus_connection_register_fallback(). + */ +typedef DBusHandlerResult (* DBusObjectPathMessageFunction) (DBusConnection *connection, + DBusMessage *message, + void *user_data); + +/** + * Virtual table that must be implemented to handle a portion of the + * object path hierarchy. Attach the vtable to a particular path using + * dbus_connection_register_object_path() or + * dbus_connection_register_fallback(). + */ +struct DBusObjectPathVTable +{ + DBusObjectPathUnregisterFunction unregister_function; /**< Function to unregister this handler */ + DBusObjectPathMessageFunction message_function; /**< Function to handle messages */ + + void (* dbus_internal_pad1) (void *); /**< Reserved for future expansion */ + void (* dbus_internal_pad2) (void *); /**< Reserved for future expansion */ + void (* dbus_internal_pad3) (void *); /**< Reserved for future expansion */ + void (* dbus_internal_pad4) (void *); /**< Reserved for future expansion */ +}; + +dbus_bool_t dbus_connection_try_register_object_path (DBusConnection *connection, + const char *path, + const DBusObjectPathVTable *vtable, + void *user_data, + DBusError *error); + +dbus_bool_t dbus_connection_register_object_path (DBusConnection *connection, + const char *path, + const DBusObjectPathVTable *vtable, + void *user_data); + +dbus_bool_t dbus_connection_try_register_fallback (DBusConnection *connection, + const char *path, + const DBusObjectPathVTable *vtable, + void *user_data, + DBusError *error); + +dbus_bool_t dbus_connection_register_fallback (DBusConnection *connection, + const char *path, + const DBusObjectPathVTable *vtable, + void *user_data); +dbus_bool_t dbus_connection_unregister_object_path (DBusConnection *connection, + const char *path); + +dbus_bool_t dbus_connection_get_object_path_data (DBusConnection *connection, + const char *path, + void **data_p); + +dbus_bool_t dbus_connection_list_registered (DBusConnection *connection, + const char *parent_path, + char ***child_entries); + +dbus_bool_t dbus_connection_get_unix_fd (DBusConnection *connection, + int *fd); +dbus_bool_t dbus_connection_get_socket (DBusConnection *connection, + int *fd); + +/** @} */ + + +/** + * @addtogroup DBusWatch + * @{ + */ + +#ifndef DBUS_DISABLE_DEPRECATED +DBUS_DEPRECATED int dbus_watch_get_fd (DBusWatch *watch); +#endif + +int dbus_watch_get_unix_fd (DBusWatch *watch); +int dbus_watch_get_socket (DBusWatch *watch); +unsigned int dbus_watch_get_flags (DBusWatch *watch); +void* dbus_watch_get_data (DBusWatch *watch); +void dbus_watch_set_data (DBusWatch *watch, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t dbus_watch_handle (DBusWatch *watch, + unsigned int flags); +dbus_bool_t dbus_watch_get_enabled (DBusWatch *watch); + +/** @} */ + +/** + * @addtogroup DBusTimeout + * @{ + */ + +int dbus_timeout_get_interval (DBusTimeout *timeout); +void* dbus_timeout_get_data (DBusTimeout *timeout); +void dbus_timeout_set_data (DBusTimeout *timeout, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t dbus_timeout_handle (DBusTimeout *timeout); +dbus_bool_t dbus_timeout_get_enabled (DBusTimeout *timeout); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_CONNECTION_H */ diff --git a/dbus/dbus-credentials-util.c b/dbus/dbus-credentials-util.c new file mode 100644 index 00000000..dae6080d --- /dev/null +++ b/dbus/dbus-credentials-util.c @@ -0,0 +1,204 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-credentials-util.c Would be in dbus-credentials.c, but only used for tests/bus + * + * Copyright (C) 2007 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-internals.h" +#include "dbus-test.h" +#include "dbus-credentials.h" + +/** + * @addtogroup DBusCredentials + * @{ + */ + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include +#include + +static DBusCredentials* +make_credentials(dbus_uid_t unix_uid, + dbus_pid_t unix_pid, + const char *windows_sid) +{ + DBusCredentials *credentials; + + credentials = _dbus_credentials_new (); + + if (unix_uid != DBUS_UID_UNSET) + { + if (!_dbus_credentials_add_unix_uid (credentials, unix_uid)) + { + _dbus_credentials_unref (credentials); + return NULL; + } + } + + if (unix_pid != DBUS_PID_UNSET) + { + if (!_dbus_credentials_add_unix_pid (credentials, unix_pid)) + { + _dbus_credentials_unref (credentials); + return NULL; + } + } + + if (windows_sid != NULL) + { + if (!_dbus_credentials_add_windows_sid (credentials, windows_sid)) + { + _dbus_credentials_unref (credentials); + return NULL; + } + } + + return credentials; +} + +#define SAMPLE_SID "whatever a windows sid looks like" +#define OTHER_SAMPLE_SID "whatever else" + +dbus_bool_t +_dbus_credentials_test (const char *test_data_dir) +{ + DBusCredentials *creds; + DBusCredentials *creds2; + + if (test_data_dir == NULL) + return TRUE; + + creds = make_credentials (12, 511, SAMPLE_SID); + if (creds == NULL) + _dbus_assert_not_reached ("oom"); + + /* test refcounting */ + _dbus_credentials_ref (creds); + _dbus_credentials_unref (creds); + + _dbus_assert (_dbus_credentials_include (creds, DBUS_CREDENTIAL_UNIX_USER_ID)); + _dbus_assert (_dbus_credentials_include (creds, DBUS_CREDENTIAL_UNIX_PROCESS_ID)); + _dbus_assert (_dbus_credentials_include (creds, DBUS_CREDENTIAL_WINDOWS_SID)); + + _dbus_assert (_dbus_credentials_get_unix_uid (creds) == 12); + _dbus_assert (_dbus_credentials_get_unix_pid (creds) == 511); + _dbus_assert (strcmp (_dbus_credentials_get_windows_sid (creds), SAMPLE_SID) == 0); + + _dbus_assert (!_dbus_credentials_are_empty (creds)); + _dbus_assert (!_dbus_credentials_are_anonymous (creds)); + + /* Test copy */ + creds2 = _dbus_credentials_copy (creds); + if (creds2 == NULL) + _dbus_assert_not_reached ("oom"); + + _dbus_assert (_dbus_credentials_include (creds2, DBUS_CREDENTIAL_UNIX_USER_ID)); + _dbus_assert (_dbus_credentials_include (creds2, DBUS_CREDENTIAL_UNIX_PROCESS_ID)); + _dbus_assert (_dbus_credentials_include (creds2, DBUS_CREDENTIAL_WINDOWS_SID)); + + _dbus_assert (_dbus_credentials_get_unix_uid (creds2) == 12); + _dbus_assert (_dbus_credentials_get_unix_pid (creds2) == 511); + _dbus_assert (strcmp (_dbus_credentials_get_windows_sid (creds2), SAMPLE_SID) == 0); + + _dbus_assert (_dbus_credentials_are_superset (creds, creds2)); + + _dbus_credentials_unref (creds2); + + /* Same user if both unix and windows are the same */ + creds2 = make_credentials (12, DBUS_PID_UNSET, SAMPLE_SID); + if (creds2 == NULL) + _dbus_assert_not_reached ("oom"); + + _dbus_assert (_dbus_credentials_same_user (creds, creds2)); + + _dbus_credentials_unref (creds2); + + /* Not the same user if Windows is missing */ + creds2 = make_credentials (12, DBUS_PID_UNSET, NULL); + if (creds2 == NULL) + _dbus_assert_not_reached ("oom"); + + _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); + _dbus_assert (_dbus_credentials_are_superset (creds, creds2)); + + _dbus_credentials_unref (creds2); + + /* Not the same user if Windows is different */ + creds2 = make_credentials (12, DBUS_PID_UNSET, OTHER_SAMPLE_SID); + if (creds2 == NULL) + _dbus_assert_not_reached ("oom"); + + _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); + _dbus_assert (!_dbus_credentials_are_superset (creds, creds2)); + + _dbus_credentials_unref (creds2); + + /* Not the same user if Unix is missing */ + creds2 = make_credentials (DBUS_UID_UNSET, DBUS_PID_UNSET, SAMPLE_SID); + if (creds2 == NULL) + _dbus_assert_not_reached ("oom"); + + _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); + _dbus_assert (_dbus_credentials_are_superset (creds, creds2)); + + _dbus_credentials_unref (creds2); + + /* Not the same user if Unix is different */ + creds2 = make_credentials (15, DBUS_PID_UNSET, SAMPLE_SID); + if (creds2 == NULL) + _dbus_assert_not_reached ("oom"); + + _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); + _dbus_assert (!_dbus_credentials_are_superset (creds, creds2)); + + _dbus_credentials_unref (creds2); + + /* Not the same user if both are missing */ + creds2 = make_credentials (DBUS_UID_UNSET, DBUS_PID_UNSET, NULL); + if (creds2 == NULL) + _dbus_assert_not_reached ("oom"); + + _dbus_assert (!_dbus_credentials_same_user (creds, creds2)); + _dbus_assert (_dbus_credentials_are_superset (creds, creds2)); + + _dbus_credentials_unref (creds2); + + /* Clearing credentials works */ + _dbus_credentials_clear (creds); + + _dbus_assert (!_dbus_credentials_include (creds, DBUS_CREDENTIAL_UNIX_USER_ID)); + _dbus_assert (!_dbus_credentials_include (creds, DBUS_CREDENTIAL_UNIX_PROCESS_ID)); + _dbus_assert (!_dbus_credentials_include (creds, DBUS_CREDENTIAL_WINDOWS_SID)); + + _dbus_assert (_dbus_credentials_get_unix_uid (creds) == DBUS_UID_UNSET); + _dbus_assert (_dbus_credentials_get_unix_pid (creds) == DBUS_PID_UNSET); + _dbus_assert (_dbus_credentials_get_windows_sid (creds) == NULL); + + _dbus_assert (_dbus_credentials_are_empty (creds)); + _dbus_assert (_dbus_credentials_are_anonymous (creds)); + + _dbus_credentials_unref (creds); + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-credentials.c b/dbus/dbus-credentials.c new file mode 100644 index 00000000..ff69f3b0 --- /dev/null +++ b/dbus/dbus-credentials.c @@ -0,0 +1,550 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-credentials.c Credentials provable through authentication + * + * Copyright (C) 2007 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include +#include +#include "dbus-credentials.h" +#include "dbus-internals.h" + +/** + * @defgroup DBusCredentials Credentials provable through authentication + * @ingroup DBusInternals + * @brief DBusCredentials object + * + * Credentials are what you have to prove you have in order to + * authenticate. The main credentials right now are a unix user + * account, a Windows user account, or a UNIX process ID. + */ + +/** + * @defgroup DBusCredentialsInternals Credentials implementation details + * @ingroup DBusInternals + * @brief DBusCredentials implementation details + * + * Private details of credentials code. + * + * @{ + */ + +struct DBusCredentials { + int refcount; + dbus_uid_t unix_uid; + dbus_pid_t unix_pid; + char *windows_sid; + void *adt_audit_data; + dbus_int32_t adt_audit_data_size; +}; + +/** @} */ + +/** + * @addtogroup DBusCredentials + * @{ + */ + +/** + * Creates a new credentials object. + * + * @returns the new object or #NULL if no memory + */ +DBusCredentials* +_dbus_credentials_new (void) +{ + DBusCredentials *creds; + + creds = dbus_new (DBusCredentials, 1); + if (creds == NULL) + return NULL; + + creds->refcount = 1; + creds->unix_uid = DBUS_UID_UNSET; + creds->unix_pid = DBUS_PID_UNSET; + creds->windows_sid = NULL; + creds->adt_audit_data = NULL; + creds->adt_audit_data_size = 0; + + return creds; +} + +/** + * Creates a new object with credentials (user ID and process ID) from the current process. + * @returns the new object or #NULL if no memory + */ +DBusCredentials* +_dbus_credentials_new_from_current_process (void) +{ + DBusCredentials *creds; + + creds = _dbus_credentials_new (); + if (creds == NULL) + return NULL; + + if (!_dbus_credentials_add_from_current_process (creds)) + { + _dbus_credentials_unref (creds); + return NULL; + } + + return creds; +} + +/** + * Increment refcount on credentials. + * + * @param credentials the object + */ +void +_dbus_credentials_ref (DBusCredentials *credentials) +{ + _dbus_assert (credentials->refcount > 0); + credentials->refcount += 1; +} + +/** + * Decrement refcount on credentials. + * + * @param credentials the object + */ +void +_dbus_credentials_unref (DBusCredentials *credentials) +{ + _dbus_assert (credentials->refcount > 0); + + credentials->refcount -= 1; + if (credentials->refcount == 0) + { + dbus_free (credentials->windows_sid); + dbus_free (credentials->adt_audit_data); + dbus_free (credentials); + } +} + +/** + * Add a UNIX process ID to the credentials. + * + * @param credentials the object + * @param pid the process ID + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_add_unix_pid (DBusCredentials *credentials, + dbus_pid_t pid) +{ + credentials->unix_pid = pid; + return TRUE; +} + +/** + * Add a UNIX user ID to the credentials. + * + * @param credentials the object + * @param uid the user ID + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_add_unix_uid(DBusCredentials *credentials, + dbus_uid_t uid) +{ + credentials->unix_uid = uid; + return TRUE; + +} + +/** + * Add a Windows user SID to the credentials. + * + * @param credentials the object + * @param windows_sid the user SID + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_add_windows_sid (DBusCredentials *credentials, + const char *windows_sid) +{ + char *copy; + + copy = _dbus_strdup (windows_sid); + if (copy == NULL) + return FALSE; + + dbus_free (credentials->windows_sid); + credentials->windows_sid = copy; + + return TRUE; +} + +/** + * Add ADT audit data to the credentials. + * + * @param credentials the object + * @param audit_data the audit data + * @param size the length of audit data + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_add_adt_audit_data (DBusCredentials *credentials, + void *audit_data, + dbus_int32_t size) +{ + void *copy; + copy = _dbus_memdup (audit_data, size); + if (copy == NULL) + return FALSE; + + dbus_free (credentials->adt_audit_data); + credentials->adt_audit_data = copy; + credentials->adt_audit_data_size = size; + + return TRUE; +} + +/** + * Checks whether the given credential is present. + * + * @param credentials the object + * @param type the credential to check for + * @returns #TRUE if the credential is present + */ +dbus_bool_t +_dbus_credentials_include (DBusCredentials *credentials, + DBusCredentialType type) +{ + switch (type) + { + case DBUS_CREDENTIAL_UNIX_PROCESS_ID: + return credentials->unix_pid != DBUS_PID_UNSET; + case DBUS_CREDENTIAL_UNIX_USER_ID: + return credentials->unix_uid != DBUS_UID_UNSET; + case DBUS_CREDENTIAL_WINDOWS_SID: + return credentials->windows_sid != NULL; + case DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID: + return credentials->adt_audit_data != NULL; + } + + _dbus_assert_not_reached ("Unknown credential enum value"); + return FALSE; +} + +/** + * Gets the UNIX process ID in the credentials, or #DBUS_PID_UNSET if + * the credentials object doesn't contain a process ID. + * + * @param credentials the object + * @returns UNIX process ID + */ +dbus_pid_t +_dbus_credentials_get_unix_pid (DBusCredentials *credentials) +{ + return credentials->unix_pid; +} + +/** + * Gets the UNIX user ID in the credentials, or #DBUS_UID_UNSET if + * the credentials object doesn't contain a user ID. + * + * @param credentials the object + * @returns UNIX user ID + */ +dbus_uid_t +_dbus_credentials_get_unix_uid (DBusCredentials *credentials) +{ + return credentials->unix_uid; +} + +/** + * Gets the Windows user SID in the credentials, or #NULL if + * the credentials object doesn't contain a Windows user SID. + * + * @param credentials the object + * @returns Windows user SID + */ +const char* +_dbus_credentials_get_windows_sid (DBusCredentials *credentials) +{ + return credentials->windows_sid; +} + +/** + * Gets the ADT audit data in the credentials, or #NULL if + * the credentials object doesn't contain ADT audit data. + * + * @param credentials the object + * @returns Solaris ADT audit data + */ +void * +_dbus_credentials_get_adt_audit_data (DBusCredentials *credentials) +{ + return credentials->adt_audit_data; +} + +/** + * Gets the ADT audit data size in the credentials, or 0 if + * the credentials object doesn't contain ADT audit data. + * + * @param credentials the object + * @returns Solaris ADT audit data size + */ +dbus_int32_t +_dbus_credentials_get_adt_audit_data_size (DBusCredentials *credentials) +{ + return credentials->adt_audit_data_size; +} + +/** + * Checks whether the first credentials object contains + * all the credentials found in the second credentials object. + * + * @param credentials the object + * @param possible_subset see if credentials in here are also in the first arg + * @returns #TRUE if second arg is contained in first + */ +dbus_bool_t +_dbus_credentials_are_superset (DBusCredentials *credentials, + DBusCredentials *possible_subset) +{ + return + (possible_subset->unix_pid == DBUS_PID_UNSET || + possible_subset->unix_pid == credentials->unix_pid) && + (possible_subset->unix_uid == DBUS_UID_UNSET || + possible_subset->unix_uid == credentials->unix_uid) && + (possible_subset->windows_sid == NULL || + (credentials->windows_sid && strcmp (possible_subset->windows_sid, + credentials->windows_sid) == 0)) && + (possible_subset->adt_audit_data == NULL || + (credentials->adt_audit_data && memcmp (possible_subset->adt_audit_data, + credentials->adt_audit_data, + credentials->adt_audit_data_size) == 0)); +} + +/** + * Checks whether a credentials object contains anything. + * + * @param credentials the object + * @returns #TRUE if there are no credentials in the object + */ +dbus_bool_t +_dbus_credentials_are_empty (DBusCredentials *credentials) +{ + return + credentials->unix_pid == DBUS_PID_UNSET && + credentials->unix_uid == DBUS_UID_UNSET && + credentials->windows_sid == NULL && + credentials->adt_audit_data == NULL; +} + +/** + * Checks whether a credentials object contains a user identity. + * + * @param credentials the object + * @returns #TRUE if there are no user identities in the object + */ +dbus_bool_t +_dbus_credentials_are_anonymous (DBusCredentials *credentials) +{ + return + credentials->unix_uid == DBUS_UID_UNSET && + credentials->windows_sid == NULL; +} + +/** + * Merge all credentials found in the second object into the first object, + * overwriting the first object if there are any overlaps. + * + * @param credentials the object + * @param other_credentials credentials to merge + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_add_credentials (DBusCredentials *credentials, + DBusCredentials *other_credentials) +{ + return + _dbus_credentials_add_credential (credentials, + DBUS_CREDENTIAL_UNIX_PROCESS_ID, + other_credentials) && + _dbus_credentials_add_credential (credentials, + DBUS_CREDENTIAL_UNIX_USER_ID, + other_credentials) && + _dbus_credentials_add_credential (credentials, + DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, + other_credentials) && + _dbus_credentials_add_credential (credentials, + DBUS_CREDENTIAL_WINDOWS_SID, + other_credentials); +} + +/** + * Merge the given credential found in the second object into the first object, + * overwriting the first object's value for that credential. + * + * Does nothing if the second object does not contain the specified credential. + * i.e., will never delete a credential from the first object. + * + * @param credentials the object + * @param which the credential to overwrite + * @param other_credentials credentials to merge + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_add_credential (DBusCredentials *credentials, + DBusCredentialType which, + DBusCredentials *other_credentials) +{ + if (which == DBUS_CREDENTIAL_UNIX_PROCESS_ID && + other_credentials->unix_pid != DBUS_PID_UNSET) + { + if (!_dbus_credentials_add_unix_pid (credentials, other_credentials->unix_pid)) + return FALSE; + } + else if (which == DBUS_CREDENTIAL_UNIX_USER_ID && + other_credentials->unix_uid != DBUS_UID_UNSET) + { + if (!_dbus_credentials_add_unix_uid (credentials, other_credentials->unix_uid)) + return FALSE; + } + else if (which == DBUS_CREDENTIAL_WINDOWS_SID && + other_credentials->windows_sid != NULL) + { + if (!_dbus_credentials_add_windows_sid (credentials, other_credentials->windows_sid)) + return FALSE; + } + else if (which == DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID && + other_credentials->adt_audit_data != NULL) + { + if (!_dbus_credentials_add_adt_audit_data (credentials, other_credentials->adt_audit_data, other_credentials->adt_audit_data_size)) + return FALSE; + } + + return TRUE; +} + +/** + * Clear all credentials in the object. + * + * @param credentials the object + */ +void +_dbus_credentials_clear (DBusCredentials *credentials) +{ + credentials->unix_pid = DBUS_PID_UNSET; + credentials->unix_uid = DBUS_UID_UNSET; + dbus_free (credentials->windows_sid); + credentials->windows_sid = NULL; + dbus_free (credentials->adt_audit_data); + credentials->adt_audit_data = NULL; + credentials->adt_audit_data_size = 0; +} + +/** + * Copy a credentials object. + * + * @param credentials the object + * @returns the copy or #NULL + */ +DBusCredentials* +_dbus_credentials_copy (DBusCredentials *credentials) +{ + DBusCredentials *copy; + + copy = _dbus_credentials_new (); + if (copy == NULL) + return NULL; + + if (!_dbus_credentials_add_credentials (copy, credentials)) + { + _dbus_credentials_unref (copy); + return NULL; + } + + return copy; +} + +/** + * Check whether the user-identifying credentials in two credentials + * objects are identical. Credentials that are not related to the + * user are ignored, but any kind of user ID credentials must be the + * same (UNIX user ID, Windows user SID, etc.) and present in both + * objects for the function to return #TRUE. + * + * @param credentials the object + * @param other_credentials credentials to compare + * @returns #TRUE if the two credentials refer to the same user + */ +dbus_bool_t +_dbus_credentials_same_user (DBusCredentials *credentials, + DBusCredentials *other_credentials) +{ + /* both windows and unix user must be the same (though pretty much + * in all conceivable cases, one will be unset) + */ + return credentials->unix_uid == other_credentials->unix_uid && + ((!(credentials->windows_sid || other_credentials->windows_sid)) || + (credentials->windows_sid && other_credentials->windows_sid && + strcmp (credentials->windows_sid, other_credentials->windows_sid) == 0)); +} + +/** + * Convert the credentials in this object to a human-readable + * string format, and append to the given string. + * + * @param credentials the object + * @param string append to this string + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_to_string_append (DBusCredentials *credentials, + DBusString *string) +{ + dbus_bool_t join; + + join = FALSE; + if (credentials->unix_uid != DBUS_UID_UNSET) + { + if (!_dbus_string_append_printf (string, "uid=" DBUS_UID_FORMAT, credentials->unix_uid)) + goto oom; + join = TRUE; + } + if (credentials->unix_pid != DBUS_PID_UNSET) + { + if (!_dbus_string_append_printf (string, "%spid=" DBUS_PID_FORMAT, join ? " " : "", credentials->unix_pid)) + goto oom; + join = TRUE; + } + else + join = FALSE; + if (credentials->windows_sid != NULL) + { + if (!_dbus_string_append_printf (string, "%ssid=%s", join ? " " : "", credentials->windows_sid)) + goto oom; + join = TRUE; + } + else + join = FALSE; + + return TRUE; +oom: + return FALSE; +} + +/** @} */ + +/* tests in dbus-credentials-util.c */ diff --git a/dbus/dbus-credentials.h b/dbus/dbus-credentials.h new file mode 100644 index 00000000..ef6124fd --- /dev/null +++ b/dbus/dbus-credentials.h @@ -0,0 +1,79 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-credentials.h Credentials provable through authentication + * + * Copyright (C) 2007 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_CREDENTIALS_H +#define DBUS_CREDENTIALS_H + +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +typedef enum { + DBUS_CREDENTIAL_UNIX_PROCESS_ID, + DBUS_CREDENTIAL_UNIX_USER_ID, + DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, + DBUS_CREDENTIAL_WINDOWS_SID +} DBusCredentialType; + +DBusCredentials* _dbus_credentials_new_from_current_process (void); +DBusCredentials* _dbus_credentials_new (void); +void _dbus_credentials_ref (DBusCredentials *credentials); +void _dbus_credentials_unref (DBusCredentials *credentials); +dbus_bool_t _dbus_credentials_add_unix_pid (DBusCredentials *credentials, + dbus_pid_t pid); +dbus_bool_t _dbus_credentials_add_unix_uid (DBusCredentials *credentials, + dbus_uid_t uid); +dbus_bool_t _dbus_credentials_add_windows_sid (DBusCredentials *credentials, + const char *windows_sid); +dbus_bool_t _dbus_credentials_add_adt_audit_data (DBusCredentials *credentials, + void *audit_data, + dbus_int32_t size); +dbus_bool_t _dbus_credentials_include (DBusCredentials *credentials, + DBusCredentialType type); +dbus_pid_t _dbus_credentials_get_unix_pid (DBusCredentials *credentials); +dbus_uid_t _dbus_credentials_get_unix_uid (DBusCredentials *credentials); +const char* _dbus_credentials_get_windows_sid (DBusCredentials *credentials); +void * _dbus_credentials_get_adt_audit_data (DBusCredentials *credentials); +dbus_int32_t _dbus_credentials_get_adt_audit_data_size (DBusCredentials *credentials); +dbus_bool_t _dbus_credentials_are_superset (DBusCredentials *credentials, + DBusCredentials *possible_subset); +dbus_bool_t _dbus_credentials_are_empty (DBusCredentials *credentials); +dbus_bool_t _dbus_credentials_are_anonymous (DBusCredentials *credentials); +dbus_bool_t _dbus_credentials_add_credentials (DBusCredentials *credentials, + DBusCredentials *other_credentials); +/* must silently allow 'which' to not exist */ +dbus_bool_t _dbus_credentials_add_credential (DBusCredentials *credentials, + DBusCredentialType which, + DBusCredentials *other_credentials); +void _dbus_credentials_clear (DBusCredentials *credentials); +DBusCredentials* _dbus_credentials_copy (DBusCredentials *credentials); +dbus_bool_t _dbus_credentials_same_user (DBusCredentials *credentials, + DBusCredentials *other_credentials); +dbus_bool_t _dbus_credentials_to_string_append (DBusCredentials *credentials, + DBusString *string); + +DBUS_END_DECLS + +#endif /* DBUS_CREDENTIALS_H */ diff --git a/dbus/dbus-dataslot.c b/dbus/dbus-dataslot.c new file mode 100644 index 00000000..8fab7bbc --- /dev/null +++ b/dbus/dbus-dataslot.c @@ -0,0 +1,477 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-dataslot.c storing data on objects + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-dataslot.h" +#include "dbus-threads-internal.h" + +/** + * @defgroup DBusDataSlot Data slots + * @ingroup DBusInternals + * @brief Storing data by ID + * + * Types and functions related to storing data by an + * allocated ID. This is used for dbus_connection_set_data(), + * dbus_server_set_data(), etc. + * @{ + */ + +/** + * Initializes a data slot allocator object, used to assign + * integer IDs for data slots. + * + * @param allocator the allocator to initialize + */ +dbus_bool_t +_dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator) +{ + allocator->allocated_slots = NULL; + allocator->n_allocated_slots = 0; + allocator->n_used_slots = 0; + allocator->lock_loc = NULL; + + return TRUE; +} + +/** + * Allocates an integer ID to be used for storing data + * in a #DBusDataSlotList. If the value at *slot_id_p is + * not -1, this function just increments the refcount for + * the existing slot ID. If the value is -1, a new slot ID + * is allocated and stored at *slot_id_p. + * + * @param allocator the allocator + * @param mutex_loc the location lock for this allocator + * @param slot_id_p address to fill with the slot ID + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator, + DBusMutex **mutex_loc, + dbus_int32_t *slot_id_p) +{ + dbus_int32_t slot; + + _dbus_mutex_lock (*mutex_loc); + + if (allocator->n_allocated_slots == 0) + { + _dbus_assert (allocator->lock_loc == NULL); + allocator->lock_loc = mutex_loc; + } + else if (allocator->lock_loc != mutex_loc) + { + _dbus_warn_check_failed ("D-Bus threads were initialized after first using the D-Bus library. If your application does not directly initialize threads or use D-Bus, keep in mind that some library or plugin may have used D-Bus or initialized threads behind your back. You can often fix this problem by calling dbus_init_threads() or dbus_g_threads_init() early in your main() method, before D-Bus is used.\n"); + _dbus_assert_not_reached ("exiting"); + } + + if (*slot_id_p >= 0) + { + slot = *slot_id_p; + + _dbus_assert (slot < allocator->n_allocated_slots); + _dbus_assert (allocator->allocated_slots[slot].slot_id == slot); + + allocator->allocated_slots[slot].refcount += 1; + + goto out; + } + + _dbus_assert (*slot_id_p < 0); + + if (allocator->n_used_slots < allocator->n_allocated_slots) + { + slot = 0; + while (slot < allocator->n_allocated_slots) + { + if (allocator->allocated_slots[slot].slot_id < 0) + { + allocator->allocated_slots[slot].slot_id = slot; + allocator->allocated_slots[slot].refcount = 1; + allocator->n_used_slots += 1; + break; + } + ++slot; + } + + _dbus_assert (slot < allocator->n_allocated_slots); + } + else + { + DBusAllocatedSlot *tmp; + + slot = -1; + tmp = dbus_realloc (allocator->allocated_slots, + sizeof (DBusAllocatedSlot) * (allocator->n_allocated_slots + 1)); + if (tmp == NULL) + goto out; + + allocator->allocated_slots = tmp; + slot = allocator->n_allocated_slots; + allocator->n_allocated_slots += 1; + allocator->n_used_slots += 1; + allocator->allocated_slots[slot].slot_id = slot; + allocator->allocated_slots[slot].refcount = 1; + } + + _dbus_assert (slot >= 0); + _dbus_assert (slot < allocator->n_allocated_slots); + _dbus_assert (*slot_id_p < 0); + _dbus_assert (allocator->allocated_slots[slot].slot_id == slot); + _dbus_assert (allocator->allocated_slots[slot].refcount == 1); + + *slot_id_p = slot; + + _dbus_verbose ("Allocated slot %d on allocator %p total %d slots allocated %d used\n", + slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots); + + out: + _dbus_mutex_unlock (*(allocator->lock_loc)); + return slot >= 0; +} + +/** + * Deallocates an ID previously allocated with + * _dbus_data_slot_allocator_alloc(). Existing data stored on + * existing #DBusDataSlotList objects with this ID will be freed when the + * data list is finalized, but may not be retrieved (and may only be + * replaced if someone else reallocates the slot). + * The slot value is reset to -1 if this is the last unref. + * + * @param allocator the allocator + * @param slot_id_p address where we store the slot + */ +void +_dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator, + dbus_int32_t *slot_id_p) +{ + _dbus_mutex_lock (*(allocator->lock_loc)); + + _dbus_assert (*slot_id_p < allocator->n_allocated_slots); + _dbus_assert (allocator->allocated_slots[*slot_id_p].slot_id == *slot_id_p); + _dbus_assert (allocator->allocated_slots[*slot_id_p].refcount > 0); + + allocator->allocated_slots[*slot_id_p].refcount -= 1; + + if (allocator->allocated_slots[*slot_id_p].refcount > 0) + { + _dbus_mutex_unlock (*(allocator->lock_loc)); + return; + } + + /* refcount is 0, free the slot */ + _dbus_verbose ("Freeing slot %d on allocator %p total %d allocated %d used\n", + *slot_id_p, allocator, allocator->n_allocated_slots, allocator->n_used_slots); + + allocator->allocated_slots[*slot_id_p].slot_id = -1; + *slot_id_p = -1; + + allocator->n_used_slots -= 1; + + if (allocator->n_used_slots == 0) + { + DBusMutex **mutex_loc = allocator->lock_loc; + + dbus_free (allocator->allocated_slots); + allocator->allocated_slots = NULL; + allocator->n_allocated_slots = 0; + allocator->lock_loc = NULL; + + _dbus_mutex_unlock (*mutex_loc); + } + else + { + _dbus_mutex_unlock (*(allocator->lock_loc)); + } +} + +/** + * Initializes a slot list. + * @param list the list to initialize. + */ +void +_dbus_data_slot_list_init (DBusDataSlotList *list) +{ + list->slots = NULL; + list->n_slots = 0; +} + +/** + * Stores a pointer in the data slot list, along with an optional + * function to be used for freeing the data when the data is set + * again, or when the slot list is finalized. The slot number must + * have been allocated with _dbus_data_slot_allocator_alloc() for the + * same allocator passed in here. The same allocator has to be used + * with the slot list every time. + * + * @param allocator the allocator to use + * @param list the data slot list + * @param slot the slot number + * @param data the data to store + * @param free_data_func finalizer function for the data + * @param old_free_func free function for any previously-existing data + * @param old_data previously-existing data, should be freed with old_free_func + * @returns #TRUE if there was enough memory to store the data + */ +dbus_bool_t +_dbus_data_slot_list_set (DBusDataSlotAllocator *allocator, + DBusDataSlotList *list, + int slot, + void *data, + DBusFreeFunction free_data_func, + DBusFreeFunction *old_free_func, + void **old_data) +{ +#ifndef DBUS_DISABLE_ASSERT + /* We need to take the allocator lock here, because the allocator could + * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts + * are disabled, since then the asserts are empty. + */ + _dbus_mutex_lock (*(allocator->lock_loc)); + _dbus_assert (slot < allocator->n_allocated_slots); + _dbus_assert (allocator->allocated_slots[slot].slot_id == slot); + _dbus_mutex_unlock (*(allocator->lock_loc)); +#endif + + if (slot >= list->n_slots) + { + DBusDataSlot *tmp; + int i; + + tmp = dbus_realloc (list->slots, + sizeof (DBusDataSlot) * (slot + 1)); + if (tmp == NULL) + return FALSE; + + list->slots = tmp; + i = list->n_slots; + list->n_slots = slot + 1; + while (i < list->n_slots) + { + list->slots[i].data = NULL; + list->slots[i].free_data_func = NULL; + ++i; + } + } + + _dbus_assert (slot < list->n_slots); + + *old_data = list->slots[slot].data; + *old_free_func = list->slots[slot].free_data_func; + + list->slots[slot].data = data; + list->slots[slot].free_data_func = free_data_func; + + return TRUE; +} + +/** + * Retrieves data previously set with _dbus_data_slot_list_set_data(). + * The slot must still be allocated (must not have been freed). + * + * @param allocator the allocator slot was allocated from + * @param list the data slot list + * @param slot the slot to get data from + * @returns the data, or #NULL if not found + */ +void* +_dbus_data_slot_list_get (DBusDataSlotAllocator *allocator, + DBusDataSlotList *list, + int slot) +{ +#ifndef DBUS_DISABLE_ASSERT + /* We need to take the allocator lock here, because the allocator could + * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts + * are disabled, since then the asserts are empty. + */ + _dbus_mutex_lock (*(allocator->lock_loc)); + _dbus_assert (slot >= 0); + _dbus_assert (slot < allocator->n_allocated_slots); + _dbus_assert (allocator->allocated_slots[slot].slot_id == slot); + _dbus_mutex_unlock (*(allocator->lock_loc)); +#endif + + if (slot >= list->n_slots) + return NULL; + else + return list->slots[slot].data; +} + +/** + * Frees all data slots contained in the list, calling + * application-provided free functions if they exist. + * + * @param list the list to clear + */ +void +_dbus_data_slot_list_clear (DBusDataSlotList *list) +{ + int i; + + i = 0; + while (i < list->n_slots) + { + if (list->slots[i].free_data_func) + (* list->slots[i].free_data_func) (list->slots[i].data); + list->slots[i].data = NULL; + list->slots[i].free_data_func = NULL; + ++i; + } +} + +/** + * Frees the data slot list and all data slots contained + * in it, calling application-provided free functions + * if they exist. + * + * @param list the list to free + */ +void +_dbus_data_slot_list_free (DBusDataSlotList *list) +{ + _dbus_data_slot_list_clear (list); + + dbus_free (list->slots); + list->slots = NULL; + list->n_slots = 0; +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +static int free_counter; + +static void +test_free_slot_data_func (void *data) +{ + int i = _DBUS_POINTER_TO_INT (data); + + _dbus_assert (free_counter == i); + ++free_counter; +} + +/** + * Test function for data slots + */ +dbus_bool_t +_dbus_data_slot_test (void) +{ + DBusDataSlotAllocator allocator; + DBusDataSlotList list; + int i; + DBusFreeFunction old_free_func; + void *old_data; + DBusMutex *mutex; + + if (!_dbus_data_slot_allocator_init (&allocator)) + _dbus_assert_not_reached ("no memory for allocator"); + + _dbus_data_slot_list_init (&list); + + _dbus_mutex_new_at_location (&mutex); + if (mutex == NULL) + _dbus_assert_not_reached ("failed to alloc mutex"); + +#define N_SLOTS 100 + + i = 0; + while (i < N_SLOTS) + { + /* we don't really want apps to rely on this ordered + * allocation, but it simplifies things to rely on it + * here. + */ + dbus_int32_t tmp = -1; + + _dbus_data_slot_allocator_alloc (&allocator, &mutex, &tmp); + + if (tmp != i) + _dbus_assert_not_reached ("did not allocate slots in numeric order\n"); + + ++i; + } + + i = 0; + while (i < N_SLOTS) + { + if (!_dbus_data_slot_list_set (&allocator, &list, + i, + _DBUS_INT_TO_POINTER (i), + test_free_slot_data_func, + &old_free_func, &old_data)) + _dbus_assert_not_reached ("no memory to set data"); + + _dbus_assert (old_free_func == NULL); + _dbus_assert (old_data == NULL); + + _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) == + _DBUS_INT_TO_POINTER (i)); + + ++i; + } + + free_counter = 0; + i = 0; + while (i < N_SLOTS) + { + if (!_dbus_data_slot_list_set (&allocator, &list, + i, + _DBUS_INT_TO_POINTER (i), + test_free_slot_data_func, + &old_free_func, &old_data)) + _dbus_assert_not_reached ("no memory to set data"); + + _dbus_assert (old_free_func == test_free_slot_data_func); + _dbus_assert (_DBUS_POINTER_TO_INT (old_data) == i); + + (* old_free_func) (old_data); + _dbus_assert (i == (free_counter - 1)); + + _dbus_assert (_dbus_data_slot_list_get (&allocator, &list, i) == + _DBUS_INT_TO_POINTER (i)); + + ++i; + } + + free_counter = 0; + _dbus_data_slot_list_free (&list); + + _dbus_assert (N_SLOTS == free_counter); + + i = 0; + while (i < N_SLOTS) + { + dbus_int32_t tmp = i; + + _dbus_data_slot_allocator_free (&allocator, &tmp); + _dbus_assert (tmp == -1); + ++i; + } + + _dbus_mutex_free_at_location (&mutex); + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-dataslot.h b/dbus/dbus-dataslot.h new file mode 100644 index 00000000..2e706f72 --- /dev/null +++ b/dbus/dbus-dataslot.h @@ -0,0 +1,96 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-dataslot.h storing data on objects + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_DATASLOT_H +#define DBUS_DATASLOT_H + +#include + +DBUS_BEGIN_DECLS + +typedef struct DBusDataSlotAllocator DBusDataSlotAllocator; +typedef struct DBusDataSlotList DBusDataSlotList; + +/** Opaque typedef for DBusDataSlot */ +typedef struct DBusDataSlot DBusDataSlot; +/** DBusDataSlot is used to store application data on the connection */ +struct DBusDataSlot +{ + void *data; /**< The application data */ + DBusFreeFunction free_data_func; /**< Free the application data */ +}; + +typedef struct DBusAllocatedSlot DBusAllocatedSlot; + +/** An allocated slot for storing data + */ +struct DBusAllocatedSlot +{ + dbus_int32_t slot_id; /**< ID of this slot */ + int refcount; /**< Number of uses of the slot */ +}; + +/** + * An allocator that tracks a set of slot IDs. + */ +struct DBusDataSlotAllocator +{ + DBusAllocatedSlot *allocated_slots; /**< Allocated slots */ + int n_allocated_slots; /**< number of slots malloc'd */ + int n_used_slots; /**< number of slots used */ + DBusMutex **lock_loc; /**< location of thread lock */ +}; + +/** + * Data structure that stores the actual user data set at a given + * slot. + */ +struct DBusDataSlotList +{ + DBusDataSlot *slots; /**< Data slots */ + int n_slots; /**< Slots we have storage for in data_slots */ +}; + +dbus_bool_t _dbus_data_slot_allocator_init (DBusDataSlotAllocator *allocator); +dbus_bool_t _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator, + DBusMutex **mutex_loc, + int *slot_id_p); +void _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator, + int *slot_id_p); +void _dbus_data_slot_list_init (DBusDataSlotList *list); +dbus_bool_t _dbus_data_slot_list_set (DBusDataSlotAllocator *allocator, + DBusDataSlotList *list, + int slot, + void *data, + DBusFreeFunction free_data_func, + DBusFreeFunction *old_free_func, + void **old_data); +void* _dbus_data_slot_list_get (DBusDataSlotAllocator *allocator, + DBusDataSlotList *list, + int slot); +void _dbus_data_slot_list_clear (DBusDataSlotList *list); +void _dbus_data_slot_list_free (DBusDataSlotList *list); + + +DBUS_END_DECLS + +#endif /* DBUS_DATASLOT_H */ diff --git a/dbus/dbus-errors.c b/dbus/dbus-errors.c new file mode 100644 index 00000000..e8154ccc --- /dev/null +++ b/dbus/dbus-errors.c @@ -0,0 +1,418 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-errors.c Error reporting + * + * Copyright (C) 2002, 2004 Red Hat Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-errors.h" +#include "dbus-internals.h" +#include "dbus-string.h" +#include "dbus-protocol.h" +#include +#include + +/** + * @defgroup DBusErrorInternals Error reporting internals + * @ingroup DBusInternals + * @brief Error reporting internals + * @{ + */ + +/** + * @def DBUS_ERROR_INIT + * + * Expands to a suitable initializer for a DBusError on the stack. + * Declaring a DBusError with: + * + * @code + * DBusError error = DBUS_ERROR_INIT; + * + * do_things_with (&error); + * @endcode + * + * is a more concise form of: + * + * @code + * DBusError error; + * + * dbus_error_init (&error); + * do_things_with (&error); + * @endcode + */ + +/** + * Internals of DBusError + */ +typedef struct +{ + char *name; /**< error name */ + char *message; /**< error message */ + + unsigned int const_message : 1; /**< Message is not owned by DBusError */ + + unsigned int dummy2 : 1; /**< placeholder */ + unsigned int dummy3 : 1; /**< placeholder */ + unsigned int dummy4 : 1; /**< placeholder */ + unsigned int dummy5 : 1; /**< placeholder */ + + void *padding1; /**< placeholder */ + +} DBusRealError; + +/** + * Returns a longer message describing an error name. + * If the error name is unknown, returns the name + * itself. + * + * @param error the error to describe + * @returns a constant string describing the error. + */ +static const char* +message_from_error (const char *error) +{ + if (strcmp (error, DBUS_ERROR_FAILED) == 0) + return "Unknown error"; + else if (strcmp (error, DBUS_ERROR_NO_MEMORY) == 0) + return "Not enough memory available"; + else if (strcmp (error, DBUS_ERROR_IO_ERROR) == 0) + return "Error reading or writing data"; + else if (strcmp (error, DBUS_ERROR_BAD_ADDRESS) == 0) + return "Could not parse address"; + else if (strcmp (error, DBUS_ERROR_NOT_SUPPORTED) == 0) + return "Feature not supported"; + else if (strcmp (error, DBUS_ERROR_LIMITS_EXCEEDED) == 0) + return "Resource limits exceeded"; + else if (strcmp (error, DBUS_ERROR_ACCESS_DENIED) == 0) + return "Permission denied"; + else if (strcmp (error, DBUS_ERROR_AUTH_FAILED) == 0) + return "Could not authenticate to server"; + else if (strcmp (error, DBUS_ERROR_NO_SERVER) == 0) + return "No server available at address"; + else if (strcmp (error, DBUS_ERROR_TIMEOUT) == 0) + return "Connection timed out"; + else if (strcmp (error, DBUS_ERROR_NO_NETWORK) == 0) + return "Network unavailable"; + else if (strcmp (error, DBUS_ERROR_ADDRESS_IN_USE) == 0) + return "Address already in use"; + else if (strcmp (error, DBUS_ERROR_DISCONNECTED) == 0) + return "Disconnected."; + else if (strcmp (error, DBUS_ERROR_INVALID_ARGS) == 0) + return "Invalid arguments."; + else if (strcmp (error, DBUS_ERROR_NO_REPLY) == 0) + return "Did not get a reply message."; + else if (strcmp (error, DBUS_ERROR_FILE_NOT_FOUND) == 0) + return "File doesn't exist."; + else if (strcmp (error, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0) + return "Object path already in use"; + else + return error; +} + +/** @} */ /* End of internals */ + +/** + * @defgroup DBusErrors Error reporting + * @ingroup DBus + * @brief Error reporting + * + * Types and functions related to reporting errors. + * + * + * In essence D-Bus error reporting works as follows: + * + * @code + * DBusError error; + * dbus_error_init (&error); + * dbus_some_function (arg1, arg2, &error); + * if (dbus_error_is_set (&error)) + * { + * fprintf (stderr, "an error occurred: %s\n", error.message); + * dbus_error_free (&error); + * } + * @endcode + * + * By convention, all functions allow #NULL instead of a DBusError*, + * so callers who don't care about the error can ignore it. + * + * There are some rules. An error passed to a D-Bus function must + * always be unset; you can't pass in an error that's already set. If + * a function has a return code indicating whether an error occurred, + * and also a #DBusError parameter, then the error will always be set + * if and only if the return code indicates an error occurred. i.e. + * the return code and the error are never going to disagree. + * + * An error only needs to be freed if it's been set, not if + * it's merely been initialized. + * + * You can check the specific error that occurred using + * dbus_error_has_name(). + * + * Errors will not be set for programming errors, such as passing + * invalid arguments to the libdbus API. Instead, libdbus will print + * warnings, exit on a failed assertion, or even crash in those cases + * (in other words, incorrect use of the API results in undefined + * behavior, possibly accompanied by helpful debugging output if + * you're lucky). + * + * @{ + */ + +/** + * Initializes a DBusError structure. Does not allocate any memory; + * the error only needs to be freed if it is set at some point. + * + * @param error the DBusError. + */ +void +dbus_error_init (DBusError *error) +{ + DBusRealError *real; + + _dbus_return_if_fail (error != NULL); + + _dbus_assert (sizeof (DBusError) == sizeof (DBusRealError)); + + real = (DBusRealError *)error; + + real->name = NULL; + real->message = NULL; + + real->const_message = TRUE; +} + +/** + * Frees an error that's been set (or just initialized), + * then reinitializes the error as in dbus_error_init(). + * + * @param error memory where the error is stored. + */ +void +dbus_error_free (DBusError *error) +{ + DBusRealError *real; + + _dbus_return_if_fail (error != NULL); + + real = (DBusRealError *)error; + + if (!real->const_message) + { + dbus_free (real->name); + dbus_free (real->message); + } + + dbus_error_init (error); +} + +/** + * Assigns an error name and message to a DBusError. Does nothing if + * error is #NULL. The message may be #NULL, which means a default + * message will be deduced from the name. The default message will be + * totally useless, though, so using a #NULL message is not recommended. + * + * Because this function does not copy the error name or message, you + * must ensure the name and message are global data that won't be + * freed. You probably want dbus_set_error() instead, in most cases. + * + * @param error the error.or #NULL + * @param name the error name (not copied!!!) + * @param message the error message (not copied!!!) + */ +void +dbus_set_error_const (DBusError *error, + const char *name, + const char *message) +{ + DBusRealError *real; + + _dbus_return_if_error_is_set (error); + _dbus_return_if_fail (name != NULL); + + if (error == NULL) + return; + + _dbus_assert (error->name == NULL); + _dbus_assert (error->message == NULL); + + if (message == NULL) + message = message_from_error (name); + + real = (DBusRealError *)error; + + real->name = (char*) name; + real->message = (char *)message; + real->const_message = TRUE; +} + +/** + * Moves an error src into dest, freeing src and + * overwriting dest. Both src and dest must be initialized. + * src is reinitialized to an empty error. dest may not + * contain an existing error. If the destination is + * #NULL, just frees and reinits the source error. + * + * @param src the source error + * @param dest the destination error or #NULL + */ +void +dbus_move_error (DBusError *src, + DBusError *dest) +{ + _dbus_return_if_error_is_set (dest); + + if (dest) + { + dbus_error_free (dest); + *dest = *src; + dbus_error_init (src); + } + else + dbus_error_free (src); +} + +/** + * Checks whether the error is set and has the given + * name. + * @param error the error + * @param name the name + * @returns #TRUE if the given named error occurred + */ +dbus_bool_t +dbus_error_has_name (const DBusError *error, + const char *name) +{ + _dbus_return_val_if_fail (error != NULL, FALSE); + _dbus_return_val_if_fail (name != NULL, FALSE); + + _dbus_assert ((error->name != NULL && error->message != NULL) || + (error->name == NULL && error->message == NULL)); + + if (error->name != NULL) + { + DBusString str1, str2; + _dbus_string_init_const (&str1, error->name); + _dbus_string_init_const (&str2, name); + return _dbus_string_equal (&str1, &str2); + } + else + return FALSE; +} + +/** + * Checks whether an error occurred (the error is set). + * + * @param error the error object + * @returns #TRUE if an error occurred + */ +dbus_bool_t +dbus_error_is_set (const DBusError *error) +{ + _dbus_return_val_if_fail (error != NULL, FALSE); + _dbus_assert ((error->name != NULL && error->message != NULL) || + (error->name == NULL && error->message == NULL)); + return error->name != NULL; +} + +/** + * Assigns an error name and message to a DBusError. + * Does nothing if error is #NULL. + * + * The format may be #NULL, which means a (pretty much useless) + * default message will be deduced from the name. This is not a good + * idea, just go ahead and provide a useful error message. It won't + * hurt you. + * + * If no memory can be allocated for the error message, + * an out-of-memory error message will be set instead. + * + * @param error the error.or #NULL + * @param name the error name + * @param format printf-style format string. + */ +void +dbus_set_error (DBusError *error, + const char *name, + const char *format, + ...) +{ + DBusRealError *real; + DBusString str; + va_list args; + + if (error == NULL) + return; + + /* it's a bug to pile up errors */ + _dbus_return_if_error_is_set (error); + _dbus_return_if_fail (name != NULL); + + _dbus_assert (error->name == NULL); + _dbus_assert (error->message == NULL); + + if (!_dbus_string_init (&str)) + goto nomem; + + if (format == NULL) + { + if (!_dbus_string_append (&str, + message_from_error (name))) + { + _dbus_string_free (&str); + va_end (args); + goto nomem; + } + } + else + { + va_start (args, format); + if (!_dbus_string_append_printf_valist (&str, format, args)) + { + _dbus_string_free (&str); + va_end (args); + goto nomem; + } + va_end (args); + } + + real = (DBusRealError *)error; + + if (!_dbus_string_steal_data (&str, &real->message)) + { + _dbus_string_free (&str); + goto nomem; + } + _dbus_string_free (&str); + + real->name = _dbus_strdup (name); + if (real->name == NULL) + { + dbus_free (real->message); + real->message = NULL; + goto nomem; + } + real->const_message = FALSE; + + return; + + nomem: + _DBUS_SET_OOM (error); +} + +/** @} */ /* End public API */ diff --git a/dbus/dbus-errors.h b/dbus/dbus-errors.h new file mode 100644 index 00000000..0ddf2477 --- /dev/null +++ b/dbus/dbus-errors.h @@ -0,0 +1,82 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-errors.h Error reporting + * + * Copyright (C) 2002 Red Hat Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_ERROR_H +#define DBUS_ERROR_H + +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusErrors + * @{ + */ + +/** Mostly-opaque type representing an error that occurred */ +typedef struct DBusError DBusError; + +/** + * Object representing an exception. + */ +struct DBusError +{ + const char *name; /**< public error name field */ + const char *message; /**< public error message field */ + + unsigned int dummy1 : 1; /**< placeholder */ + unsigned int dummy2 : 1; /**< placeholder */ + unsigned int dummy3 : 1; /**< placeholder */ + unsigned int dummy4 : 1; /**< placeholder */ + unsigned int dummy5 : 1; /**< placeholder */ + + void *padding1; /**< placeholder */ +}; + +#define DBUS_ERROR_INIT { NULL, NULL, TRUE, 0, 0, 0, 0, NULL } + +void dbus_error_init (DBusError *error); +void dbus_error_free (DBusError *error); +void dbus_set_error (DBusError *error, + const char *name, + const char *message, + ...); +void dbus_set_error_const (DBusError *error, + const char *name, + const char *message); +void dbus_move_error (DBusError *src, + DBusError *dest); +dbus_bool_t dbus_error_has_name (const DBusError *error, + const char *name); +dbus_bool_t dbus_error_is_set (const DBusError *error); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_ERROR_H */ diff --git a/dbus/dbus-hash.c b/dbus/dbus-hash.c new file mode 100644 index 00000000..e9eba6e5 --- /dev/null +++ b/dbus/dbus-hash.c @@ -0,0 +1,2193 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-hash.c Generic hash table utility (internal to D-Bus implementation) + * + * Copyright (C) 2002 Red Hat, Inc. + * Copyright (c) 1991-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * Hash table implementation based on generic/tclHash.c from the Tcl + * source code. The original Tcl license applies to portions of the + * code from tclHash.c; the Tcl license follows this standad D-Bus + * license information. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +/* + * The following copyright applies to code from the Tcl distribution. + * + * Copyright (c) 1991-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * This software is copyrighted by the Regents of the University of + * California, Sun Microsystems, Inc., Scriptics Corporation, and + * other parties. The following terms apply to all files associated + * with the software unless explicitly disclaimed in individual files. + * + * The authors hereby grant permission to use, copy, modify, + * distribute, and license this software and its documentation for any + * purpose, provided that existing copyright notices are retained in + * all copies and that this notice is included verbatim in any + * distributions. No written agreement, license, or royalty fee is + * required for any of the authorized uses. Modifications to this + * software may be copyrighted by their authors and need not follow + * the licensing terms described here, provided that the new terms are + * clearly indicated on the first page of each file where they apply. + * + * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL + * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, + * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND + * NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, + * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE + * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * GOVERNMENT USE: If you are acquiring this software on behalf of the + * U.S. government, the Government shall have only "Restricted Rights" + * in the software and related documentation as defined in the Federal + * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you + * are acquiring the software on behalf of the Department of Defense, + * the software shall be classified as "Commercial Computer Software" + * and the Government shall have only "Restricted Rights" as defined + * in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the + * foregoing, the authors grant the U.S. Government and others acting + * in its behalf permission to use and distribute the software in + * accordance with the terms specified in this license. + */ + +#include "dbus-hash.h" +#include "dbus-internals.h" +#include "dbus-mempool.h" + +/** + * @defgroup DBusHashTable Hash table + * @ingroup DBusInternals + * @brief DBusHashTable data structure + * + * Types and functions related to DBusHashTable. + */ + +/** + * @defgroup DBusHashTableInternals Hash table implementation details + * @ingroup DBusInternals + * @brief DBusHashTable implementation details + * + * The guts of DBusHashTable. + * + * @{ + */ + +/** + * When there are this many entries per bucket, on average, rebuild + * the hash table to make it larger. + */ +#define REBUILD_MULTIPLIER 3 + +/** + * Takes a preliminary integer hash value and produces an index into a + * hash tables bucket list. The idea is to make it so that + * preliminary values that are arbitrarily similar will end up in + * different buckets. The hash function was taken from a + * random-number generator. (This is used to hash integers.) + * + * The down_shift drops off the high bits of the hash index, and + * decreases as we increase the number of hash buckets (to keep more + * range in the hash index). The mask also strips high bits and strips + * fewer high bits as the number of hash buckets increases. + * I don't understand two things: why is the initial downshift 28 + * to keep 4 bits when the initial mask is 011 to keep 2 bits, + * and why do we have both a mask and a downshift? + * + */ +#define RANDOM_INDEX(table, i) \ + (((((long) (i))*1103515245) >> (table)->down_shift) & (table)->mask) + +/** + * Initial number of buckets in hash table (hash table statically + * allocates its buckets for this size and below). + * The initial mask has to be synced to this. + */ +#define DBUS_SMALL_HASH_TABLE 4 + +/** + * Typedef for DBusHashEntry + */ +typedef struct DBusHashEntry DBusHashEntry; + +/** + * @brief Internal representation of a hash entry. + * + * A single entry (key-value pair) in the hash table. + * Internal to hash table implementation. + */ +struct DBusHashEntry +{ + DBusHashEntry *next; /**< Pointer to next entry in this + * hash bucket, or #NULL for end of + * chain. + */ + void *key; /**< Hash key */ + void *value; /**< Hash value */ +}; + +/** + * Function used to find and optionally create a hash entry. + */ +typedef DBusHashEntry* (* DBusFindEntryFunction) (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated); + +/** + * @brief Internals of DBusHashTable. + * + * Hash table internals. Hash tables are opaque objects, they must be + * used via accessor functions. + */ +struct DBusHashTable { + int refcount; /**< Reference count */ + + DBusHashEntry **buckets; /**< Pointer to bucket array. Each + * element points to first entry in + * bucket's hash chain, or #NULL. + */ + DBusHashEntry *static_buckets[DBUS_SMALL_HASH_TABLE]; + /**< Bucket array used for small tables + * (to avoid mallocs and frees). + */ + int n_buckets; /**< Total number of buckets allocated + * at **buckets. + */ + int n_entries; /**< Total number of entries present + * in table. + */ + int hi_rebuild_size; /**< Enlarge table when n_entries gets + * to be this large. + */ + int lo_rebuild_size; /**< Shrink table when n_entries gets + * below this. + */ + int down_shift; /**< Shift count used in hashing + * function. Designed to use high- + * order bits of randomized keys. + */ + int mask; /**< Mask value used in hashing + * function. + */ + DBusHashType key_type; /**< Type of keys used in this table */ + + + DBusFindEntryFunction find_function; /**< Function for finding entries */ + + DBusFreeFunction free_key_function; /**< Function to free keys */ + DBusFreeFunction free_value_function; /**< Function to free values */ + + DBusMemPool *entry_pool; /**< Memory pool for hash entries */ +}; + +/** + * @brief Internals of DBusHashIter. + */ +typedef struct +{ + DBusHashTable *table; /**< Pointer to table containing entry. */ + DBusHashEntry **bucket; /**< Pointer to bucket that points to + * first entry in this entry's chain: + * used for deleting the entry. + */ + DBusHashEntry *entry; /**< Current hash entry */ + DBusHashEntry *next_entry; /**< Next entry to be iterated onto in current bucket */ + int next_bucket; /**< index of next bucket */ + int n_entries_on_init; /**< used to detect table resize since initialization */ +} DBusRealHashIter; + +static DBusHashEntry* find_direct_function (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated); +static DBusHashEntry* find_string_function (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated); +#ifdef DBUS_BUILD_TESTS +static DBusHashEntry* find_two_strings_function (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated); +#endif +static unsigned int string_hash (const char *str); +#ifdef DBUS_BUILD_TESTS +static unsigned int two_strings_hash (const char *str); +#endif +static void rebuild_table (DBusHashTable *table); +static DBusHashEntry* alloc_entry (DBusHashTable *table); +static void remove_entry (DBusHashTable *table, + DBusHashEntry **bucket, + DBusHashEntry *entry); +static void free_entry (DBusHashTable *table, + DBusHashEntry *entry); +static void free_entry_data (DBusHashTable *table, + DBusHashEntry *entry); + + +/** @} */ + +/** + * @addtogroup DBusHashTable + * @{ + */ + +/** + * @typedef DBusHashIter + * + * Public opaque hash table iterator object. + */ + +/** + * @typedef DBusHashTable + * + * Public opaque hash table object. + */ + +/** + * @typedef DBusHashType + * + * Indicates the type of a key in the hash table. + */ + +/** + * Constructs a new hash table. Should be freed with + * _dbus_hash_table_unref(). If memory cannot be + * allocated for the hash table, returns #NULL. + * + * @param type the type of hash key to use. + * @param key_free_function function to free hash keys. + * @param value_free_function function to free hash values. + * @returns a new DBusHashTable or #NULL if no memory. + */ +DBusHashTable* +_dbus_hash_table_new (DBusHashType type, + DBusFreeFunction key_free_function, + DBusFreeFunction value_free_function) +{ + DBusHashTable *table; + DBusMemPool *entry_pool; + + table = dbus_new0 (DBusHashTable, 1); + if (table == NULL) + return NULL; + + entry_pool = _dbus_mem_pool_new (sizeof (DBusHashEntry), TRUE); + if (entry_pool == NULL) + { + dbus_free (table); + return NULL; + } + + table->refcount = 1; + table->entry_pool = entry_pool; + + _dbus_assert (DBUS_SMALL_HASH_TABLE == _DBUS_N_ELEMENTS (table->static_buckets)); + + table->buckets = table->static_buckets; + table->n_buckets = DBUS_SMALL_HASH_TABLE; + table->n_entries = 0; + table->hi_rebuild_size = DBUS_SMALL_HASH_TABLE * REBUILD_MULTIPLIER; + table->lo_rebuild_size = 0; + table->down_shift = 28; + table->mask = 3; + table->key_type = type; + + _dbus_assert (table->mask < table->n_buckets); + + switch (table->key_type) + { + case DBUS_HASH_INT: + case DBUS_HASH_POINTER: + case DBUS_HASH_ULONG: + table->find_function = find_direct_function; + break; + case DBUS_HASH_STRING: + table->find_function = find_string_function; + break; + case DBUS_HASH_TWO_STRINGS: +#ifdef DBUS_BUILD_TESTS + table->find_function = find_two_strings_function; +#endif + break; + default: + _dbus_assert_not_reached ("Unknown hash table type"); + break; + } + + table->free_key_function = key_free_function; + table->free_value_function = value_free_function; + + return table; +} + + +/** + * Increments the reference count for a hash table. + * + * @param table the hash table to add a reference to. + * @returns the hash table. + */ +DBusHashTable * +_dbus_hash_table_ref (DBusHashTable *table) +{ + table->refcount += 1; + + return table; +} + +/** + * Decrements the reference count for a hash table, + * freeing the hash table if the count reaches zero. + * + * @param table the hash table to remove a reference from. + */ +void +_dbus_hash_table_unref (DBusHashTable *table) +{ + table->refcount -= 1; + + if (table->refcount == 0) + { +#if 0 + DBusHashEntry *entry; + DBusHashEntry *next; + int i; + + /* Free the entries in the table. */ + for (i = 0; i < table->n_buckets; i++) + { + entry = table->buckets[i]; + while (entry != NULL) + { + next = entry->next; + + free_entry (table, entry); + + entry = next; + } + } +#else + DBusHashEntry *entry; + int i; + + /* Free the entries in the table. */ + for (i = 0; i < table->n_buckets; i++) + { + entry = table->buckets[i]; + while (entry != NULL) + { + free_entry_data (table, entry); + + entry = entry->next; + } + } + /* We can do this very quickly with memory pools ;-) */ + _dbus_mem_pool_free (table->entry_pool); +#endif + + /* Free the bucket array, if it was dynamically allocated. */ + if (table->buckets != table->static_buckets) + dbus_free (table->buckets); + + dbus_free (table); + } +} + +/** + * Removed all entries from a hash table. + * + * @param table the hash table to remove all entries from. + */ +void +_dbus_hash_table_remove_all (DBusHashTable *table) +{ + DBusHashIter iter; + _dbus_hash_iter_init (table, &iter); + while (_dbus_hash_iter_next (&iter)) + { + _dbus_hash_iter_remove_entry(&iter); + } +} + +static DBusHashEntry* +alloc_entry (DBusHashTable *table) +{ + DBusHashEntry *entry; + + entry = _dbus_mem_pool_alloc (table->entry_pool); + + return entry; +} + +static void +free_entry_data (DBusHashTable *table, + DBusHashEntry *entry) +{ + if (table->free_key_function) + (* table->free_key_function) (entry->key); + if (table->free_value_function) + (* table->free_value_function) (entry->value); +} + +static void +free_entry (DBusHashTable *table, + DBusHashEntry *entry) +{ + free_entry_data (table, entry); + _dbus_mem_pool_dealloc (table->entry_pool, entry); +} + +static void +remove_entry (DBusHashTable *table, + DBusHashEntry **bucket, + DBusHashEntry *entry) +{ + _dbus_assert (table != NULL); + _dbus_assert (bucket != NULL); + _dbus_assert (*bucket != NULL); + _dbus_assert (entry != NULL); + + if (*bucket == entry) + *bucket = entry->next; + else + { + DBusHashEntry *prev; + prev = *bucket; + + while (prev->next != entry) + prev = prev->next; + + _dbus_assert (prev != NULL); + + prev->next = entry->next; + } + + table->n_entries -= 1; + free_entry (table, entry); +} + +/** + * Initializes a hash table iterator. To iterate over all entries in a + * hash table, use the following code (the printf assumes a hash + * from strings to strings obviously): + * + * @code + * DBusHashIter iter; + * + * _dbus_hash_iter_init (table, &iter); + * while (_dbus_hash_iter_next (&iter)) + * { + * printf ("The first key is %s and value is %s\n", + * _dbus_hash_iter_get_string_key (&iter), + * _dbus_hash_iter_get_value (&iter)); + * } + * + * + * @endcode + * + * The iterator is initialized pointing "one before" the first hash + * entry. The first call to _dbus_hash_iter_next() moves it onto + * the first valid entry or returns #FALSE if the hash table is + * empty. Subsequent calls move to the next valid entry or return + * #FALSE if there are no more entries. + * + * Note that it is guaranteed to be safe to remove a hash entry during + * iteration, but it is not safe to add a hash entry. + * + * @param table the hash table to iterate over. + * @param iter the iterator to initialize. + */ +void +_dbus_hash_iter_init (DBusHashTable *table, + DBusHashIter *iter) +{ + DBusRealHashIter *real; + + _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter)); + + real = (DBusRealHashIter*) iter; + + real->table = table; + real->bucket = NULL; + real->entry = NULL; + real->next_entry = NULL; + real->next_bucket = 0; + real->n_entries_on_init = table->n_entries; +} + +/** + * Move the hash iterator forward one step, to the next hash entry. + * The documentation for _dbus_hash_iter_init() explains in more + * detail. + * + * @param iter the iterator to move forward. + * @returns #FALSE if there are no more entries to move to. + */ +dbus_bool_t +_dbus_hash_iter_next (DBusHashIter *iter) +{ + DBusRealHashIter *real; + + _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter)); + + real = (DBusRealHashIter*) iter; + + /* if this assertion failed someone probably added hash entries + * during iteration, which is bad. + */ + _dbus_assert (real->n_entries_on_init >= real->table->n_entries); + + /* Remember that real->entry may have been deleted */ + + while (real->next_entry == NULL) + { + if (real->next_bucket >= real->table->n_buckets) + { + /* invalidate iter and return false */ + real->entry = NULL; + real->table = NULL; + real->bucket = NULL; + return FALSE; + } + + real->bucket = &(real->table->buckets[real->next_bucket]); + real->next_entry = *(real->bucket); + real->next_bucket += 1; + } + + _dbus_assert (real->next_entry != NULL); + _dbus_assert (real->bucket != NULL); + + real->entry = real->next_entry; + real->next_entry = real->entry->next; + + return TRUE; +} + +/** + * Removes the current entry from the hash table. + * If a key_free_function or value_free_function + * was provided to _dbus_hash_table_new(), + * frees the key and/or value for this entry. + * + * @param iter the hash table iterator. + */ +void +_dbus_hash_iter_remove_entry (DBusHashIter *iter) +{ + DBusRealHashIter *real; + + real = (DBusRealHashIter*) iter; + + _dbus_assert (real->table != NULL); + _dbus_assert (real->entry != NULL); + _dbus_assert (real->bucket != NULL); + + remove_entry (real->table, real->bucket, real->entry); + + real->entry = NULL; /* make it crash if you try to use this entry */ +} + +/** + * Gets the value of the current entry. + * + * @param iter the hash table iterator. + */ +void* +_dbus_hash_iter_get_value (DBusHashIter *iter) +{ + DBusRealHashIter *real; + + real = (DBusRealHashIter*) iter; + + _dbus_assert (real->table != NULL); + _dbus_assert (real->entry != NULL); + + return real->entry->value; +} + +/** + * Sets the value of the current entry. + * If the hash table has a value_free_function + * it will be used to free the previous value. + * The hash table will own the passed-in value + * (it will not be copied). + * + * @param iter the hash table iterator. + * @param value the new value. + */ +void +_dbus_hash_iter_set_value (DBusHashIter *iter, + void *value) +{ + DBusRealHashIter *real; + + real = (DBusRealHashIter*) iter; + + _dbus_assert (real->table != NULL); + _dbus_assert (real->entry != NULL); + + if (real->table->free_value_function && value != real->entry->value) + (* real->table->free_value_function) (real->entry->value); + + real->entry->value = value; +} + +/** + * Gets the key for the current entry. + * Only works for hash tables of type #DBUS_HASH_INT. + * + * @param iter the hash table iterator. + */ +int +_dbus_hash_iter_get_int_key (DBusHashIter *iter) +{ + DBusRealHashIter *real; + + real = (DBusRealHashIter*) iter; + + _dbus_assert (real->table != NULL); + _dbus_assert (real->entry != NULL); + + return _DBUS_POINTER_TO_INT (real->entry->key); +} + +/** + * Gets the key for the current entry. + * Only works for hash tables of type #DBUS_HASH_ULONG. + * + * @param iter the hash table iterator. + */ +unsigned long +_dbus_hash_iter_get_ulong_key (DBusHashIter *iter) +{ + DBusRealHashIter *real; + + real = (DBusRealHashIter*) iter; + + _dbus_assert (real->table != NULL); + _dbus_assert (real->entry != NULL); + + return (unsigned long) real->entry->key; +} + +/** + * Gets the key for the current entry. + * Only works for hash tables of type #DBUS_HASH_STRING + * @param iter the hash table iterator. + */ +const char* +_dbus_hash_iter_get_string_key (DBusHashIter *iter) +{ + DBusRealHashIter *real; + + real = (DBusRealHashIter*) iter; + + _dbus_assert (real->table != NULL); + _dbus_assert (real->entry != NULL); + + return real->entry->key; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Gets the key for the current entry. + * Only works for hash tables of type #DBUS_HASH_TWO_STRINGS + * @param iter the hash table iterator. + */ +const char* +_dbus_hash_iter_get_two_strings_key (DBusHashIter *iter) +{ + DBusRealHashIter *real; + + real = (DBusRealHashIter*) iter; + + _dbus_assert (real->table != NULL); + _dbus_assert (real->entry != NULL); + + return real->entry->key; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * A low-level but efficient interface for manipulating the hash + * table. It's efficient because you can get, set, and optionally + * create the hash entry while only running the hash function one + * time. + * + * Note that while calling _dbus_hash_iter_next() on the iterator + * filled in by this function may work, it's completely + * undefined which entries are after this iter and which + * are before it. So it would be silly to iterate using this + * iterator. + * + * If the hash entry is created, its value will be initialized + * to all bits zero. + * + * #FALSE may be returned due to memory allocation failure, or + * because create_if_not_found was #FALSE and the entry + * did not exist. + * + * If create_if_not_found is #TRUE and the entry is created, the hash + * table takes ownership of the key that's passed in. + * + * For a hash table of type #DBUS_HASH_INT, cast the int + * key to the key parameter using #_DBUS_INT_TO_POINTER(). + * + * @param table the hash table. + * @param key the hash key. + * @param create_if_not_found if #TRUE, create the entry if it didn't exist. + * @param iter the iterator to initialize. + * @returns #TRUE if the hash entry now exists (and the iterator is thus valid). + */ +dbus_bool_t +_dbus_hash_iter_lookup (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashIter *iter) +{ + DBusRealHashIter *real; + DBusHashEntry *entry; + DBusHashEntry **bucket; + + _dbus_assert (sizeof (DBusHashIter) == sizeof (DBusRealHashIter)); + + real = (DBusRealHashIter*) iter; + + entry = (* table->find_function) (table, key, create_if_not_found, &bucket, NULL); + + if (entry == NULL) + return FALSE; + + real->table = table; + real->bucket = bucket; + real->entry = entry; + real->next_entry = entry->next; + real->next_bucket = (bucket - table->buckets) + 1; + real->n_entries_on_init = table->n_entries; + + _dbus_assert (&(table->buckets[real->next_bucket-1]) == real->bucket); + + return TRUE; +} + +static void +add_allocated_entry (DBusHashTable *table, + DBusHashEntry *entry, + unsigned int idx, + void *key, + DBusHashEntry ***bucket) +{ + DBusHashEntry **b; + + entry->key = key; + + b = &(table->buckets[idx]); + entry->next = *b; + *b = entry; + + if (bucket) + *bucket = b; + + table->n_entries += 1; + + /* note we ONLY rebuild when ADDING - because you can iterate over a + * table and remove entries safely. + */ + if (table->n_entries >= table->hi_rebuild_size || + table->n_entries < table->lo_rebuild_size) + rebuild_table (table); +} + +static DBusHashEntry* +add_entry (DBusHashTable *table, + unsigned int idx, + void *key, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated) +{ + DBusHashEntry *entry; + + if (preallocated == NULL) + { + entry = alloc_entry (table); + if (entry == NULL) + { + if (bucket) + *bucket = NULL; + return NULL; + } + } + else + { + entry = (DBusHashEntry*) preallocated; + } + + add_allocated_entry (table, entry, idx, key, bucket); + + return entry; +} + +/* This is g_str_hash from GLib which was + * extensively discussed/tested/profiled + */ +static unsigned int +string_hash (const char *str) +{ + const char *p = str; + unsigned int h = *p; + + if (h) + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; + + return h; +} + +#ifdef DBUS_BUILD_TESTS +/* This hashes a memory block with two nul-terminated strings + * in it, used in dbus-object-registry.c at the moment. + */ +static unsigned int +two_strings_hash (const char *str) +{ + const char *p = str; + unsigned int h = *p; + + if (h) + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; + + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; + + return h; +} +#endif /* DBUS_BUILD_TESTS */ + +/** Key comparison function */ +typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b); + +static DBusHashEntry* +find_generic_function (DBusHashTable *table, + void *key, + unsigned int idx, + KeyCompareFunc compare_func, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated) +{ + DBusHashEntry *entry; + + if (bucket) + *bucket = NULL; + + /* Search all of the entries in this bucket. */ + entry = table->buckets[idx]; + while (entry != NULL) + { + if ((compare_func == NULL && key == entry->key) || + (compare_func != NULL && (* compare_func) (key, entry->key) == 0)) + { + if (bucket) + *bucket = &(table->buckets[idx]); + + if (preallocated) + _dbus_hash_table_free_preallocated_entry (table, preallocated); + + return entry; + } + + entry = entry->next; + } + + if (create_if_not_found) + entry = add_entry (table, idx, key, bucket, preallocated); + else if (preallocated) + _dbus_hash_table_free_preallocated_entry (table, preallocated); + + return entry; +} + +static DBusHashEntry* +find_string_function (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated) +{ + unsigned int idx; + + idx = string_hash (key) & table->mask; + + return find_generic_function (table, key, idx, + (KeyCompareFunc) strcmp, create_if_not_found, bucket, + preallocated); +} + +#ifdef DBUS_BUILD_TESTS +static int +two_strings_cmp (const char *a, + const char *b) +{ + size_t len_a; + size_t len_b; + int res; + + res = strcmp (a, b); + if (res != 0) + return res; + + len_a = strlen (a); + len_b = strlen (b); + + return strcmp (a + len_a + 1, b + len_b + 1); +} +#endif + +#ifdef DBUS_BUILD_TESTS +static DBusHashEntry* +find_two_strings_function (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated) +{ + unsigned int idx; + + idx = two_strings_hash (key) & table->mask; + + return find_generic_function (table, key, idx, + (KeyCompareFunc) two_strings_cmp, create_if_not_found, bucket, + preallocated); +} +#endif /* DBUS_BUILD_TESTS */ + +static DBusHashEntry* +find_direct_function (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashEntry ***bucket, + DBusPreallocatedHash *preallocated) +{ + unsigned int idx; + + idx = RANDOM_INDEX (table, key) & table->mask; + + + return find_generic_function (table, key, idx, + NULL, create_if_not_found, bucket, + preallocated); +} + +static void +rebuild_table (DBusHashTable *table) +{ + int old_size; + int new_buckets; + DBusHashEntry **old_buckets; + DBusHashEntry **old_chain; + DBusHashEntry *entry; + dbus_bool_t growing; + + /* + * Allocate and initialize the new bucket array, and set up + * hashing constants for new array size. + */ + + growing = table->n_entries >= table->hi_rebuild_size; + + old_size = table->n_buckets; + old_buckets = table->buckets; + + if (growing) + { + /* overflow paranoia */ + if (table->n_buckets < _DBUS_INT_MAX / 4 && + table->down_shift >= 0) + new_buckets = table->n_buckets * 4; + else + return; /* can't grow anymore */ + } + else + { + new_buckets = table->n_buckets / 4; + if (new_buckets < DBUS_SMALL_HASH_TABLE) + return; /* don't bother shrinking this far */ + } + + table->buckets = dbus_new0 (DBusHashEntry*, new_buckets); + if (table->buckets == NULL) + { + /* out of memory, yay - just don't reallocate, the table will + * still work, albeit more slowly. + */ + table->buckets = old_buckets; + return; + } + + table->n_buckets = new_buckets; + + if (growing) + { + table->lo_rebuild_size = table->hi_rebuild_size; + table->hi_rebuild_size *= 4; + + table->down_shift -= 2; /* keep 2 more high bits */ + table->mask = (table->mask << 2) + 3; /* keep 2 more high bits */ + } + else + { + table->hi_rebuild_size = table->lo_rebuild_size; + table->lo_rebuild_size /= 4; + + table->down_shift += 2; /* keep 2 fewer high bits */ + table->mask = table->mask >> 2; /* keep 2 fewer high bits */ + } + +#if 0 + printf ("%s table to lo = %d hi = %d downshift = %d mask = 0x%x\n", + growing ? "GROW" : "SHRINK", + table->lo_rebuild_size, + table->hi_rebuild_size, + table->down_shift, + table->mask); +#endif + + _dbus_assert (table->lo_rebuild_size >= 0); + _dbus_assert (table->hi_rebuild_size > table->lo_rebuild_size); + _dbus_assert (table->mask != 0); + /* the mask is essentially the max index */ + _dbus_assert (table->mask < table->n_buckets); + + /* + * Rehash all of the existing entries into the new bucket array. + */ + + for (old_chain = old_buckets; old_size > 0; old_size--, old_chain++) + { + for (entry = *old_chain; entry != NULL; entry = *old_chain) + { + unsigned int idx; + DBusHashEntry **bucket; + + *old_chain = entry->next; + switch (table->key_type) + { + case DBUS_HASH_STRING: + idx = string_hash (entry->key) & table->mask; + break; + case DBUS_HASH_TWO_STRINGS: +#ifdef DBUS_BUILD_TESTS + idx = two_strings_hash (entry->key) & table->mask; +#else + idx = 0; + _dbus_assert_not_reached ("two-strings is not enabled"); +#endif + break; + case DBUS_HASH_INT: + case DBUS_HASH_ULONG: + case DBUS_HASH_POINTER: + idx = RANDOM_INDEX (table, entry->key); + break; + default: + idx = 0; + _dbus_assert_not_reached ("Unknown hash table type"); + break; + } + + bucket = &(table->buckets[idx]); + entry->next = *bucket; + *bucket = entry; + } + } + + /* Free the old bucket array, if it was dynamically allocated. */ + + if (old_buckets != table->static_buckets) + dbus_free (old_buckets); +} + +/** + * Looks up the value for a given string in a hash table + * of type #DBUS_HASH_STRING. Returns %NULL if the value + * is not present. (A not-present entry is indistinguishable + * from an entry with a value of %NULL.) + * @param table the hash table. + * @param key the string to look up. + * @returns the value of the hash entry. + */ +void* +_dbus_hash_table_lookup_string (DBusHashTable *table, + const char *key) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_STRING); + + entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL); + + if (entry) + return entry->value; + else + return NULL; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Looks up the value for a given string in a hash table + * of type #DBUS_HASH_TWO_STRINGS. Returns %NULL if the value + * is not present. (A not-present entry is indistinguishable + * from an entry with a value of %NULL.) + * @param table the hash table. + * @param key the string to look up. + * @returns the value of the hash entry. + */ +void* +_dbus_hash_table_lookup_two_strings (DBusHashTable *table, + const char *key) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS); + + entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL); + + if (entry) + return entry->value; + else + return NULL; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Looks up the value for a given integer in a hash table + * of type #DBUS_HASH_INT. Returns %NULL if the value + * is not present. (A not-present entry is indistinguishable + * from an entry with a value of %NULL.) + * @param table the hash table. + * @param key the integer to look up. + * @returns the value of the hash entry. + */ +void* +_dbus_hash_table_lookup_int (DBusHashTable *table, + int key) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_INT); + + entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, NULL, NULL); + + if (entry) + return entry->value; + else + return NULL; +} + +#ifdef DBUS_BUILD_TESTS +/* disabled since it's only used for testing */ +/** + * Looks up the value for a given integer in a hash table + * of type #DBUS_HASH_POINTER. Returns %NULL if the value + * is not present. (A not-present entry is indistinguishable + * from an entry with a value of %NULL.) + * @param table the hash table. + * @param key the integer to look up. + * @returns the value of the hash entry. + */ +void* +_dbus_hash_table_lookup_pointer (DBusHashTable *table, + void *key) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_POINTER); + + entry = (* table->find_function) (table, key, FALSE, NULL, NULL); + + if (entry) + return entry->value; + else + return NULL; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Looks up the value for a given integer in a hash table + * of type #DBUS_HASH_ULONG. Returns %NULL if the value + * is not present. (A not-present entry is indistinguishable + * from an entry with a value of %NULL.) + * @param table the hash table. + * @param key the integer to look up. + * @returns the value of the hash entry. + */ +void* +_dbus_hash_table_lookup_ulong (DBusHashTable *table, + unsigned long key) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_ULONG); + + entry = (* table->find_function) (table, (void*) key, FALSE, NULL, NULL); + + if (entry) + return entry->value; + else + return NULL; +} + +/** + * Removes the hash entry for the given key. If no hash entry + * for the key exists, does nothing. + * + * @param table the hash table. + * @param key the hash key. + * @returns #TRUE if the entry existed + */ +dbus_bool_t +_dbus_hash_table_remove_string (DBusHashTable *table, + const char *key) +{ + DBusHashEntry *entry; + DBusHashEntry **bucket; + + _dbus_assert (table->key_type == DBUS_HASH_STRING); + + entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL); + + if (entry) + { + remove_entry (table, bucket, entry); + return TRUE; + } + else + return FALSE; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Removes the hash entry for the given key. If no hash entry + * for the key exists, does nothing. + * + * @param table the hash table. + * @param key the hash key. + * @returns #TRUE if the entry existed + */ +dbus_bool_t +_dbus_hash_table_remove_two_strings (DBusHashTable *table, + const char *key) +{ + DBusHashEntry *entry; + DBusHashEntry **bucket; + + _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS); + + entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL); + + if (entry) + { + remove_entry (table, bucket, entry); + return TRUE; + } + else + return FALSE; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Removes the hash entry for the given key. If no hash entry + * for the key exists, does nothing. + * + * @param table the hash table. + * @param key the hash key. + * @returns #TRUE if the entry existed + */ +dbus_bool_t +_dbus_hash_table_remove_int (DBusHashTable *table, + int key) +{ + DBusHashEntry *entry; + DBusHashEntry **bucket; + + _dbus_assert (table->key_type == DBUS_HASH_INT); + + entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), FALSE, &bucket, NULL); + + if (entry) + { + remove_entry (table, bucket, entry); + return TRUE; + } + else + return FALSE; +} + +#ifdef DBUS_BUILD_TESTS +/* disabled since it's only used for testing */ +/** + * Removes the hash entry for the given key. If no hash entry + * for the key exists, does nothing. + * + * @param table the hash table. + * @param key the hash key. + * @returns #TRUE if the entry existed + */ +dbus_bool_t +_dbus_hash_table_remove_pointer (DBusHashTable *table, + void *key) +{ + DBusHashEntry *entry; + DBusHashEntry **bucket; + + _dbus_assert (table->key_type == DBUS_HASH_POINTER); + + entry = (* table->find_function) (table, key, FALSE, &bucket, NULL); + + if (entry) + { + remove_entry (table, bucket, entry); + return TRUE; + } + else + return FALSE; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Removes the hash entry for the given key. If no hash entry + * for the key exists, does nothing. + * + * @param table the hash table. + * @param key the hash key. + * @returns #TRUE if the entry existed + */ +dbus_bool_t +_dbus_hash_table_remove_ulong (DBusHashTable *table, + unsigned long key) +{ + DBusHashEntry *entry; + DBusHashEntry **bucket; + + _dbus_assert (table->key_type == DBUS_HASH_ULONG); + + entry = (* table->find_function) (table, (void*) key, FALSE, &bucket, NULL); + + if (entry) + { + remove_entry (table, bucket, entry); + return TRUE; + } + else + return FALSE; +} + +/** + * Creates a hash entry with the given key and value. + * The key and value are not copied; they are stored + * in the hash table by reference. If an entry with the + * given key already exists, the previous key and value + * are overwritten (and freed if the hash table has + * a key_free_function and/or value_free_function). + * + * Returns #FALSE if memory for the new hash entry + * can't be allocated. + * + * @param table the hash table. + * @param key the hash entry key. + * @param value the hash entry value. + */ +dbus_bool_t +_dbus_hash_table_insert_string (DBusHashTable *table, + char *key, + void *value) +{ + DBusPreallocatedHash *preallocated; + + _dbus_assert (table->key_type == DBUS_HASH_STRING); + + preallocated = _dbus_hash_table_preallocate_entry (table); + if (preallocated == NULL) + return FALSE; + + _dbus_hash_table_insert_string_preallocated (table, preallocated, + key, value); + + return TRUE; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Creates a hash entry with the given key and value. + * The key and value are not copied; they are stored + * in the hash table by reference. If an entry with the + * given key already exists, the previous key and value + * are overwritten (and freed if the hash table has + * a key_free_function and/or value_free_function). + * + * Returns #FALSE if memory for the new hash entry + * can't be allocated. + * + * @param table the hash table. + * @param key the hash entry key. + * @param value the hash entry value. + */ +dbus_bool_t +_dbus_hash_table_insert_two_strings (DBusHashTable *table, + char *key, + void *value) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS); + + entry = (* table->find_function) (table, key, TRUE, NULL, NULL); + + if (entry == NULL) + return FALSE; /* no memory */ + + if (table->free_key_function && entry->key != key) + (* table->free_key_function) (entry->key); + + if (table->free_value_function && entry->value != value) + (* table->free_value_function) (entry->value); + + entry->key = key; + entry->value = value; + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Creates a hash entry with the given key and value. + * The key and value are not copied; they are stored + * in the hash table by reference. If an entry with the + * given key already exists, the previous key and value + * are overwritten (and freed if the hash table has + * a key_free_function and/or value_free_function). + * + * Returns #FALSE if memory for the new hash entry + * can't be allocated. + * + * @param table the hash table. + * @param key the hash entry key. + * @param value the hash entry value. + */ +dbus_bool_t +_dbus_hash_table_insert_int (DBusHashTable *table, + int key, + void *value) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_INT); + + entry = (* table->find_function) (table, _DBUS_INT_TO_POINTER (key), TRUE, NULL, NULL); + + if (entry == NULL) + return FALSE; /* no memory */ + + if (table->free_key_function && entry->key != _DBUS_INT_TO_POINTER (key)) + (* table->free_key_function) (entry->key); + + if (table->free_value_function && entry->value != value) + (* table->free_value_function) (entry->value); + + entry->key = _DBUS_INT_TO_POINTER (key); + entry->value = value; + + return TRUE; +} + +#ifdef DBUS_BUILD_TESTS +/* disabled since it's only used for testing */ +/** + * Creates a hash entry with the given key and value. + * The key and value are not copied; they are stored + * in the hash table by reference. If an entry with the + * given key already exists, the previous key and value + * are overwritten (and freed if the hash table has + * a key_free_function and/or value_free_function). + * + * Returns #FALSE if memory for the new hash entry + * can't be allocated. + * + * @param table the hash table. + * @param key the hash entry key. + * @param value the hash entry value. + */ +dbus_bool_t +_dbus_hash_table_insert_pointer (DBusHashTable *table, + void *key, + void *value) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_POINTER); + + entry = (* table->find_function) (table, key, TRUE, NULL, NULL); + + if (entry == NULL) + return FALSE; /* no memory */ + + if (table->free_key_function && entry->key != key) + (* table->free_key_function) (entry->key); + + if (table->free_value_function && entry->value != value) + (* table->free_value_function) (entry->value); + + entry->key = key; + entry->value = value; + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Creates a hash entry with the given key and value. + * The key and value are not copied; they are stored + * in the hash table by reference. If an entry with the + * given key already exists, the previous key and value + * are overwritten (and freed if the hash table has + * a key_free_function and/or value_free_function). + * + * Returns #FALSE if memory for the new hash entry + * can't be allocated. + * + * @param table the hash table. + * @param key the hash entry key. + * @param value the hash entry value. + */ +dbus_bool_t +_dbus_hash_table_insert_ulong (DBusHashTable *table, + unsigned long key, + void *value) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_ULONG); + + entry = (* table->find_function) (table, (void*) key, TRUE, NULL, NULL); + + if (entry == NULL) + return FALSE; /* no memory */ + + if (table->free_key_function && entry->key != (void*) key) + (* table->free_key_function) (entry->key); + + if (table->free_value_function && entry->value != value) + (* table->free_value_function) (entry->value); + + entry->key = (void*) key; + entry->value = value; + + return TRUE; +} + +/** + * Preallocate an opaque data blob that allows us to insert into the + * hash table at a later time without allocating any memory. + * + * @param table the hash table + * @returns the preallocated data, or #NULL if no memory + */ +DBusPreallocatedHash* +_dbus_hash_table_preallocate_entry (DBusHashTable *table) +{ + DBusHashEntry *entry; + + entry = alloc_entry (table); + + return (DBusPreallocatedHash*) entry; +} + +/** + * Frees an opaque DBusPreallocatedHash that was *not* used + * in order to insert into the hash table. + * + * @param table the hash table + * @param preallocated the preallocated data + */ +void +_dbus_hash_table_free_preallocated_entry (DBusHashTable *table, + DBusPreallocatedHash *preallocated) +{ + DBusHashEntry *entry; + + _dbus_assert (preallocated != NULL); + + entry = (DBusHashEntry*) preallocated; + + /* Don't use free_entry(), since this entry has no key/data */ + _dbus_mem_pool_dealloc (table->entry_pool, entry); +} + +/** + * Inserts a string-keyed entry into the hash table, using a + * preallocated data block from + * _dbus_hash_table_preallocate_entry(). This function cannot fail due + * to lack of memory. The DBusPreallocatedHash object is consumed and + * should not be reused or freed. Otherwise this function works + * just like _dbus_hash_table_insert_string(). + * + * @param table the hash table + * @param preallocated the preallocated data + * @param key the hash key + * @param value the value + */ +void +_dbus_hash_table_insert_string_preallocated (DBusHashTable *table, + DBusPreallocatedHash *preallocated, + char *key, + void *value) +{ + DBusHashEntry *entry; + + _dbus_assert (table->key_type == DBUS_HASH_STRING); + _dbus_assert (preallocated != NULL); + + entry = (* table->find_function) (table, key, TRUE, NULL, preallocated); + + _dbus_assert (entry != NULL); + + if (table->free_key_function && entry->key != key) + (* table->free_key_function) (entry->key); + + if (table->free_value_function && entry->value != value) + (* table->free_value_function) (entry->value); + + entry->key = key; + entry->value = value; +} + +/** + * Gets the number of hash entries in a hash table. + * + * @param table the hash table. + * @returns the number of entries in the table. + */ +int +_dbus_hash_table_get_n_entries (DBusHashTable *table) +{ + return table->n_entries; +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +/* If you're wondering why the hash table test takes + * forever to run, it's because we call this function + * in inner loops thus making things quadratic. + */ +static int +count_entries (DBusHashTable *table) +{ + DBusHashIter iter; + int count; + + count = 0; + _dbus_hash_iter_init (table, &iter); + while (_dbus_hash_iter_next (&iter)) + ++count; + + _dbus_assert (count == _dbus_hash_table_get_n_entries (table)); + + return count; +} + +/* Copy the foo\0bar\0 double string thing */ +static char* +_dbus_strdup2 (const char *str) +{ + size_t len; + char *copy; + + if (str == NULL) + return NULL; + + len = strlen (str); + len += strlen ((str + len + 1)); + + copy = dbus_malloc (len + 2); + if (copy == NULL) + return NULL; + + memcpy (copy, str, len + 2); + + return copy; +} + +/** + * @ingroup DBusHashTableInternals + * Unit test for DBusHashTable + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_hash_test (void) +{ + int i; + DBusHashTable *table1; + DBusHashTable *table2; + DBusHashTable *table3; + DBusHashTable *table4; + DBusHashIter iter; +#define N_HASH_KEYS 5000 + char **keys; + dbus_bool_t ret = FALSE; + + keys = dbus_new (char *, N_HASH_KEYS); + if (keys == NULL) + _dbus_assert_not_reached ("no memory"); + + for (i = 0; i < N_HASH_KEYS; i++) + { + keys[i] = dbus_malloc (128); + + if (keys[i] == NULL) + _dbus_assert_not_reached ("no memory"); + } + + printf ("Computing test hash keys...\n"); + i = 0; + while (i < N_HASH_KEYS) + { + int len; + + /* all the hash keys are TWO_STRINGS, but + * then we can also use those as regular strings. + */ + + len = sprintf (keys[i], "Hash key %d", i); + sprintf (keys[i] + len + 1, "Two string %d", i); + _dbus_assert (*(keys[i] + len) == '\0'); + _dbus_assert (*(keys[i] + len + 1) != '\0'); + ++i; + } + printf ("... done.\n"); + + table1 = _dbus_hash_table_new (DBUS_HASH_STRING, + dbus_free, dbus_free); + if (table1 == NULL) + goto out; + + table2 = _dbus_hash_table_new (DBUS_HASH_INT, + NULL, dbus_free); + if (table2 == NULL) + goto out; + + table3 = _dbus_hash_table_new (DBUS_HASH_ULONG, + NULL, dbus_free); + if (table3 == NULL) + goto out; + + table4 = _dbus_hash_table_new (DBUS_HASH_TWO_STRINGS, + dbus_free, dbus_free); + if (table4 == NULL) + goto out; + + + /* Insert and remove a bunch of stuff, counting the table in between + * to be sure it's not broken and that iteration works + */ + i = 0; + while (i < 3000) + { + void *value; + char *key; + + key = _dbus_strdup (keys[i]); + if (key == NULL) + goto out; + value = _dbus_strdup ("Value!"); + if (value == NULL) + goto out; + + if (!_dbus_hash_table_insert_string (table1, + key, value)) + goto out; + + value = _dbus_strdup (keys[i]); + if (value == NULL) + goto out; + + if (!_dbus_hash_table_insert_int (table2, + i, value)) + goto out; + + value = _dbus_strdup (keys[i]); + if (value == NULL) + goto out; + + if (!_dbus_hash_table_insert_ulong (table3, + i, value)) + goto out; + + key = _dbus_strdup2 (keys[i]); + if (key == NULL) + goto out; + value = _dbus_strdup ("Value!"); + if (value == NULL) + goto out; + + if (!_dbus_hash_table_insert_two_strings (table4, + key, value)) + goto out; + + _dbus_assert (count_entries (table1) == i + 1); + _dbus_assert (count_entries (table2) == i + 1); + _dbus_assert (count_entries (table3) == i + 1); + _dbus_assert (count_entries (table4) == i + 1); + + value = _dbus_hash_table_lookup_string (table1, keys[i]); + _dbus_assert (value != NULL); + _dbus_assert (strcmp (value, "Value!") == 0); + + value = _dbus_hash_table_lookup_int (table2, i); + _dbus_assert (value != NULL); + _dbus_assert (strcmp (value, keys[i]) == 0); + + value = _dbus_hash_table_lookup_ulong (table3, i); + _dbus_assert (value != NULL); + _dbus_assert (strcmp (value, keys[i]) == 0); + + value = _dbus_hash_table_lookup_two_strings (table4, keys[i]); + _dbus_assert (value != NULL); + _dbus_assert (strcmp (value, "Value!") == 0); + + ++i; + } + + --i; + while (i >= 0) + { + _dbus_hash_table_remove_string (table1, + keys[i]); + + _dbus_hash_table_remove_int (table2, i); + + _dbus_hash_table_remove_ulong (table3, i); + + _dbus_hash_table_remove_two_strings (table4, + keys[i]); + + _dbus_assert (count_entries (table1) == i); + _dbus_assert (count_entries (table2) == i); + _dbus_assert (count_entries (table3) == i); + _dbus_assert (count_entries (table4) == i); + + --i; + } + + _dbus_hash_table_ref (table1); + _dbus_hash_table_ref (table2); + _dbus_hash_table_ref (table3); + _dbus_hash_table_ref (table4); + _dbus_hash_table_unref (table1); + _dbus_hash_table_unref (table2); + _dbus_hash_table_unref (table3); + _dbus_hash_table_unref (table4); + _dbus_hash_table_unref (table1); + _dbus_hash_table_unref (table2); + _dbus_hash_table_unref (table3); + _dbus_hash_table_unref (table4); + table3 = NULL; + + /* Insert a bunch of stuff then check + * that iteration works correctly (finds the right + * values, iter_set_value works, etc.) + */ + table1 = _dbus_hash_table_new (DBUS_HASH_STRING, + dbus_free, dbus_free); + if (table1 == NULL) + goto out; + + table2 = _dbus_hash_table_new (DBUS_HASH_INT, + NULL, dbus_free); + if (table2 == NULL) + goto out; + + i = 0; + while (i < 5000) + { + char *key; + void *value; + + key = _dbus_strdup (keys[i]); + if (key == NULL) + goto out; + value = _dbus_strdup ("Value!"); + if (value == NULL) + goto out; + + if (!_dbus_hash_table_insert_string (table1, + key, value)) + goto out; + + value = _dbus_strdup (keys[i]); + if (value == NULL) + goto out; + + if (!_dbus_hash_table_insert_int (table2, + i, value)) + goto out; + + _dbus_assert (count_entries (table1) == i + 1); + _dbus_assert (count_entries (table2) == i + 1); + + ++i; + } + + _dbus_hash_iter_init (table1, &iter); + while (_dbus_hash_iter_next (&iter)) + { + const char *key; + void *value; + + key = _dbus_hash_iter_get_string_key (&iter); + value = _dbus_hash_iter_get_value (&iter); + + _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value); + + value = _dbus_strdup ("Different value!"); + if (value == NULL) + goto out; + + _dbus_hash_iter_set_value (&iter, value); + + _dbus_assert (_dbus_hash_table_lookup_string (table1, key) == value); + } + + _dbus_hash_iter_init (table1, &iter); + while (_dbus_hash_iter_next (&iter)) + { + _dbus_hash_iter_remove_entry (&iter); + _dbus_assert (count_entries (table1) == i - 1); + --i; + } + + _dbus_hash_iter_init (table2, &iter); + while (_dbus_hash_iter_next (&iter)) + { + int key; + void *value; + + key = _dbus_hash_iter_get_int_key (&iter); + value = _dbus_hash_iter_get_value (&iter); + + _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value); + + value = _dbus_strdup ("Different value!"); + if (value == NULL) + goto out; + + _dbus_hash_iter_set_value (&iter, value); + + _dbus_assert (_dbus_hash_table_lookup_int (table2, key) == value); + } + + i = count_entries (table2); + _dbus_hash_iter_init (table2, &iter); + while (_dbus_hash_iter_next (&iter)) + { + _dbus_hash_iter_remove_entry (&iter); + _dbus_assert (count_entries (table2) + 1 == i); + --i; + } + + /* add/remove interleaved, to check that we grow/shrink the table + * appropriately + */ + i = 0; + while (i < 1000) + { + char *key; + void *value; + + key = _dbus_strdup (keys[i]); + if (key == NULL) + goto out; + + value = _dbus_strdup ("Value!"); + if (value == NULL) + goto out; + + if (!_dbus_hash_table_insert_string (table1, + key, value)) + goto out; + + ++i; + } + + --i; + while (i >= 0) + { + char *key; + void *value; + + key = _dbus_strdup (keys[i]); + if (key == NULL) + goto out; + value = _dbus_strdup ("Value!"); + if (value == NULL) + goto out; + + if (!_dbus_hash_table_remove_string (table1, keys[i])) + goto out; + + if (!_dbus_hash_table_insert_string (table1, + key, value)) + goto out; + + if (!_dbus_hash_table_remove_string (table1, keys[i])) + goto out; + + _dbus_assert (_dbus_hash_table_get_n_entries (table1) == i); + + --i; + } + + /* nuke these tables */ + _dbus_hash_table_unref (table1); + _dbus_hash_table_unref (table2); + + + /* Now do a bunch of things again using _dbus_hash_iter_lookup() to + * be sure that interface works. + */ + table1 = _dbus_hash_table_new (DBUS_HASH_STRING, + dbus_free, dbus_free); + if (table1 == NULL) + goto out; + + table2 = _dbus_hash_table_new (DBUS_HASH_INT, + NULL, dbus_free); + if (table2 == NULL) + goto out; + + i = 0; + while (i < 3000) + { + void *value; + char *key; + + key = _dbus_strdup (keys[i]); + if (key == NULL) + goto out; + value = _dbus_strdup ("Value!"); + if (value == NULL) + goto out; + + if (!_dbus_hash_iter_lookup (table1, + key, TRUE, &iter)) + goto out; + _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL); + _dbus_hash_iter_set_value (&iter, value); + + value = _dbus_strdup (keys[i]); + if (value == NULL) + goto out; + + if (!_dbus_hash_iter_lookup (table2, + _DBUS_INT_TO_POINTER (i), TRUE, &iter)) + goto out; + _dbus_assert (_dbus_hash_iter_get_value (&iter) == NULL); + _dbus_hash_iter_set_value (&iter, value); + + _dbus_assert (count_entries (table1) == i + 1); + _dbus_assert (count_entries (table2) == i + 1); + + if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter)) + goto out; + + value = _dbus_hash_iter_get_value (&iter); + _dbus_assert (value != NULL); + _dbus_assert (strcmp (value, "Value!") == 0); + + /* Iterate just to be sure it works, though + * it's a stupid thing to do + */ + while (_dbus_hash_iter_next (&iter)) + ; + + if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter)) + goto out; + + value = _dbus_hash_iter_get_value (&iter); + _dbus_assert (value != NULL); + _dbus_assert (strcmp (value, keys[i]) == 0); + + /* Iterate just to be sure it works, though + * it's a stupid thing to do + */ + while (_dbus_hash_iter_next (&iter)) + ; + + ++i; + } + + --i; + while (i >= 0) + { + if (!_dbus_hash_iter_lookup (table1, keys[i], FALSE, &iter)) + _dbus_assert_not_reached ("hash entry should have existed"); + _dbus_hash_iter_remove_entry (&iter); + + if (!_dbus_hash_iter_lookup (table2, _DBUS_INT_TO_POINTER (i), FALSE, &iter)) + _dbus_assert_not_reached ("hash entry should have existed"); + _dbus_hash_iter_remove_entry (&iter); + + _dbus_assert (count_entries (table1) == i); + _dbus_assert (count_entries (table2) == i); + + --i; + } + + _dbus_hash_table_unref (table1); + _dbus_hash_table_unref (table2); + + ret = TRUE; + + out: + for (i = 0; i < N_HASH_KEYS; i++) + dbus_free (keys[i]); + + dbus_free (keys); + + return ret; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-hash.h b/dbus/dbus-hash.h new file mode 100644 index 00000000..78f69ddf --- /dev/null +++ b/dbus/dbus-hash.h @@ -0,0 +1,142 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-hash.h Generic hash table utility (internal to D-Bus implementation) + * + * Copyright (C) 2002 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_HASH_H +#define DBUS_HASH_H + +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusHashTable + * @{ + */ + +/** Hash iterator object. The iterator is on the stack, but its real + * fields are hidden privately. + */ +struct DBusHashIter +{ + void *dummy1; /**< Do not use. */ + void *dummy2; /**< Do not use. */ + void *dummy3; /**< Do not use. */ + void *dummy4; /**< Do not use. */ + int dummy5; /**< Do not use. */ + int dummy6; /**< Do not use. */ +}; + +typedef struct DBusHashTable DBusHashTable; +typedef struct DBusHashIter DBusHashIter; + +/* Allowing an arbitrary function as with GLib + * would be nicer for a public API, but for + * an internal API this saves typing, we can add + * more whenever we feel like it. + */ +typedef enum +{ + DBUS_HASH_STRING, /**< Hash keys are strings. */ + DBUS_HASH_TWO_STRINGS, /**< Hash key is two strings in one memory block, i.e. foo\\0bar\\0 */ + DBUS_HASH_INT, /**< Hash keys are integers. */ + DBUS_HASH_POINTER, /**< Hash keys are pointers. */ + DBUS_HASH_ULONG /**< Hash keys are unsigned long. */ +} DBusHashType; + +DBusHashTable* _dbus_hash_table_new (DBusHashType type, + DBusFreeFunction key_free_function, + DBusFreeFunction value_free_function); +DBusHashTable* _dbus_hash_table_ref (DBusHashTable *table); +void _dbus_hash_table_unref (DBusHashTable *table); +void _dbus_hash_table_remove_all (DBusHashTable *table); +void _dbus_hash_iter_init (DBusHashTable *table, + DBusHashIter *iter); +dbus_bool_t _dbus_hash_iter_next (DBusHashIter *iter); +void _dbus_hash_iter_remove_entry (DBusHashIter *iter); +void* _dbus_hash_iter_get_value (DBusHashIter *iter); +void _dbus_hash_iter_set_value (DBusHashIter *iter, + void *value); +int _dbus_hash_iter_get_int_key (DBusHashIter *iter); +const char* _dbus_hash_iter_get_string_key (DBusHashIter *iter); +const char* _dbus_hash_iter_get_two_strings_key (DBusHashIter *iter); +unsigned long _dbus_hash_iter_get_ulong_key (DBusHashIter *iter); +dbus_bool_t _dbus_hash_iter_lookup (DBusHashTable *table, + void *key, + dbus_bool_t create_if_not_found, + DBusHashIter *iter); +void* _dbus_hash_table_lookup_string (DBusHashTable *table, + const char *key); +void* _dbus_hash_table_lookup_two_strings (DBusHashTable *table, + const char *key); +void* _dbus_hash_table_lookup_int (DBusHashTable *table, + int key); +void* _dbus_hash_table_lookup_pointer (DBusHashTable *table, + void *key); +void* _dbus_hash_table_lookup_ulong (DBusHashTable *table, + unsigned long key); +dbus_bool_t _dbus_hash_table_remove_string (DBusHashTable *table, + const char *key); +dbus_bool_t _dbus_hash_table_remove_two_strings (DBusHashTable *table, + const char *key); +dbus_bool_t _dbus_hash_table_remove_int (DBusHashTable *table, + int key); +dbus_bool_t _dbus_hash_table_remove_pointer (DBusHashTable *table, + void *key); +dbus_bool_t _dbus_hash_table_remove_ulong (DBusHashTable *table, + unsigned long key); +dbus_bool_t _dbus_hash_table_insert_string (DBusHashTable *table, + char *key, + void *value); +dbus_bool_t _dbus_hash_table_insert_two_strings (DBusHashTable *table, + char *key, + void *value); +dbus_bool_t _dbus_hash_table_insert_int (DBusHashTable *table, + int key, + void *value); +dbus_bool_t _dbus_hash_table_insert_pointer (DBusHashTable *table, + void *key, + void *value); +dbus_bool_t _dbus_hash_table_insert_ulong (DBusHashTable *table, + unsigned long key, + void *value); +int _dbus_hash_table_get_n_entries (DBusHashTable *table); + +/* Preallocation */ + +/** A preallocated hash entry */ +typedef struct DBusPreallocatedHash DBusPreallocatedHash; + +DBusPreallocatedHash *_dbus_hash_table_preallocate_entry (DBusHashTable *table); +void _dbus_hash_table_free_preallocated_entry (DBusHashTable *table, + DBusPreallocatedHash *preallocated); +void _dbus_hash_table_insert_string_preallocated (DBusHashTable *table, + DBusPreallocatedHash *preallocated, + char *key, + void *value); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_HASH_H */ diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c new file mode 100644 index 00000000..c5885eae --- /dev/null +++ b/dbus/dbus-internals.c @@ -0,0 +1,951 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-internals.c random utility stuff (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-internals.h" +#include "dbus-protocol.h" +#include "dbus-marshal-basic.h" +#include "dbus-test.h" +#include +#include +#include +#include + +/** + * @defgroup DBusInternals D-Bus secret internal implementation details + * @brief Documentation useful when developing or debugging D-Bus itself. + * + */ + +/** + * @defgroup DBusInternalsUtils Utilities and portability + * @ingroup DBusInternals + * @brief Utility functions (_dbus_assert(), _dbus_warn(), etc.) + * @{ + */ + +/** + * @def _dbus_assert + * + * Aborts with an error message if the condition is false. + * + * @param condition condition which must be true. + */ + +/** + * @def _dbus_assert_not_reached + * + * Aborts with an error message if called. + * The given explanation will be printed. + * + * @param explanation explanation of what happened if the code was reached. + */ + +/** + * @def _DBUS_N_ELEMENTS + * + * Computes the number of elements in a fixed-size array using + * sizeof(). + * + * @param array the array to count elements in. + */ + +/** + * @def _DBUS_POINTER_TO_INT + * + * Safely casts a void* to an integer; should only be used on void* + * that actually contain integers, for example one created with + * _DBUS_INT_TO_POINTER. Only guaranteed to preserve 32 bits. + * (i.e. it's used to store 32-bit ints in pointers, but + * can't be used to store 64-bit pointers in ints.) + * + * @param pointer pointer to extract an integer from. + */ +/** + * @def _DBUS_INT_TO_POINTER + * + * Safely stuffs an integer into a pointer, to be extracted later with + * _DBUS_POINTER_TO_INT. Only guaranteed to preserve 32 bits. + * + * @param integer the integer to stuff into a pointer. + */ +/** + * @def _DBUS_ZERO + * + * Sets all bits in an object to zero. + * + * @param object the object to be zeroed. + */ +/** + * @def _DBUS_INT16_MIN + * + * Minimum value of type "int16" + */ +/** + * @def _DBUS_INT16_MAX + * + * Maximum value of type "int16" + */ +/** + * @def _DBUS_UINT16_MAX + * + * Maximum value of type "uint16" + */ + +/** + * @def _DBUS_INT32_MIN + * + * Minimum value of type "int32" + */ +/** + * @def _DBUS_INT32_MAX + * + * Maximum value of type "int32" + */ +/** + * @def _DBUS_UINT32_MAX + * + * Maximum value of type "uint32" + */ + +/** + * @def _DBUS_INT_MIN + * + * Minimum value of type "int" + */ +/** + * @def _DBUS_INT_MAX + * + * Maximum value of type "int" + */ +/** + * @def _DBUS_UINT_MAX + * + * Maximum value of type "uint" + */ + +/** + * @typedef DBusForeachFunction + * + * Used to iterate over each item in a collection, such as + * a DBusList. + */ + +/** + * @def _DBUS_LOCK_NAME + * + * Expands to name of a global lock variable. + */ + +/** + * @def _DBUS_DEFINE_GLOBAL_LOCK + * + * Defines a global lock variable with the given name. + * The lock must be added to the list to initialize + * in dbus_threads_init(). + */ + +/** + * @def _DBUS_DECLARE_GLOBAL_LOCK + * + * Expands to declaration of a global lock defined + * with _DBUS_DEFINE_GLOBAL_LOCK. + * The lock must be added to the list to initialize + * in dbus_threads_init(). + */ + +/** + * @def _DBUS_LOCK + * + * Locks a global lock + */ + +/** + * @def _DBUS_UNLOCK + * + * Unlocks a global lock + */ + +/** + * Fixed "out of memory" error message, just to avoid + * making up a different string every time and wasting + * space. + */ +const char _dbus_no_memory_message[] = "Not enough memory"; + +static dbus_bool_t warn_initted = FALSE; +static dbus_bool_t fatal_warnings = FALSE; +static dbus_bool_t fatal_warnings_on_check_failed = TRUE; + +static void +init_warnings(void) +{ + if (!warn_initted) + { + const char *s; + s = _dbus_getenv ("DBUS_FATAL_WARNINGS"); + if (s && *s) + { + if (*s == '0') + { + fatal_warnings = FALSE; + fatal_warnings_on_check_failed = FALSE; + } + else if (*s == '1') + { + fatal_warnings = TRUE; + fatal_warnings_on_check_failed = TRUE; + } + else + { + fprintf(stderr, "DBUS_FATAL_WARNINGS should be set to 0 or 1 if set, not '%s'", + s); + } + } + + warn_initted = TRUE; + } +} + +/** + * Prints a warning message to stderr. Can optionally be made to exit + * fatally by setting DBUS_FATAL_WARNINGS, but this is rarely + * used. This function should be considered pretty much equivalent to + * fprintf(stderr). _dbus_warn_check_failed() on the other hand is + * suitable for use when a programming mistake has been made. + * + * @param format printf-style format string. + */ +void +_dbus_warn (const char *format, + ...) +{ + va_list args; + + if (!warn_initted) + init_warnings (); + + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + + if (fatal_warnings) + { + fflush (stderr); + _dbus_abort (); + } +} + +/** + * Prints a "critical" warning to stderr when an assertion fails; + * differs from _dbus_warn primarily in that it prefixes the pid and + * defaults to fatal. This should be used only when a programming + * error has been detected. (NOT for unavoidable errors that an app + * might handle - those should be returned as DBusError.) Calling this + * means "there is a bug" + */ +void +_dbus_warn_check_failed(const char *format, + ...) +{ + va_list args; + + if (!warn_initted) + init_warnings (); + + fprintf (stderr, "process %lu: ", _dbus_pid_for_log ()); + + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + + if (fatal_warnings_on_check_failed) + { + fflush (stderr); + _dbus_abort (); + } +} + +#ifdef DBUS_ENABLE_VERBOSE_MODE + +static dbus_bool_t verbose_initted = FALSE; +static dbus_bool_t verbose = TRUE; + +/** Whether to show the current thread in verbose messages */ +#define PTHREAD_IN_VERBOSE 0 +#if PTHREAD_IN_VERBOSE +#include +#endif + +#ifdef DBUS_WIN +#define inline +#endif + +static inline void +_dbus_verbose_init (void) +{ + if (!verbose_initted) + { + const char *p = _dbus_getenv ("DBUS_VERBOSE"); + verbose = p != NULL && *p == '1'; + verbose_initted = TRUE; + } +} + +/** + * Implementation of dbus_is_verbose() macro if built with verbose logging + * enabled. + * @returns whether verbose logging is active. + */ +dbus_bool_t +_dbus_is_verbose_real (void) +{ + _dbus_verbose_init (); + return verbose; +} + +/** + * Prints a warning message to stderr + * if the user has enabled verbose mode. + * This is the real function implementation, + * use _dbus_verbose() macro in code. + * + * @param format printf-style format string. + */ +void +_dbus_verbose_real (const char *format, + ...) +{ + va_list args; + static dbus_bool_t need_pid = TRUE; + int len; + + /* things are written a bit oddly here so that + * in the non-verbose case we just have the one + * conditional and return immediately. + */ + if (!_dbus_is_verbose_real()) + return; + + /* Print out pid before the line */ + if (need_pid) + { +#if PTHREAD_IN_VERBOSE + fprintf (stderr, "%lu: 0x%lx: ", _dbus_pid_for_log (), pthread_self ()); +#else + fprintf (stderr, "%lu: ", _dbus_pid_for_log ()); +#endif + } + + + /* Only print pid again if the next line is a new line */ + len = strlen (format); + if (format[len-1] == '\n') + need_pid = TRUE; + else + need_pid = FALSE; + + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + + fflush (stderr); +} + +/** + * Reinitializes the verbose logging code, used + * as a hack in dbus-spawn.c so that a child + * process re-reads its pid + * + */ +void +_dbus_verbose_reset_real (void) +{ + verbose_initted = FALSE; +} + +#endif /* DBUS_ENABLE_VERBOSE_MODE */ + +/** + * Duplicates a string. Result must be freed with + * dbus_free(). Returns #NULL if memory allocation fails. + * If the string to be duplicated is #NULL, returns #NULL. + * + * @param str string to duplicate. + * @returns newly-allocated copy. + */ +char* +_dbus_strdup (const char *str) +{ + size_t len; + char *copy; + + if (str == NULL) + return NULL; + + len = strlen (str); + + copy = dbus_malloc (len + 1); + if (copy == NULL) + return NULL; + + memcpy (copy, str, len + 1); + + return copy; +} + +/** + * Duplicates a block of memory. Returns + * #NULL on failure. + * + * @param mem memory to copy + * @param n_bytes number of bytes to copy + * @returns the copy + */ +void* +_dbus_memdup (const void *mem, + size_t n_bytes) +{ + void *copy; + + copy = dbus_malloc (n_bytes); + if (copy == NULL) + return NULL; + + memcpy (copy, mem, n_bytes); + + return copy; +} + +/** + * Duplicates a string array. Result may be freed with + * dbus_free_string_array(). Returns #NULL if memory allocation fails. + * If the array to be duplicated is #NULL, returns #NULL. + * + * @param array array to duplicate. + * @returns newly-allocated copy. + */ +char** +_dbus_dup_string_array (const char **array) +{ + int len; + int i; + char **copy; + + if (array == NULL) + return NULL; + + for (len = 0; array[len] != NULL; ++len) + ; + + copy = dbus_new0 (char*, len + 1); + if (copy == NULL) + return NULL; + + i = 0; + while (i < len) + { + copy[i] = _dbus_strdup (array[i]); + if (copy[i] == NULL) + { + dbus_free_string_array (copy); + return NULL; + } + + ++i; + } + + return copy; +} + +/** + * Checks whether a string array contains the given string. + * + * @param array array to search. + * @param str string to look for + * @returns #TRUE if array contains string + */ +dbus_bool_t +_dbus_string_array_contains (const char **array, + const char *str) +{ + int i; + + i = 0; + while (array[i] != NULL) + { + if (strcmp (array[i], str) == 0) + return TRUE; + ++i; + } + + return FALSE; +} + +/** + * Generates a new UUID. If you change how this is done, + * there's some text about it in the spec that should also change. + * + * @param uuid the uuid to initialize + */ +void +_dbus_generate_uuid (DBusGUID *uuid) +{ + long now; + + _dbus_get_current_time (&now, NULL); + + uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now); + + _dbus_generate_random_bytes_buffer (uuid->as_bytes, DBUS_UUID_LENGTH_BYTES - 4); +} + +/** + * Hex-encode a UUID. + * + * @param uuid the uuid + * @param encoded string to append hex uuid to + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_uuid_encode (const DBusGUID *uuid, + DBusString *encoded) +{ + DBusString binary; + _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES); + return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded)); +} + +static dbus_bool_t +_dbus_read_uuid_file_without_creating (const DBusString *filename, + DBusGUID *uuid, + DBusError *error) +{ + DBusString contents; + DBusString decoded; + int end; + + if (!_dbus_string_init (&contents)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_init (&decoded)) + { + _dbus_string_free (&contents); + _DBUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_file_get_contents (&contents, filename, error)) + goto error; + + _dbus_string_chop_white (&contents); + + if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX) + { + dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT, + "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text", + _dbus_string_get_const_data (filename), + DBUS_UUID_LENGTH_HEX, + _dbus_string_get_length (&contents)); + goto error; + } + + if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0)) + { + _DBUS_SET_OOM (error); + goto error; + } + + if (end == 0) + { + dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT, + "UUID file '%s' contains invalid hex data", + _dbus_string_get_const_data (filename)); + goto error; + } + + if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES) + { + dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT, + "UUID file '%s' contains %d bytes of hex-encoded data instead of %d", + _dbus_string_get_const_data (filename), + _dbus_string_get_length (&decoded), + DBUS_UUID_LENGTH_BYTES); + goto error; + } + + _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES); + + _dbus_string_free (&decoded); + _dbus_string_free (&contents); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + return TRUE; + + error: + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_string_free (&contents); + _dbus_string_free (&decoded); + return FALSE; +} + +static dbus_bool_t +_dbus_create_uuid_file_exclusively (const DBusString *filename, + DBusGUID *uuid, + DBusError *error) +{ + DBusString encoded; + + if (!_dbus_string_init (&encoded)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + _dbus_generate_uuid (uuid); + + if (!_dbus_uuid_encode (uuid, &encoded)) + { + _DBUS_SET_OOM (error); + goto error; + } + + /* FIXME this is racy; we need a save_file_exclusively + * function. But in practice this should be fine for now. + * + * - first be sure we can create the file and it + * doesn't exist by creating it empty with O_EXCL + * - then create it by creating a temporary file and + * overwriting atomically with rename() + */ + if (!_dbus_create_file_exclusively (filename, error)) + goto error; + + if (!_dbus_string_append_byte (&encoded, '\n')) + { + _DBUS_SET_OOM (error); + goto error; + } + + if (!_dbus_string_save_to_file (&encoded, filename, error)) + goto error; + + if (!_dbus_make_file_world_readable (filename, error)) + goto error; + + _dbus_string_free (&encoded); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return TRUE; + + error: + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_string_free (&encoded); + return FALSE; +} + +/** + * Reads (and optionally writes) a uuid to a file. Initializes the uuid + * unless an error is returned. + * + * @param filename the name of the file + * @param uuid uuid to be initialized with the loaded uuid + * @param create_if_not_found #TRUE to create a new uuid and save it if the file doesn't exist + * @param error the error return + * @returns #FALSE if the error is set + */ +dbus_bool_t +_dbus_read_uuid_file (const DBusString *filename, + DBusGUID *uuid, + dbus_bool_t create_if_not_found, + DBusError *error) +{ + DBusError read_error = DBUS_ERROR_INIT; + + if (_dbus_read_uuid_file_without_creating (filename, uuid, &read_error)) + return TRUE; + + if (!create_if_not_found) + { + dbus_move_error (&read_error, error); + return FALSE; + } + + /* If the file exists and contains junk, we want to keep that error + * message instead of overwriting it with a "file exists" error + * message when we try to write + */ + if (dbus_error_has_name (&read_error, DBUS_ERROR_INVALID_FILE_CONTENT)) + { + dbus_move_error (&read_error, error); + return FALSE; + } + else + { + dbus_error_free (&read_error); + return _dbus_create_uuid_file_exclusively (filename, uuid, error); + } +} + +_DBUS_DEFINE_GLOBAL_LOCK (machine_uuid); +static int machine_uuid_initialized_generation = 0; +static DBusGUID machine_uuid; + +/** + * Gets the hex-encoded UUID of the machine this function is + * executed on. This UUID is guaranteed to be the same for a given + * machine at least until it next reboots, though it also + * makes some effort to be the same forever, it may change if the + * machine is reconfigured or its hardware is modified. + * + * @param uuid_str string to append hex-encoded machine uuid to + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_get_local_machine_uuid_encoded (DBusString *uuid_str) +{ + dbus_bool_t ok; + + _DBUS_LOCK (machine_uuid); + if (machine_uuid_initialized_generation != _dbus_current_generation) + { + DBusError error = DBUS_ERROR_INIT; + + if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE, + &error)) + { +#ifndef DBUS_BUILD_TESTS + /* For the test suite, we may not be installed so just continue silently + * here. But in a production build, we want to be nice and loud about + * this. + */ + _dbus_warn_check_failed ("D-Bus library appears to be incorrectly set up; failed to read machine uuid: %s\n" + "See the manual page for dbus-uuidgen to correct this issue.\n", + error.message); +#endif + + dbus_error_free (&error); + + _dbus_generate_uuid (&machine_uuid); + } + } + + ok = _dbus_uuid_encode (&machine_uuid, uuid_str); + + _DBUS_UNLOCK (machine_uuid); + + return ok; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Returns a string describing the given name. + * + * @param header_field the field to describe + * @returns a constant string describing the field + */ +const char * +_dbus_header_field_to_string (int header_field) +{ + switch (header_field) + { + case DBUS_HEADER_FIELD_INVALID: + return "invalid"; + case DBUS_HEADER_FIELD_PATH: + return "path"; + case DBUS_HEADER_FIELD_INTERFACE: + return "interface"; + case DBUS_HEADER_FIELD_MEMBER: + return "member"; + case DBUS_HEADER_FIELD_ERROR_NAME: + return "error-name"; + case DBUS_HEADER_FIELD_REPLY_SERIAL: + return "reply-serial"; + case DBUS_HEADER_FIELD_DESTINATION: + return "destination"; + case DBUS_HEADER_FIELD_SENDER: + return "sender"; + case DBUS_HEADER_FIELD_SIGNATURE: + return "signature"; + default: + return "unknown"; + } +} +#endif /* DBUS_BUILD_TESTS */ + +#ifndef DBUS_DISABLE_CHECKS +/** String used in _dbus_return_if_fail macro */ +const char _dbus_return_if_fail_warning_format[] = +"arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n" +"This is normally a bug in some application using the D-Bus library.\n"; +#endif + +#ifndef DBUS_DISABLE_ASSERT +/** + * Internals of _dbus_assert(); it's a function + * rather than a macro with the inline code so + * that the assertion failure blocks don't show up + * in test suite coverage, and to shrink code size. + * + * @param condition TRUE if assertion succeeded + * @param condition_text condition as a string + * @param file file the assertion is in + * @param line line the assertion is in + * @param func function the assertion is in + */ +void +_dbus_real_assert (dbus_bool_t condition, + const char *condition_text, + const char *file, + int line, + const char *func) +{ + if (_DBUS_UNLIKELY (!condition)) + { + _dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d function %s\n", + _dbus_pid_for_log (), condition_text, file, line, func); + _dbus_abort (); + } +} + +/** + * Internals of _dbus_assert_not_reached(); it's a function + * rather than a macro with the inline code so + * that the assertion failure blocks don't show up + * in test suite coverage, and to shrink code size. + * + * @param explanation what was reached that shouldn't have been + * @param file file the assertion is in + * @param line line the assertion is in + */ +void +_dbus_real_assert_not_reached (const char *explanation, + const char *file, + int line) +{ + _dbus_warn ("File \"%s\" line %d process %lu should not have been reached: %s\n", + file, line, _dbus_pid_for_log (), explanation); + _dbus_abort (); +} +#endif /* DBUS_DISABLE_ASSERT */ + +#ifdef DBUS_BUILD_TESTS +static dbus_bool_t +run_failing_each_malloc (int n_mallocs, + const char *description, + DBusTestMemoryFunction func, + void *data) +{ + n_mallocs += 10; /* fudge factor to ensure reallocs etc. are covered */ + + while (n_mallocs >= 0) + { + _dbus_set_fail_alloc_counter (n_mallocs); + + _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n", + description, n_mallocs, + _dbus_get_fail_alloc_failures ()); + + if (!(* func) (data)) + return FALSE; + + n_mallocs -= 1; + } + + _dbus_set_fail_alloc_counter (_DBUS_INT_MAX); + + return TRUE; +} + +/** + * Tests how well the given function responds to out-of-memory + * situations. Calls the function repeatedly, failing a different + * call to malloc() each time. If the function ever returns #FALSE, + * the test fails. The function should return #TRUE whenever something + * valid (such as returning an error, or succeeding) occurs, and #FALSE + * if it gets confused in some way. + * + * @param description description of the test used in verbose output + * @param func function to call + * @param data data to pass to function + * @returns #TRUE if the function never returns FALSE + */ +dbus_bool_t +_dbus_test_oom_handling (const char *description, + DBusTestMemoryFunction func, + void *data) +{ + int approx_mallocs; + const char *setting; + int max_failures_to_try; + int i; + + /* Run once to see about how many mallocs are involved */ + + _dbus_set_fail_alloc_counter (_DBUS_INT_MAX); + + _dbus_verbose ("Running once to count mallocs\n"); + + if (!(* func) (data)) + return FALSE; + + approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter (); + + _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n", + description, approx_mallocs); + + setting = _dbus_getenv ("DBUS_TEST_MALLOC_FAILURES"); + if (setting != NULL) + { + DBusString str; + long v; + _dbus_string_init_const (&str, setting); + v = 4; + if (!_dbus_string_parse_int (&str, 0, &v, NULL)) + _dbus_warn ("couldn't parse '%s' as integer\n", setting); + max_failures_to_try = v; + } + else + { + max_failures_to_try = 4; + } + + i = setting ? max_failures_to_try - 1 : 1; + while (i < max_failures_to_try) + { + _dbus_set_fail_alloc_failures (i); + if (!run_failing_each_malloc (approx_mallocs, description, func, data)) + return FALSE; + ++i; + } + + _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n", + description); + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ + +/** @} */ diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h new file mode 100644 index 00000000..54c73fca --- /dev/null +++ b/dbus/dbus-internals.h @@ -0,0 +1,346 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-internals.h random utility stuff (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifdef DBUS_INSIDE_DBUS_H +#error "You can't include dbus-internals.h in the public header dbus.h" +#endif + +#ifndef DBUS_INTERNALS_H +#define DBUS_INTERNALS_H + +#include + +#include +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +#define DBUS_SESSION_BUS_DEFAULT_ADDRESS "autolaunch:" + +void _dbus_warn (const char *format, + ...) _DBUS_GNUC_PRINTF (1, 2); + +void _dbus_warn_check_failed (const char *format, + ...) _DBUS_GNUC_PRINTF (1, 2); + + +#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define _DBUS_FUNCTION_NAME __func__ +#elif defined(__GNUC__) || defined(_MSC_VER) +#define _DBUS_FUNCTION_NAME __FUNCTION__ +#else +#define _DBUS_FUNCTION_NAME "unknown function" +#endif + +/* + * (code from GLib) + * + * The _DBUS_LIKELY and _DBUS_UNLIKELY macros let the programmer give hints to + * the compiler about the expected result of an expression. Some compilers + * can use this information for optimizations. + * + * The _DBUS_BOOLEAN_EXPR macro is intended to trigger a gcc warning when + * putting assignments in the macro arg + */ +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +#define _DBUS_BOOLEAN_EXPR(expr) \ + __extension__ ({ \ + int _dbus_boolean_var_; \ + if (expr) \ + _dbus_boolean_var_ = 1; \ + else \ + _dbus_boolean_var_ = 0; \ + _dbus_boolean_var_; \ +}) +#define _DBUS_LIKELY(expr) (__builtin_expect (_DBUS_BOOLEAN_EXPR(expr), 1)) +#define _DBUS_UNLIKELY(expr) (__builtin_expect (_DBUS_BOOLEAN_EXPR(expr), 0)) +#else +#define _DBUS_LIKELY(expr) (expr) +#define _DBUS_UNLIKELY(expr) (expr) +#endif + +#ifdef DBUS_ENABLE_VERBOSE_MODE + +void _dbus_verbose_real (const char *format, + ...) _DBUS_GNUC_PRINTF (1, 2); +void _dbus_verbose_reset_real (void); +dbus_bool_t _dbus_is_verbose_real (void); + +# define _dbus_verbose _dbus_verbose_real +# define _dbus_verbose_reset _dbus_verbose_reset_real +# define _dbus_is_verbose _dbus_is_verbose_real +#else +# ifdef HAVE_ISO_VARARGS +# define _dbus_verbose(...) +# elif defined (HAVE_GNUC_VARARGS) +# define _dbus_verbose(format...) +# else +static void _dbus_verbose(const char * x,...) {;} +# endif +# define _dbus_verbose_reset() +# define _dbus_is_verbose() FALSE +#endif /* !DBUS_ENABLE_VERBOSE_MODE */ + +const char* _dbus_strerror (int error_number); + +#ifdef DBUS_DISABLE_ASSERT +#define _dbus_assert(condition) +#else +void _dbus_real_assert (dbus_bool_t condition, + const char *condition_text, + const char *file, + int line, + const char *func); +#define _dbus_assert(condition) \ + _dbus_real_assert ((condition) != 0, #condition, __FILE__, __LINE__, _DBUS_FUNCTION_NAME) +#endif /* !DBUS_DISABLE_ASSERT */ + +#ifdef DBUS_DISABLE_ASSERT +#define _dbus_assert_not_reached(explanation) +#else +void _dbus_real_assert_not_reached (const char *explanation, + const char *file, + int line) _DBUS_GNUC_NORETURN; +#define _dbus_assert_not_reached(explanation) \ + _dbus_real_assert_not_reached (explanation, __FILE__, __LINE__) +#endif /* !DBUS_DISABLE_ASSERT */ + +#ifdef DBUS_DISABLE_CHECKS +#define _dbus_return_if_fail(condition) +#define _dbus_return_val_if_fail(condition, val) +#else +extern const char _dbus_return_if_fail_warning_format[]; + +#define _dbus_return_if_fail(condition) do { \ + _dbus_assert ((*(const char*)_DBUS_FUNCTION_NAME) != '_'); \ + if (!(condition)) { \ + _dbus_warn_check_failed (_dbus_return_if_fail_warning_format, \ + _DBUS_FUNCTION_NAME, #condition, __FILE__, __LINE__); \ + return; \ + } } while (0) + +#define _dbus_return_val_if_fail(condition, val) do { \ + _dbus_assert ((*(const char*)_DBUS_FUNCTION_NAME) != '_'); \ + if (!(condition)) { \ + _dbus_warn_check_failed (_dbus_return_if_fail_warning_format, \ + _DBUS_FUNCTION_NAME, #condition, __FILE__, __LINE__); \ + return (val); \ + } } while (0) + +#endif /* !DBUS_DISABLE_ASSERT */ + +#define _DBUS_N_ELEMENTS(array) ((int) (sizeof ((array)) / sizeof ((array)[0]))) + +#define _DBUS_POINTER_TO_INT(pointer) ((long)(pointer)) +#define _DBUS_INT_TO_POINTER(integer) ((void*)((long)(integer))) + +#define _DBUS_ZERO(object) (memset (&(object), '\0', sizeof ((object)))) + +#define _DBUS_STRUCT_OFFSET(struct_type, member) \ + ((long) ((unsigned char*) &((struct_type*) 0)->member)) + +#ifdef DBUS_DISABLE_CHECKS +/* this is an assert and not an error, but in the typical --disable-checks case (you're trying + * to really minimize code size), disabling these assertions makes sense. + */ +#define _DBUS_ASSERT_ERROR_IS_SET(error) +#define _DBUS_ASSERT_ERROR_IS_CLEAR(error) +#else +#define _DBUS_ASSERT_ERROR_IS_SET(error) _dbus_assert ((error) == NULL || dbus_error_is_set ((error))) +#define _DBUS_ASSERT_ERROR_IS_CLEAR(error) _dbus_assert ((error) == NULL || !dbus_error_is_set ((error))) +#endif + +#define _dbus_return_if_error_is_set(error) _dbus_return_if_fail ((error) == NULL || !dbus_error_is_set ((error))) +#define _dbus_return_val_if_error_is_set(error, val) _dbus_return_val_if_fail ((error) == NULL || !dbus_error_is_set ((error)), (val)) + +/* This alignment thing is from ORBit2 */ +/* Align a value upward to a boundary, expressed as a number of bytes. + * E.g. align to an 8-byte boundary with argument of 8. + */ + +/* + * (this + boundary - 1) + * & + * ~(boundary - 1) + */ + +#define _DBUS_ALIGN_VALUE(this, boundary) \ + (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1))) + +#define _DBUS_ALIGN_ADDRESS(this, boundary) \ + ((void*)_DBUS_ALIGN_VALUE(this, boundary)) + + +char* _dbus_strdup (const char *str); +void* _dbus_memdup (const void *mem, + size_t n_bytes); +dbus_bool_t _dbus_string_array_contains (const char **array, + const char *str); +char** _dbus_dup_string_array (const char **array); + +#define _DBUS_INT16_MIN ((dbus_int16_t) 0x8000) +#define _DBUS_INT16_MAX ((dbus_int16_t) 0x7fff) +#define _DBUS_UINT16_MAX ((dbus_uint16_t)0xffff) +#define _DBUS_INT32_MIN ((dbus_int32_t) 0x80000000) +#define _DBUS_INT32_MAX ((dbus_int32_t) 0x7fffffff) +#define _DBUS_UINT32_MAX ((dbus_uint32_t)0xffffffff) +/* using 32-bit here is sort of bogus */ +#define _DBUS_INT_MIN _DBUS_INT32_MIN +#define _DBUS_INT_MAX _DBUS_INT32_MAX +#define _DBUS_UINT_MAX _DBUS_UINT32_MAX +#ifdef DBUS_HAVE_INT64 +#define _DBUS_INT64_MAX DBUS_INT64_CONSTANT (0x7fffffffffffffff) +#define _DBUS_UINT64_MAX DBUS_UINT64_CONSTANT (0xffffffffffffffff) +#endif +#define _DBUS_ONE_KILOBYTE 1024 +#define _DBUS_ONE_MEGABYTE 1024 * _DBUS_ONE_KILOBYTE +#define _DBUS_ONE_HOUR_IN_MILLISECONDS (1000 * 60 * 60) +#define _DBUS_USEC_PER_SECOND (1000000) + +#undef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#undef ABS +#define ABS(a) (((a) < 0) ? -(a) : (a)) + +#define _DBUS_ISASCII(c) ((c) != '\0' && (((c) & ~0x7f) == 0)) + +typedef void (* DBusForeachFunction) (void *element, + void *data); + +dbus_bool_t _dbus_set_fd_nonblocking (int fd, + DBusError *error); + +void _dbus_verbose_bytes (const unsigned char *data, + int len, + int offset); +void _dbus_verbose_bytes_of_string (const DBusString *str, + int start, + int len); + +const char* _dbus_header_field_to_string (int header_field); + +extern const char _dbus_no_memory_message[]; +#define _DBUS_SET_OOM(error) dbus_set_error_const ((error), DBUS_ERROR_NO_MEMORY, _dbus_no_memory_message) + +#ifdef DBUS_BUILD_TESTS +/* Memory debugging */ +void _dbus_set_fail_alloc_counter (int until_next_fail); +int _dbus_get_fail_alloc_counter (void); +void _dbus_set_fail_alloc_failures (int failures_per_failure); +int _dbus_get_fail_alloc_failures (void); +dbus_bool_t _dbus_decrement_fail_alloc_counter (void); +dbus_bool_t _dbus_disable_mem_pools (void); +int _dbus_get_malloc_blocks_outstanding (void); + +typedef dbus_bool_t (* DBusTestMemoryFunction) (void *data); +dbus_bool_t _dbus_test_oom_handling (const char *description, + DBusTestMemoryFunction func, + void *data); +#else +#define _dbus_set_fail_alloc_counter(n) +#define _dbus_get_fail_alloc_counter _DBUS_INT_MAX + +/* These are constant expressions so that blocks + * they protect should be optimized away + */ +#define _dbus_decrement_fail_alloc_counter() (FALSE) +#define _dbus_disable_mem_pools() (FALSE) +#define _dbus_get_malloc_blocks_outstanding (0) +#endif /* !DBUS_BUILD_TESTS */ + +typedef void (* DBusShutdownFunction) (void *data); +dbus_bool_t _dbus_register_shutdown_func (DBusShutdownFunction function, + void *data); + +extern int _dbus_current_generation; + +/* Thread initializers */ +#define _DBUS_LOCK_NAME(name) _dbus_lock_##name +#define _DBUS_DECLARE_GLOBAL_LOCK(name) extern DBusMutex *_dbus_lock_##name +#define _DBUS_DEFINE_GLOBAL_LOCK(name) DBusMutex *_dbus_lock_##name +#define _DBUS_LOCK(name) _dbus_mutex_lock (_dbus_lock_##name) +#define _DBUS_UNLOCK(name) _dbus_mutex_unlock (_dbus_lock_##name) + +/* 1-5 */ +_DBUS_DECLARE_GLOBAL_LOCK (list); +_DBUS_DECLARE_GLOBAL_LOCK (connection_slots); +_DBUS_DECLARE_GLOBAL_LOCK (pending_call_slots); +_DBUS_DECLARE_GLOBAL_LOCK (server_slots); +_DBUS_DECLARE_GLOBAL_LOCK (message_slots); +/* 5-10 */ +_DBUS_DECLARE_GLOBAL_LOCK (atomic); +_DBUS_DECLARE_GLOBAL_LOCK (bus); +_DBUS_DECLARE_GLOBAL_LOCK (bus_datas); +_DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs); +_DBUS_DECLARE_GLOBAL_LOCK (system_users); +/* 10-15 */ +_DBUS_DECLARE_GLOBAL_LOCK (message_cache); +_DBUS_DECLARE_GLOBAL_LOCK (shared_connections); +_DBUS_DECLARE_GLOBAL_LOCK (win_fds); +_DBUS_DECLARE_GLOBAL_LOCK (sid_atom_cache); +_DBUS_DECLARE_GLOBAL_LOCK (machine_uuid); +#define _DBUS_N_GLOBAL_LOCKS (15) + +dbus_bool_t _dbus_threads_init_debug (void); + +dbus_bool_t _dbus_address_append_escaped (DBusString *escaped, + const DBusString *unescaped); + +void _dbus_set_bad_address (DBusError *error, + const char *address_problem_type, + const char *address_problem_field, + const char *address_problem_other); + +#define DBUS_UUID_LENGTH_BYTES 16 +#define DBUS_UUID_LENGTH_WORDS (DBUS_UUID_LENGTH_BYTES / 4) +#define DBUS_UUID_LENGTH_HEX (DBUS_UUID_LENGTH_BYTES * 2) + +/** + * A globally unique ID ; we have one for each DBusServer, and also one for each + * machine with libdbus installed on it. + */ +union DBusGUID +{ + dbus_uint32_t as_uint32s[DBUS_UUID_LENGTH_WORDS]; /**< guid as four uint32 values */ + char as_bytes[DBUS_UUID_LENGTH_BYTES]; /**< guid as 16 single-byte values */ +}; + +void _dbus_generate_uuid (DBusGUID *uuid); +dbus_bool_t _dbus_uuid_encode (const DBusGUID *uuid, + DBusString *encoded); +dbus_bool_t _dbus_read_uuid_file (const DBusString *filename, + DBusGUID *uuid, + dbus_bool_t create_if_not_found, + DBusError *error); + +dbus_bool_t _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str); + +DBUS_END_DECLS + +#endif /* DBUS_INTERNALS_H */ diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c new file mode 100644 index 00000000..6dc1e129 --- /dev/null +++ b/dbus/dbus-keyring.c @@ -0,0 +1,1154 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-keyring.c Store secret cookies in your homedir + * + * Copyright (C) 2003, 2004 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-keyring.h" +#include "dbus-protocol.h" +#include +#include +#include + +/** + * @defgroup DBusKeyring keyring class + * @ingroup DBusInternals + * @brief DBusKeyring data structure + * + * Types and functions related to DBusKeyring. DBusKeyring is intended + * to manage cookies used to authenticate clients to servers. This is + * essentially the "verify that client can read the user's homedir" + * authentication mechanism. Both client and server must have access + * to the homedir. + * + * The secret keys are not kept in locked memory, and are written to a + * file in the user's homedir. However they are transient (only used + * by a single server instance for a fixed period of time, then + * discarded). Also, the keys are not sent over the wire. + * + * @todo there's a memory leak on some codepath in here, I saw it once + * when running make check - probably some specific initial cookies + * present in the cookie file, then depending on what we do with them. + */ + +/** + * @defgroup DBusKeyringInternals DBusKeyring implementation details + * @ingroup DBusInternals + * @brief DBusKeyring implementation details + * + * The guts of DBusKeyring. + * + * @{ + */ + +/** The maximum age of a key before we create a new key to use in + * challenges. This isn't super-reliably enforced, since system + * clocks can change or be wrong, but we make a best effort to only + * use keys for a short time. + */ +#define NEW_KEY_TIMEOUT_SECONDS (60*5) +/** + * The time after which we drop a key from the secrets file. + * The EXPIRE_KEYS_TIMEOUT_SECONDS - NEW_KEY_TIMEOUT_SECONDS is the minimum + * time window a client has to complete authentication. + */ +#define EXPIRE_KEYS_TIMEOUT_SECONDS (NEW_KEY_TIMEOUT_SECONDS + (60*2)) +/** + * The maximum amount of time a key can be in the future. + */ +#define MAX_TIME_TRAVEL_SECONDS (60*5) + +/** + * Maximum number of keys in the keyring before + * we just ignore the rest + */ +#ifdef DBUS_BUILD_TESTS +#define MAX_KEYS_IN_FILE 10 +#else +#define MAX_KEYS_IN_FILE 256 +#endif + +/** + * A single key from the cookie file + */ +typedef struct +{ + dbus_int32_t id; /**< identifier used to refer to the key */ + + long creation_time; /**< when the key was generated, + * as unix timestamp. signed long + * matches struct timeval. + */ + + DBusString secret; /**< the actual key */ + +} DBusKey; + +/** + * @brief Internals of DBusKeyring. + * + * DBusKeyring internals. DBusKeyring is an opaque object, it must be + * used via accessor functions. + */ +struct DBusKeyring +{ + int refcount; /**< Reference count */ + DBusString directory; /**< Directory the below two items are inside */ + DBusString filename; /**< Keyring filename */ + DBusString filename_lock; /**< Name of lockfile */ + DBusKey *keys; /**< Keys loaded from the file */ + int n_keys; /**< Number of keys */ + DBusCredentials *credentials; /**< Credentials containing user the keyring is for */ +}; + +static DBusKeyring* +_dbus_keyring_new (void) +{ + DBusKeyring *keyring; + + keyring = dbus_new0 (DBusKeyring, 1); + if (keyring == NULL) + goto out_0; + + if (!_dbus_string_init (&keyring->directory)) + goto out_1; + + if (!_dbus_string_init (&keyring->filename)) + goto out_2; + + if (!_dbus_string_init (&keyring->filename_lock)) + goto out_3; + + keyring->refcount = 1; + keyring->keys = NULL; + keyring->n_keys = 0; + + return keyring; + + /* out_4: */ + _dbus_string_free (&keyring->filename_lock); + out_3: + _dbus_string_free (&keyring->filename); + out_2: + _dbus_string_free (&keyring->directory); + out_1: + dbus_free (keyring); + out_0: + return NULL; +} + +static void +free_keys (DBusKey *keys, + int n_keys) +{ + int i; + + /* should be safe for args NULL, 0 */ + + i = 0; + while (i < n_keys) + { + _dbus_string_free (&keys[i].secret); + ++i; + } + + dbus_free (keys); +} + +/* Our locking scheme is highly unreliable. However, there is + * unfortunately no reliable locking scheme in user home directories; + * between bugs in Linux NFS, people using Tru64 or other total crap + * NFS, AFS, random-file-system-of-the-week, and so forth, fcntl() in + * homedirs simply generates tons of bug reports. This has been + * learned through hard experience with GConf, unfortunately. + * + * This bad hack might work better for the kind of lock we have here, + * which we don't expect to hold for any length of time. Crashing + * while we hold it should be unlikely, and timing out such that we + * delete a stale lock should also be unlikely except when the + * filesystem is running really slowly. Stuff might break in corner + * cases but as long as it's not a security-level breakage it should + * be OK. + */ + +/** Maximum number of timeouts waiting for lock before we decide it's stale */ +#define MAX_LOCK_TIMEOUTS 32 +/** Length of each timeout while waiting for a lock */ +#define LOCK_TIMEOUT_MILLISECONDS 250 + +static dbus_bool_t +_dbus_keyring_lock (DBusKeyring *keyring) +{ + int n_timeouts; + + n_timeouts = 0; + while (n_timeouts < MAX_LOCK_TIMEOUTS) + { + DBusError error = DBUS_ERROR_INIT; + + if (_dbus_create_file_exclusively (&keyring->filename_lock, + &error)) + break; + + _dbus_verbose ("Did not get lock file, sleeping %d milliseconds (%s)\n", + LOCK_TIMEOUT_MILLISECONDS, error.message); + dbus_error_free (&error); + + _dbus_sleep_milliseconds (LOCK_TIMEOUT_MILLISECONDS); + + ++n_timeouts; + } + + if (n_timeouts == MAX_LOCK_TIMEOUTS) + { + DBusError error = DBUS_ERROR_INIT; + + _dbus_verbose ("Lock file timed out %d times, assuming stale\n", + n_timeouts); + + if (!_dbus_delete_file (&keyring->filename_lock, &error)) + { + _dbus_verbose ("Couldn't delete old lock file: %s\n", + error.message); + dbus_error_free (&error); + return FALSE; + } + + if (!_dbus_create_file_exclusively (&keyring->filename_lock, + &error)) + { + _dbus_verbose ("Couldn't create lock file after deleting stale one: %s\n", + error.message); + dbus_error_free (&error); + return FALSE; + } + } + + return TRUE; +} + +static void +_dbus_keyring_unlock (DBusKeyring *keyring) +{ + DBusError error = DBUS_ERROR_INIT; + + if (!_dbus_delete_file (&keyring->filename_lock, &error)) + { + _dbus_warn ("Failed to delete lock file: %s\n", + error.message); + dbus_error_free (&error); + } +} + +static DBusKey* +find_key_by_id (DBusKey *keys, + int n_keys, + int id) +{ + int i; + + i = 0; + while (i < n_keys) + { + if (keys[i].id == id) + return &keys[i]; + + ++i; + } + + return NULL; +} + +static dbus_bool_t +add_new_key (DBusKey **keys_p, + int *n_keys_p, + DBusError *error) +{ + DBusKey *new; + DBusString bytes; + int id; + long timestamp; + const unsigned char *s; + dbus_bool_t retval; + DBusKey *keys; + int n_keys; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&bytes)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return FALSE; + } + + keys = *keys_p; + n_keys = *n_keys_p; + retval = FALSE; + + /* Generate an integer ID and then the actual key. */ + retry: + + if (!_dbus_generate_random_bytes (&bytes, 4)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + s = (const unsigned char*) _dbus_string_get_const_data (&bytes); + + id = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); + if (id < 0) + id = - id; + _dbus_assert (id >= 0); + + if (find_key_by_id (keys, n_keys, id) != NULL) + { + _dbus_string_set_length (&bytes, 0); + _dbus_verbose ("Key ID %d already existed, trying another one\n", + id); + goto retry; + } + + _dbus_verbose ("Creating key with ID %d\n", id); + +#define KEY_LENGTH_BYTES 24 + _dbus_string_set_length (&bytes, 0); + if (!_dbus_generate_random_bytes (&bytes, KEY_LENGTH_BYTES)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1)); + if (new == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + keys = new; + *keys_p = keys; /* otherwise *keys_p ends up invalid */ + n_keys += 1; + + if (!_dbus_string_init (&keys[n_keys-1].secret)) + { + n_keys -= 1; /* we don't want to free the one we didn't init */ + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + _dbus_get_current_time (×tamp, NULL); + + keys[n_keys-1].id = id; + keys[n_keys-1].creation_time = timestamp; + if (!_dbus_string_move (&bytes, 0, + &keys[n_keys-1].secret, + 0)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (&keys[n_keys-1].secret); + n_keys -= 1; + goto out; + } + + retval = TRUE; + + out: + *n_keys_p = n_keys; + + _dbus_string_free (&bytes); + return retval; +} + +/** + * Reloads the keyring file, optionally adds one new key to the file, + * removes all expired keys from the file iff a key was added, then + * resaves the file. Stores the keys from the file in keyring->keys. + * Note that the file is only resaved (written to) if a key is added, + * this means that only servers ever write to the file and need to + * lock it, which avoids a lot of lock contention at login time and + * such. + * + * @param keyring the keyring + * @param add_new #TRUE to add a new key to the file, expire keys, and resave + * @param error return location for errors + * @returns #FALSE on failure + */ +static dbus_bool_t +_dbus_keyring_reload (DBusKeyring *keyring, + dbus_bool_t add_new, + DBusError *error) +{ + DBusString contents; + DBusString line; + dbus_bool_t retval; + dbus_bool_t have_lock; + DBusKey *keys; + int n_keys; + int i; + long now; + DBusError tmp_error; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_check_dir_is_private_to_user (&keyring->directory, error)) + return FALSE; + + if (!_dbus_string_init (&contents)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return FALSE; + } + + if (!_dbus_string_init (&line)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (&contents); + return FALSE; + } + + keys = NULL; + n_keys = 0; + retval = FALSE; + have_lock = FALSE; + + _dbus_get_current_time (&now, NULL); + + if (add_new) + { + if (!_dbus_keyring_lock (keyring)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Could not lock keyring file to add to it"); + goto out; + } + + have_lock = TRUE; + } + + dbus_error_init (&tmp_error); + if (!_dbus_file_get_contents (&contents, + &keyring->filename, + &tmp_error)) + { + _dbus_verbose ("Failed to load keyring file: %s\n", + tmp_error.message); + /* continue with empty keyring file, so we recreate it */ + dbus_error_free (&tmp_error); + } + + if (!_dbus_string_validate_ascii (&contents, 0, + _dbus_string_get_length (&contents))) + { + _dbus_warn ("Secret keyring file contains non-ASCII! Ignoring existing contents\n"); + _dbus_string_set_length (&contents, 0); + } + + /* FIXME this is badly inefficient for large keyring files + * (not that large keyring files exist outside of test suites) + */ + while (_dbus_string_pop_line (&contents, &line)) + { + int next; + long val; + int id; + long timestamp; + int len; + int end; + DBusKey *new; + + /* Don't load more than the max. */ + if (n_keys >= (add_new ? MAX_KEYS_IN_FILE - 1 : MAX_KEYS_IN_FILE)) + break; + + next = 0; + if (!_dbus_string_parse_int (&line, 0, &val, &next)) + { + _dbus_verbose ("could not parse secret key ID at start of line\n"); + continue; + } + + if (val > _DBUS_INT32_MAX || val < 0) + { + _dbus_verbose ("invalid secret key ID at start of line\n"); + continue; + } + + id = val; + + _dbus_string_skip_blank (&line, next, &next); + + if (!_dbus_string_parse_int (&line, next, ×tamp, &next)) + { + _dbus_verbose ("could not parse secret key timestamp\n"); + continue; + } + + if (timestamp < 0 || + (now + MAX_TIME_TRAVEL_SECONDS) < timestamp || + (now - EXPIRE_KEYS_TIMEOUT_SECONDS) > timestamp) + { + _dbus_verbose ("dropping/ignoring %ld-seconds old key with timestamp %ld as current time is %ld\n", + now - timestamp, timestamp, now); + continue; + } + + _dbus_string_skip_blank (&line, next, &next); + + len = _dbus_string_get_length (&line); + + if ((len - next) == 0) + { + _dbus_verbose ("no secret key after ID and timestamp\n"); + continue; + } + + /* We have all three parts */ + new = dbus_realloc (keys, sizeof (DBusKey) * (n_keys + 1)); + if (new == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + keys = new; + n_keys += 1; + + if (!_dbus_string_init (&keys[n_keys-1].secret)) + { + n_keys -= 1; /* we don't want to free the one we didn't init */ + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + keys[n_keys-1].id = id; + keys[n_keys-1].creation_time = timestamp; + if (!_dbus_string_hex_decode (&line, next, &end, + &keys[n_keys-1].secret, 0)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (_dbus_string_get_length (&line) != end) + { + _dbus_verbose ("invalid hex encoding in keyring file\n"); + _dbus_string_free (&keys[n_keys - 1].secret); + n_keys -= 1; + continue; + } + } + + _dbus_verbose ("Successfully loaded %d existing keys\n", + n_keys); + + if (add_new) + { + if (!add_new_key (&keys, &n_keys, error)) + { + _dbus_verbose ("Failed to generate new key: %s\n", + error ? error->message : "(unknown)"); + goto out; + } + + _dbus_string_set_length (&contents, 0); + + i = 0; + while (i < n_keys) + { + if (!_dbus_string_append_int (&contents, + keys[i].id)) + goto nomem; + + if (!_dbus_string_append_byte (&contents, ' ')) + goto nomem; + + if (!_dbus_string_append_int (&contents, + keys[i].creation_time)) + goto nomem; + + if (!_dbus_string_append_byte (&contents, ' ')) + goto nomem; + + if (!_dbus_string_hex_encode (&keys[i].secret, 0, + &contents, + _dbus_string_get_length (&contents))) + goto nomem; + + if (!_dbus_string_append_byte (&contents, '\n')) + goto nomem; + + ++i; + continue; + + nomem: + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto out; + } + + if (!_dbus_string_save_to_file (&contents, &keyring->filename, + error)) + goto out; + } + + if (keyring->keys) + free_keys (keyring->keys, keyring->n_keys); + keyring->keys = keys; + keyring->n_keys = n_keys; + keys = NULL; + n_keys = 0; + + retval = TRUE; + + out: + if (have_lock) + _dbus_keyring_unlock (keyring); + + if (! ((retval == TRUE && (error == NULL || error->name == NULL)) || + (retval == FALSE && (error == NULL || error->name != NULL)))) + { + if (error && error->name) + _dbus_verbose ("error is %s: %s\n", error->name, error->message); + _dbus_warn ("returning %d but error pointer %p name %s\n", + retval, error, error->name ? error->name : "(none)"); + _dbus_assert_not_reached ("didn't handle errors properly"); + } + + if (keys != NULL) + { + i = 0; + while (i < n_keys) + { + _dbus_string_zero (&keys[i].secret); + _dbus_string_free (&keys[i].secret); + ++i; + } + + dbus_free (keys); + } + + _dbus_string_free (&contents); + _dbus_string_free (&line); + + return retval; +} + +/** @} */ /* end of internals */ + +/** + * @addtogroup DBusKeyring + * + * @{ + */ + +/** + * Increments reference count of the keyring + * + * @param keyring the keyring + * @returns the keyring + */ +DBusKeyring * +_dbus_keyring_ref (DBusKeyring *keyring) +{ + keyring->refcount += 1; + + return keyring; +} + +/** + * Decrements refcount and finalizes if it reaches + * zero. + * + * @param keyring the keyring + */ +void +_dbus_keyring_unref (DBusKeyring *keyring) +{ + keyring->refcount -= 1; + + if (keyring->refcount == 0) + { + if (keyring->credentials) + _dbus_credentials_unref (keyring->credentials); + + _dbus_string_free (&keyring->filename); + _dbus_string_free (&keyring->filename_lock); + _dbus_string_free (&keyring->directory); + free_keys (keyring->keys, keyring->n_keys); + dbus_free (keyring); + } +} + +/** + * Creates a new keyring that lives in the ~/.dbus-keyrings directory + * of the given user credentials. If the credentials are #NULL or + * empty, uses those of the current process. + * + * @param username username to get keyring for, or #NULL + * @param context which keyring to get + * @param error return location for errors + * @returns the keyring or #NULL on error + */ +DBusKeyring* +_dbus_keyring_new_for_credentials (DBusCredentials *credentials, + const DBusString *context, + DBusError *error) +{ + DBusString ringdir; + DBusKeyring *keyring; + dbus_bool_t error_set; + DBusError tmp_error; + DBusCredentials *our_credentials; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + keyring = NULL; + error_set = FALSE; + our_credentials = NULL; + + if (!_dbus_string_init (&ringdir)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (credentials != NULL) + { + our_credentials = _dbus_credentials_copy (credentials); + } + else + { + our_credentials = _dbus_credentials_new_from_current_process (); + } + + if (our_credentials == NULL) + goto failed; + + if (_dbus_credentials_are_anonymous (our_credentials)) + { + if (!_dbus_credentials_add_from_current_process (our_credentials)) + goto failed; + } + + if (!_dbus_append_keyring_directory_for_credentials (&ringdir, + our_credentials)) + goto failed; + + keyring = _dbus_keyring_new (); + if (keyring == NULL) + goto failed; + + _dbus_assert (keyring->credentials == NULL); + keyring->credentials = our_credentials; + our_credentials = NULL; /* so we don't unref it again later */ + + /* should have been validated already, but paranoia check here */ + if (!_dbus_keyring_validate_context (context)) + { + error_set = TRUE; + dbus_set_error_const (error, + DBUS_ERROR_FAILED, + "Invalid context in keyring creation"); + goto failed; + } + + /* Save keyring dir in the keyring object */ + if (!_dbus_string_copy (&ringdir, 0, + &keyring->directory, 0)) + goto failed; + + /* Create keyring->filename based on keyring dir and context */ + if (!_dbus_string_copy (&keyring->directory, 0, + &keyring->filename, 0)) + goto failed; + + if (!_dbus_concat_dir_and_file (&keyring->filename, + context)) + goto failed; + + /* Create lockfile name */ + if (!_dbus_string_copy (&keyring->filename, 0, + &keyring->filename_lock, 0)) + goto failed; + + if (!_dbus_string_append (&keyring->filename_lock, ".lock")) + goto failed; + + /* Reload keyring */ + dbus_error_init (&tmp_error); + if (!_dbus_keyring_reload (keyring, FALSE, &tmp_error)) + { + _dbus_verbose ("didn't load an existing keyring: %s\n", + tmp_error.message); + dbus_error_free (&tmp_error); + } + + /* We don't fail fatally if we can't create the directory, + * but the keyring will probably always be empty + * unless someone else manages to create it + */ + dbus_error_init (&tmp_error); + if (!_dbus_create_directory (&keyring->directory, + &tmp_error)) + { + _dbus_verbose ("Creating keyring directory: %s\n", + tmp_error.message); + dbus_error_free (&tmp_error); + } + + _dbus_string_free (&ringdir); + + return keyring; + + failed: + if (!error_set) + dbus_set_error_const (error, + DBUS_ERROR_NO_MEMORY, + NULL); + if (our_credentials) + _dbus_credentials_unref (our_credentials); + if (keyring) + _dbus_keyring_unref (keyring); + _dbus_string_free (&ringdir); + return NULL; + +} + +/** + * Checks whether the context is a valid context. + * Contexts that might cause confusion when used + * in filenames are not allowed (contexts can't + * start with a dot or contain dir separators). + * + * @todo this is the most inefficient implementation + * imaginable. + * + * @param context the context + * @returns #TRUE if valid + */ +dbus_bool_t +_dbus_keyring_validate_context (const DBusString *context) +{ + if (_dbus_string_get_length (context) == 0) + { + _dbus_verbose ("context is zero-length\n"); + return FALSE; + } + + if (!_dbus_string_validate_ascii (context, 0, + _dbus_string_get_length (context))) + { + _dbus_verbose ("context not valid ascii\n"); + return FALSE; + } + + /* no directory separators */ + if (_dbus_string_find (context, 0, "/", NULL)) + { + _dbus_verbose ("context contains a slash\n"); + return FALSE; + } + + if (_dbus_string_find (context, 0, "\\", NULL)) + { + _dbus_verbose ("context contains a backslash\n"); + return FALSE; + } + + /* prevent attempts to use dotfiles or ".." or ".lock" + * all of which might allow some kind of attack + */ + if (_dbus_string_find (context, 0, ".", NULL)) + { + _dbus_verbose ("context contains a dot\n"); + return FALSE; + } + + /* no spaces/tabs, those are used for separators in the protocol */ + if (_dbus_string_find_blank (context, 0, NULL)) + { + _dbus_verbose ("context contains a blank\n"); + return FALSE; + } + + if (_dbus_string_find (context, 0, "\n", NULL)) + { + _dbus_verbose ("context contains a newline\n"); + return FALSE; + } + + if (_dbus_string_find (context, 0, "\r", NULL)) + { + _dbus_verbose ("context contains a carriage return\n"); + return FALSE; + } + + return TRUE; +} + +static DBusKey* +find_recent_key (DBusKeyring *keyring) +{ + int i; + long tv_sec, tv_usec; + + _dbus_get_current_time (&tv_sec, &tv_usec); + + i = 0; + while (i < keyring->n_keys) + { + DBusKey *key = &keyring->keys[i]; + + _dbus_verbose ("Key %d is %ld seconds old\n", + i, tv_sec - key->creation_time); + + if ((tv_sec - NEW_KEY_TIMEOUT_SECONDS) < key->creation_time) + return key; + + ++i; + } + + return NULL; +} + +/** + * Gets a recent key to use for authentication. + * If no recent key exists, creates one. Returns + * the key ID. If a key can't be written to the keyring + * file so no recent key can be created, returns -1. + * All valid keys are > 0. + * + * @param keyring the keyring + * @param error error on failure + * @returns key ID to use for auth, or -1 on failure + */ +int +_dbus_keyring_get_best_key (DBusKeyring *keyring, + DBusError *error) +{ + DBusKey *key; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + key = find_recent_key (keyring); + if (key) + return key->id; + + /* All our keys are too old, or we've never loaded the + * keyring. Create a new one. + */ + if (!_dbus_keyring_reload (keyring, TRUE, + error)) + return -1; + + key = find_recent_key (keyring); + if (key) + return key->id; + else + { + dbus_set_error_const (error, + DBUS_ERROR_FAILED, + "No recent-enough key found in keyring, and unable to create a new key"); + return -1; + } +} + +/** + * Checks whether the keyring is for the same user as the given credentials. + * + * @param keyring the keyring + * @param credentials the credentials to check + * + * @returns #TRUE if the keyring belongs to the given user + */ +dbus_bool_t +_dbus_keyring_is_for_credentials (DBusKeyring *keyring, + DBusCredentials *credentials) +{ + return _dbus_credentials_same_user (keyring->credentials, + credentials); +} + +/** + * Gets the hex-encoded secret key for the given ID. + * Returns #FALSE if not enough memory. Returns #TRUE + * but empty key on any other error such as unknown + * key ID. + * + * @param keyring the keyring + * @param key_id the key ID + * @param hex_key string to append hex-encoded key to + * @returns #TRUE if we had enough memory + */ +dbus_bool_t +_dbus_keyring_get_hex_key (DBusKeyring *keyring, + int key_id, + DBusString *hex_key) +{ + DBusKey *key; + + key = find_key_by_id (keyring->keys, + keyring->n_keys, + key_id); + if (key == NULL) + return TRUE; /* had enough memory, so TRUE */ + + return _dbus_string_hex_encode (&key->secret, 0, + hex_key, + _dbus_string_get_length (hex_key)); +} + +/** @} */ /* end of exposed API */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +dbus_bool_t +_dbus_keyring_test (void) +{ + DBusString context; + DBusKeyring *ring1; + DBusKeyring *ring2; + int id; + DBusError error; + int i; + + ring1 = NULL; + ring2 = NULL; + + /* Context validation */ + + _dbus_string_init_const (&context, "foo"); + _dbus_assert (_dbus_keyring_validate_context (&context)); + _dbus_string_init_const (&context, "org_freedesktop_blah"); + _dbus_assert (_dbus_keyring_validate_context (&context)); + + _dbus_string_init_const (&context, ""); + _dbus_assert (!_dbus_keyring_validate_context (&context)); + _dbus_string_init_const (&context, ".foo"); + _dbus_assert (!_dbus_keyring_validate_context (&context)); + _dbus_string_init_const (&context, "bar.foo"); + _dbus_assert (!_dbus_keyring_validate_context (&context)); + _dbus_string_init_const (&context, "bar/foo"); + _dbus_assert (!_dbus_keyring_validate_context (&context)); + _dbus_string_init_const (&context, "bar\\foo"); + _dbus_assert (!_dbus_keyring_validate_context (&context)); + _dbus_string_init_const (&context, "foo\xfa\xf0"); + _dbus_assert (!_dbus_keyring_validate_context (&context)); + _dbus_string_init_const (&context, "foo\x80"); + _dbus_assert (!_dbus_keyring_validate_context (&context)); + _dbus_string_init_const (&context, "foo\x7f"); + _dbus_assert (_dbus_keyring_validate_context (&context)); + _dbus_string_init_const (&context, "foo bar"); + _dbus_assert (!_dbus_keyring_validate_context (&context)); + + if (!_dbus_string_init (&context)) + _dbus_assert_not_reached ("no memory"); + if (!_dbus_string_append_byte (&context, '\0')) + _dbus_assert_not_reached ("no memory"); + _dbus_assert (!_dbus_keyring_validate_context (&context)); + _dbus_string_free (&context); + + /* Now verify that if we create a key in keyring 1, + * it is properly loaded in keyring 2 + */ + + _dbus_string_init_const (&context, "org_freedesktop_dbus_testsuite"); + dbus_error_init (&error); + ring1 = _dbus_keyring_new_for_credentials (NULL, &context, + &error); + _dbus_assert (ring1 != NULL); + _dbus_assert (error.name == NULL); + + id = _dbus_keyring_get_best_key (ring1, &error); + if (id < 0) + { + fprintf (stderr, "Could not load keyring: %s\n", error.message); + dbus_error_free (&error); + goto failure; + } + + ring2 = _dbus_keyring_new_for_credentials (NULL, &context, &error); + _dbus_assert (ring2 != NULL); + _dbus_assert (error.name == NULL); + + if (ring1->n_keys != ring2->n_keys) + { + fprintf (stderr, "Different number of keys in keyrings\n"); + goto failure; + } + + /* We guarantee we load and save keeping keys in a fixed + * order + */ + i = 0; + while (i < ring1->n_keys) + { + if (ring1->keys[i].id != ring2->keys[i].id) + { + fprintf (stderr, "Keyring 1 has first key ID %d and keyring 2 has %d\n", + ring1->keys[i].id, ring2->keys[i].id); + goto failure; + } + + if (ring1->keys[i].creation_time != ring2->keys[i].creation_time) + { + fprintf (stderr, "Keyring 1 has first key time %ld and keyring 2 has %ld\n", + ring1->keys[i].creation_time, ring2->keys[i].creation_time); + goto failure; + } + + if (!_dbus_string_equal (&ring1->keys[i].secret, + &ring2->keys[i].secret)) + { + fprintf (stderr, "Keyrings 1 and 2 have different secrets for same ID/timestamp\n"); + goto failure; + } + + ++i; + } + + printf (" %d keys in test\n", ring1->n_keys); + + /* Test ref/unref */ + _dbus_keyring_ref (ring1); + _dbus_keyring_ref (ring2); + _dbus_keyring_unref (ring1); + _dbus_keyring_unref (ring2); + + + /* really unref */ + _dbus_keyring_unref (ring1); + _dbus_keyring_unref (ring2); + + return TRUE; + + failure: + if (ring1) + _dbus_keyring_unref (ring1); + if (ring2) + _dbus_keyring_unref (ring2); + + return FALSE; +} + +#endif /* DBUS_BUILD_TESTS */ + diff --git a/dbus/dbus-keyring.h b/dbus/dbus-keyring.h new file mode 100644 index 00000000..200e31bc --- /dev/null +++ b/dbus/dbus-keyring.h @@ -0,0 +1,52 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-keyring.h Store secret cookies in your homedir + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_KEYRING_H +#define DBUS_KEYRING_H + +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +typedef struct DBusKeyring DBusKeyring; + +DBusKeyring* _dbus_keyring_new_for_credentials (DBusCredentials *credentials, + const DBusString *context, + DBusError *error); +DBusKeyring* _dbus_keyring_ref (DBusKeyring *keyring); +void _dbus_keyring_unref (DBusKeyring *keyring); +dbus_bool_t _dbus_keyring_validate_context (const DBusString *context); +int _dbus_keyring_get_best_key (DBusKeyring *keyring, + DBusError *error); +dbus_bool_t _dbus_keyring_is_for_credentials (DBusKeyring *keyring, + DBusCredentials *credentials); +dbus_bool_t _dbus_keyring_get_hex_key (DBusKeyring *keyring, + int key_id, + DBusString *hex_key); + + +DBUS_END_DECLS + +#endif /* DBUS_KEYRING_H */ diff --git a/dbus/dbus-list.c b/dbus/dbus-list.c new file mode 100644 index 00000000..e075ffe1 --- /dev/null +++ b/dbus/dbus-list.c @@ -0,0 +1,1405 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-list.c Generic linked list utility (internal to D-Bus implementation) + * + * Copyright (C) 2002 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-list.h" +#include "dbus-mempool.h" +#include "dbus-threads-internal.h" + +/** + * @defgroup DBusList Linked list + * @ingroup DBusInternals + * @brief DBusList data structure + * + * Types and functions related to DBusList. + */ + +static DBusMemPool *list_pool; +_DBUS_DEFINE_GLOBAL_LOCK (list); + +/** + * @defgroup DBusListInternals Linked list implementation details + * @ingroup DBusInternals + * @brief DBusList implementation details + * + * The guts of DBusList. + * + * @{ + */ + +/* the mem pool is probably a speed hit, with the thread + * lock, though it does still save memory - unknown. + */ +static DBusList* +alloc_link (void *data) +{ + DBusList *link; + + _DBUS_LOCK (list); + + if (list_pool == NULL) + { + list_pool = _dbus_mem_pool_new (sizeof (DBusList), TRUE); + + if (list_pool == NULL) + { + _DBUS_UNLOCK (list); + return NULL; + } + + link = _dbus_mem_pool_alloc (list_pool); + if (link == NULL) + { + _dbus_mem_pool_free (list_pool); + list_pool = NULL; + _DBUS_UNLOCK (list); + return NULL; + } + } + else + { + link = _dbus_mem_pool_alloc (list_pool); + } + + if (link) + link->data = data; + + _DBUS_UNLOCK (list); + + return link; +} + +static void +free_link (DBusList *link) +{ + _DBUS_LOCK (list); + if (_dbus_mem_pool_dealloc (list_pool, link)) + { + _dbus_mem_pool_free (list_pool); + list_pool = NULL; + } + + _DBUS_UNLOCK (list); +} + +static void +link_before (DBusList **list, + DBusList *before_this_link, + DBusList *link) +{ + if (*list == NULL) + { + link->prev = link; + link->next = link; + *list = link; + } + else + { + link->next = before_this_link; + link->prev = before_this_link->prev; + before_this_link->prev = link; + link->prev->next = link; + + if (before_this_link == *list) + *list = link; + } +} + +static void +link_after (DBusList **list, + DBusList *after_this_link, + DBusList *link) +{ + if (*list == NULL) + { + link->prev = link; + link->next = link; + *list = link; + } + else + { + link->prev = after_this_link; + link->next = after_this_link->next; + after_this_link->next = link; + link->next->prev = link; + } +} + +/** @} */ + +/** + * @addtogroup DBusList + * @{ + */ + +/** + * @struct DBusList + * + * A node in a linked list. + * + * DBusList is a circular list; that is, the tail of the list + * points back to the head of the list. The empty list is + * represented by a #NULL pointer. + */ + +/** + * @def _dbus_list_get_next_link + * + * Gets the next link in the list, or #NULL if + * there are no more links. Used for iteration. + * + * @code + * DBusList *link; + * link = _dbus_list_get_first_link (&list); + * while (link != NULL) + * { + * printf ("value is %p\n", link->data); + * link = _dbus_list_get_next_link (&link); + * } + * @endcode + * + * @param list address of the list head. + * @param link current link. + * @returns the next link, or %NULL if none. + * + */ + +/** + * @def _dbus_list_get_prev_link + * + * Gets the previous link in the list, or #NULL if + * there are no more links. Used for iteration. + * + * @code + * DBusList *link; + * link = _dbus_list_get_last_link (&list); + * while (link != NULL) + * { + * printf ("value is %p\n", link->data); + * link = _dbus_list_get_prev_link (&link); + * } + * @endcode + * + * @param list address of the list head. + * @param link current link. + * @returns the previous link, or %NULL if none. + * + */ + +/** + * Allocates a linked list node. Useful for preallocating + * nodes and using _dbus_list_append_link() to avoid + * allocations. + * + * @param data the value to store in the link. + * @returns a newly allocated link. + */ +DBusList* +_dbus_list_alloc_link (void *data) +{ + return alloc_link (data); +} + +/** + * Frees a linked list node allocated with _dbus_list_alloc_link. + * Does not free the data in the node. + * + * @param link the list node + */ +void +_dbus_list_free_link (DBusList *link) +{ + free_link (link); +} + + +/** + * Appends a value to the list. May return #FALSE + * if insufficient memory exists to add a list link. + * This is a constant-time operation. + * + * @param list address of the list head. + * @param data the value to append. + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_list_append (DBusList **list, + void *data) +{ + if (!_dbus_list_prepend (list, data)) + return FALSE; + + /* Now cycle the list forward one so the prepended node is the tail */ + *list = (*list)->next; + + return TRUE; +} + +/** + * Prepends a value to the list. May return #FALSE + * if insufficient memory exists to add a list link. + * This is a constant-time operation. + * + * @param list address of the list head. + * @param data the value to prepend. + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_list_prepend (DBusList **list, + void *data) +{ + DBusList *link; + + link = alloc_link (data); + if (link == NULL) + return FALSE; + + link_before (list, *list, link); + + return TRUE; +} + +/** + * Appends a link to the list. + * Cannot fail due to out of memory. + * This is a constant-time operation. + * + * @param list address of the list head. + * @param link the link to append. + */ +void +_dbus_list_append_link (DBusList **list, + DBusList *link) +{ + _dbus_list_prepend_link (list, link); + + /* Now cycle the list forward one so the prepended node is the tail */ + *list = (*list)->next; +} + +/** + * Prepends a link to the list. + * Cannot fail due to out of memory. + * This is a constant-time operation. + * + * @param list address of the list head. + * @param link the link to prepend. + */ +void +_dbus_list_prepend_link (DBusList **list, + DBusList *link) +{ + link_before (list, *list, link); +} + +#ifdef DBUS_BUILD_TESTS +/** + * Inserts data into the list before the given existing link. + * + * @param list the list to modify + * @param before_this_link existing link to insert before, or #NULL to append + * @param data the value to insert + * @returns #TRUE on success, #FALSE if memory allocation fails + */ +dbus_bool_t +_dbus_list_insert_before (DBusList **list, + DBusList *before_this_link, + void *data) +{ + DBusList *link; + + if (before_this_link == NULL) + return _dbus_list_append (list, data); + else + { + link = alloc_link (data); + if (link == NULL) + return FALSE; + + link_before (list, before_this_link, link); + } + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Inserts data into the list after the given existing link. + * + * @param list the list to modify + * @param after_this_link existing link to insert after, or #NULL to prepend + * @param data the value to insert + * @returns #TRUE on success, #FALSE if memory allocation fails + */ +dbus_bool_t +_dbus_list_insert_after (DBusList **list, + DBusList *after_this_link, + void *data) +{ + DBusList *link; + + if (after_this_link == NULL) + return _dbus_list_prepend (list, data); + else + { + link = alloc_link (data); + if (link == NULL) + return FALSE; + + link_after (list, after_this_link, link); + } + + return TRUE; +} + +/** + * Inserts a link into the list before the given existing link. + * + * @param list the list to modify + * @param before_this_link existing link to insert before, or #NULL to append + * @param link the link to insert + */ +void +_dbus_list_insert_before_link (DBusList **list, + DBusList *before_this_link, + DBusList *link) +{ + if (before_this_link == NULL) + _dbus_list_append_link (list, link); + else + link_before (list, before_this_link, link); +} + +/** + * Inserts a link into the list after the given existing link. + * + * @param list the list to modify + * @param after_this_link existing link to insert after, or #NULL to prepend + * @param link the link to insert + */ +void +_dbus_list_insert_after_link (DBusList **list, + DBusList *after_this_link, + DBusList *link) +{ + if (after_this_link == NULL) + _dbus_list_prepend_link (list, link); + else + link_after (list, after_this_link, link); +} + +/** + * Removes a value from the list. Only removes the + * first value equal to the given data pointer, + * even if multiple values exist which match. + * This is a linear-time operation. + * + * @param list address of the list head. + * @param data the value to remove. + * @returns #TRUE if a value was found to remove. + */ +dbus_bool_t +_dbus_list_remove (DBusList **list, + void *data) +{ + DBusList *link; + + link = *list; + while (link != NULL) + { + if (link->data == data) + { + _dbus_list_remove_link (list, link); + return TRUE; + } + + link = _dbus_list_get_next_link (list, link); + } + + return FALSE; +} + +/** + * Removes a value from the list. Only removes the + * last value equal to the given data pointer, + * even if multiple values exist which match. + * This is a linear-time operation. + * + * @param list address of the list head. + * @param data the value to remove. + * @returns #TRUE if a value was found to remove. + */ +dbus_bool_t +_dbus_list_remove_last (DBusList **list, + void *data) +{ + DBusList *link; + + link = _dbus_list_find_last (list, data); + if (link) + { + _dbus_list_remove_link (list, link); + return TRUE; + } + else + return FALSE; +} + +/** + * Finds a value in the list. Returns the last link + * with value equal to the given data pointer. + * This is a linear-time operation. + * Returns #NULL if no value found that matches. + * + * @param list address of the list head. + * @param data the value to find. + * @returns the link if found + */ +DBusList* +_dbus_list_find_last (DBusList **list, + void *data) +{ + DBusList *link; + + link = _dbus_list_get_last_link (list); + + while (link != NULL) + { + if (link->data == data) + return link; + + link = _dbus_list_get_prev_link (list, link); + } + + return NULL; +} + +/** + * Removes the given link from the list, but doesn't + * free it. _dbus_list_remove_link() both removes the + * link and also frees it. + * + * @param list the list + * @param link the link in the list + */ +void +_dbus_list_unlink (DBusList **list, + DBusList *link) +{ + if (link->next == link) + { + /* one-element list */ + *list = NULL; + } + else + { + link->prev->next = link->next; + link->next->prev = link->prev; + + if (*list == link) + *list = link->next; + } + + link->next = NULL; + link->prev = NULL; +} + +/** + * Removes a link from the list. This is a constant-time operation. + * + * @param list address of the list head. + * @param link the list link to remove. + */ +void +_dbus_list_remove_link (DBusList **list, + DBusList *link) +{ + _dbus_list_unlink (list, link); + free_link (link); +} + +/** + * Frees all links in the list and sets the list head to #NULL. Does + * not free the data in each link, for obvious reasons. This is a + * linear-time operation. + * + * @param list address of the list head. + */ +void +_dbus_list_clear (DBusList **list) +{ + DBusList *link; + + link = *list; + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (list, link); + + free_link (link); + + link = next; + } + + *list = NULL; +} + +/** + * Gets the first link in the list. + * This is a constant-time operation. + * + * @param list address of the list head. + * @returns the first link, or #NULL for an empty list. + */ +DBusList* +_dbus_list_get_first_link (DBusList **list) +{ + return *list; +} + +/** + * Gets the last link in the list. + * This is a constant-time operation. + * + * @param list address of the list head. + * @returns the last link, or #NULL for an empty list. + */ +DBusList* +_dbus_list_get_last_link (DBusList **list) +{ + if (*list == NULL) + return NULL; + else + return (*list)->prev; +} + +/** + * Gets the last data in the list. + * This is a constant-time operation. + * + * @param list address of the list head. + * @returns the last data in the list, or #NULL for an empty list. + */ +void* +_dbus_list_get_last (DBusList **list) +{ + if (*list == NULL) + return NULL; + else + return (*list)->prev->data; +} + +/** + * Gets the first data in the list. + * This is a constant-time operation. + * + * @param list address of the list head. + * @returns the first data in the list, or #NULL for an empty list. + */ +void* +_dbus_list_get_first (DBusList **list) +{ + if (*list == NULL) + return NULL; + else + return (*list)->data; +} + +/** + * Removes the first link in the list and returns it. This is a + * constant-time operation. + * + * @param list address of the list head. + * @returns the first link in the list, or #NULL for an empty list. + */ +DBusList* +_dbus_list_pop_first_link (DBusList **list) +{ + DBusList *link; + + link = _dbus_list_get_first_link (list); + if (link == NULL) + return NULL; + + _dbus_list_unlink (list, link); + + return link; +} + +/** + * Removes the first value in the list and returns it. This is a + * constant-time operation. + * + * @param list address of the list head. + * @returns the first data in the list, or #NULL for an empty list. + */ +void* +_dbus_list_pop_first (DBusList **list) +{ + DBusList *link; + void *data; + + link = _dbus_list_get_first_link (list); + if (link == NULL) + return NULL; + + data = link->data; + _dbus_list_remove_link (list, link); + + return data; +} + +/** + * Removes the last value in the list and returns it. This is a + * constant-time operation. + * + * @param list address of the list head. + * @returns the last data in the list, or #NULL for an empty list. + */ +void* +_dbus_list_pop_last (DBusList **list) +{ + DBusList *link; + void *data; + + link = _dbus_list_get_last_link (list); + if (link == NULL) + return NULL; + + data = link->data; + _dbus_list_remove_link (list, link); + + return data; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Removes the last link in the list and returns it. This is a + * constant-time operation. + * + * @param list address of the list head. + * @returns the last link in the list, or #NULL for an empty list. + */ +DBusList* +_dbus_list_pop_last_link (DBusList **list) +{ + DBusList *link; + + link = _dbus_list_get_last_link (list); + if (link == NULL) + return NULL; + + _dbus_list_unlink (list, link); + + return link; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Copies a list. This is a linear-time operation. If there isn't + * enough memory to copy the entire list, the destination list will be + * set to #NULL. + * + * @param list address of the head of the list to copy. + * @param dest address where the copied list should be placed. + * @returns #TRUE on success, #FALSE if not enough memory. + */ +dbus_bool_t +_dbus_list_copy (DBusList **list, + DBusList **dest) +{ + DBusList *link; + + _dbus_assert (list != dest); + + *dest = NULL; + + link = *list; + while (link != NULL) + { + if (!_dbus_list_append (dest, link->data)) + { + /* free what we have so far */ + _dbus_list_clear (dest); + return FALSE; + } + + link = _dbus_list_get_next_link (list, link); + } + + return TRUE; +} + +/** + * Gets the length of a list. This is a linear-time + * operation. + * + * @param list address of the head of the list + * @returns number of elements in the list. + */ +int +_dbus_list_get_length (DBusList **list) +{ + DBusList *link; + int length; + + length = 0; + + link = *list; + while (link != NULL) + { + ++length; + + link = _dbus_list_get_next_link (list, link); + } + + return length; +} + +/** + * Calls the given function for each element in the list. The + * function is passed the list element as its first argument, and the + * given data as its second argument. + * + * @param list address of the head of the list. + * @param function function to call for each element. + * @param data extra data for the function. + * + */ +void +_dbus_list_foreach (DBusList **list, + DBusForeachFunction function, + void *data) +{ + DBusList *link; + + link = *list; + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (list, link); + + (* function) (link->data, data); + + link = next; + } +} + +/** + * Check whether length is exactly one. + * + * @param list the list + * @returns #TRUE if length is exactly one + */ +dbus_bool_t +_dbus_list_length_is_one (DBusList **list) +{ + return (*list != NULL && + (*list)->next == *list); +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +static void +verify_list (DBusList **list) +{ + DBusList *link; + int length; + + link = *list; + + if (link == NULL) + return; + + if (link->next == link) + { + _dbus_assert (link->prev == link); + _dbus_assert (*list == link); + return; + } + + length = 0; + do + { + length += 1; + _dbus_assert (link->prev->next == link); + _dbus_assert (link->next->prev == link); + link = link->next; + } + while (link != *list); + + _dbus_assert (length == _dbus_list_get_length (list)); + + if (length == 1) + _dbus_assert (_dbus_list_length_is_one (list)); + else + _dbus_assert (!_dbus_list_length_is_one (list)); +} + +static dbus_bool_t +is_ascending_sequence (DBusList **list) +{ + DBusList *link; + int prev; + + prev = _DBUS_INT_MIN; + + link = _dbus_list_get_first_link (list); + while (link != NULL) + { + int v = _DBUS_POINTER_TO_INT (link->data); + + if (v <= prev) + return FALSE; + + prev = v; + + link = _dbus_list_get_next_link (list, link); + } + + return TRUE; +} + +static dbus_bool_t +is_descending_sequence (DBusList **list) +{ + DBusList *link; + int prev; + + prev = _DBUS_INT_MAX; + + link = _dbus_list_get_first_link (list); + while (link != NULL) + { + int v = _DBUS_POINTER_TO_INT (link->data); + + if (v >= prev) + return FALSE; + + prev = v; + + link = _dbus_list_get_next_link (list, link); + } + + return TRUE; +} + +static dbus_bool_t +all_even_values (DBusList **list) +{ + DBusList *link; + + link = _dbus_list_get_first_link (list); + while (link != NULL) + { + int v = _DBUS_POINTER_TO_INT (link->data); + + if ((v % 2) != 0) + return FALSE; + + link = _dbus_list_get_next_link (list, link); + } + + return TRUE; +} + +static dbus_bool_t +all_odd_values (DBusList **list) +{ + DBusList *link; + + link = _dbus_list_get_first_link (list); + while (link != NULL) + { + int v = _DBUS_POINTER_TO_INT (link->data); + + if ((v % 2) == 0) + return FALSE; + + link = _dbus_list_get_next_link (list, link); + } + + return TRUE; +} + +static dbus_bool_t +lists_equal (DBusList **list1, + DBusList **list2) +{ + DBusList *link1; + DBusList *link2; + + link1 = _dbus_list_get_first_link (list1); + link2 = _dbus_list_get_first_link (list2); + while (link1 && link2) + { + if (link1->data != link2->data) + return FALSE; + + link1 = _dbus_list_get_next_link (list1, link1); + link2 = _dbus_list_get_next_link (list2, link2); + } + + if (link1 || link2) + return FALSE; + + return TRUE; +} + +/** + * @ingroup DBusListInternals + * Unit test for DBusList + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_list_test (void) +{ + DBusList *list1; + DBusList *list2; + DBusList *link1; + DBusList *link2; + DBusList *copy1; + DBusList *copy2; + int i; + + list1 = NULL; + list2 = NULL; + + /* Test append and prepend */ + + i = 0; + while (i < 10) + { + if (!_dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i))) + _dbus_assert_not_reached ("could not allocate for append"); + + if (!_dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i))) + _dbus_assert_not_reached ("count not allocate for prepend"); + ++i; + + verify_list (&list1); + verify_list (&list2); + + _dbus_assert (_dbus_list_get_length (&list1) == i); + _dbus_assert (_dbus_list_get_length (&list2) == i); + } + + _dbus_assert (is_ascending_sequence (&list1)); + _dbus_assert (is_descending_sequence (&list2)); + + /* Test list clear */ + _dbus_list_clear (&list1); + _dbus_list_clear (&list2); + + verify_list (&list1); + verify_list (&list2); + + /* Test get_first, get_last, pop_first, pop_last */ + + i = 0; + while (i < 10) + { + _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); + _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); + ++i; + } + + --i; + while (i >= 0) + { + void *got_data1; + void *got_data2; + + void *data1; + void *data2; + + got_data1 = _dbus_list_get_last (&list1); + got_data2 = _dbus_list_get_first (&list2); + + data1 = _dbus_list_pop_last (&list1); + data2 = _dbus_list_pop_first (&list2); + + _dbus_assert (got_data1 == data1); + _dbus_assert (got_data2 == data2); + + _dbus_assert (_DBUS_POINTER_TO_INT (data1) == i); + _dbus_assert (_DBUS_POINTER_TO_INT (data2) == i); + + verify_list (&list1); + verify_list (&list2); + + _dbus_assert (is_ascending_sequence (&list1)); + _dbus_assert (is_descending_sequence (&list2)); + + --i; + } + + _dbus_assert (list1 == NULL); + _dbus_assert (list2 == NULL); + + /* Test get_first_link, get_last_link, pop_first_link, pop_last_link */ + + i = 0; + while (i < 10) + { + _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); + _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); + ++i; + } + + --i; + while (i >= 0) + { + DBusList *got_link1; + DBusList *got_link2; + + DBusList *link1; + DBusList *link2; + + void *data1; + void *data2; + + got_link1 = _dbus_list_get_last_link (&list1); + got_link2 = _dbus_list_get_first_link (&list2); + + link1 = _dbus_list_pop_last_link (&list1); + link2 = _dbus_list_pop_first_link (&list2); + + _dbus_assert (got_link1 == link1); + _dbus_assert (got_link2 == link2); + + data1 = link1->data; + data2 = link2->data; + + _dbus_list_free_link (link1); + _dbus_list_free_link (link2); + + _dbus_assert (_DBUS_POINTER_TO_INT (data1) == i); + _dbus_assert (_DBUS_POINTER_TO_INT (data2) == i); + + verify_list (&list1); + verify_list (&list2); + + _dbus_assert (is_ascending_sequence (&list1)); + _dbus_assert (is_descending_sequence (&list2)); + + --i; + } + + _dbus_assert (list1 == NULL); + _dbus_assert (list2 == NULL); + + /* Test iteration */ + + i = 0; + while (i < 10) + { + _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); + _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); + ++i; + + verify_list (&list1); + verify_list (&list2); + + _dbus_assert (_dbus_list_get_length (&list1) == i); + _dbus_assert (_dbus_list_get_length (&list2) == i); + } + + _dbus_assert (is_ascending_sequence (&list1)); + _dbus_assert (is_descending_sequence (&list2)); + + --i; + link2 = _dbus_list_get_first_link (&list2); + while (link2 != NULL) + { + verify_list (&link2); /* pretend this link is the head */ + + _dbus_assert (_DBUS_POINTER_TO_INT (link2->data) == i); + + link2 = _dbus_list_get_next_link (&list2, link2); + --i; + } + + i = 0; + link1 = _dbus_list_get_first_link (&list1); + while (link1 != NULL) + { + verify_list (&link1); /* pretend this link is the head */ + + _dbus_assert (_DBUS_POINTER_TO_INT (link1->data) == i); + + link1 = _dbus_list_get_next_link (&list1, link1); + ++i; + } + + --i; + link1 = _dbus_list_get_last_link (&list1); + while (link1 != NULL) + { + verify_list (&link1); /* pretend this link is the head */ + + _dbus_assert (_DBUS_POINTER_TO_INT (link1->data) == i); + + link1 = _dbus_list_get_prev_link (&list1, link1); + --i; + } + + _dbus_list_clear (&list1); + _dbus_list_clear (&list2); + + /* Test remove */ + + i = 0; + while (i < 10) + { + _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); + _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); + ++i; + } + + --i; + while (i >= 0) + { + if ((i % 2) == 0) + { + if (!_dbus_list_remove (&list1, _DBUS_INT_TO_POINTER (i))) + _dbus_assert_not_reached ("element should have been in list"); + if (!_dbus_list_remove (&list2, _DBUS_INT_TO_POINTER (i))) + _dbus_assert_not_reached ("element should have been in list"); + + verify_list (&list1); + verify_list (&list2); + } + --i; + } + + _dbus_assert (all_odd_values (&list1)); + _dbus_assert (all_odd_values (&list2)); + + _dbus_list_clear (&list1); + _dbus_list_clear (&list2); + + /* test removing the other half of the elements */ + + i = 0; + while (i < 10) + { + _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); + _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); + ++i; + } + + --i; + while (i >= 0) + { + if ((i % 2) != 0) + { + if (!_dbus_list_remove (&list1, _DBUS_INT_TO_POINTER (i))) + _dbus_assert_not_reached ("element should have been in list"); + if (!_dbus_list_remove (&list2, _DBUS_INT_TO_POINTER (i))) + _dbus_assert_not_reached ("element should have been in list"); + + verify_list (&list1); + verify_list (&list2); + } + --i; + } + + _dbus_assert (all_even_values (&list1)); + _dbus_assert (all_even_values (&list2)); + + /* clear list using remove_link */ + while (list1 != NULL) + { + _dbus_list_remove_link (&list1, list1); + verify_list (&list1); + } + while (list2 != NULL) + { + _dbus_list_remove_link (&list2, list2); + verify_list (&list2); + } + + /* Test remove link more generally */ + i = 0; + while (i < 10) + { + _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); + _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); + ++i; + } + + --i; + link2 = _dbus_list_get_first_link (&list2); + while (link2 != NULL) + { + DBusList *next = _dbus_list_get_next_link (&list2, link2); + + _dbus_assert (_DBUS_POINTER_TO_INT (link2->data) == i); + + if ((i % 2) == 0) + _dbus_list_remove_link (&list2, link2); + + verify_list (&list2); + + link2 = next; + --i; + } + + _dbus_assert (all_odd_values (&list2)); + _dbus_list_clear (&list2); + + i = 0; + link1 = _dbus_list_get_first_link (&list1); + while (link1 != NULL) + { + DBusList *next = _dbus_list_get_next_link (&list1, link1); + + _dbus_assert (_DBUS_POINTER_TO_INT (link1->data) == i); + + if ((i % 2) != 0) + _dbus_list_remove_link (&list1, link1); + + verify_list (&list1); + + link1 = next; + ++i; + } + + _dbus_assert (all_even_values (&list1)); + _dbus_list_clear (&list1); + + /* Test copying a list */ + i = 0; + while (i < 10) + { + _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (i)); + _dbus_list_prepend (&list2, _DBUS_INT_TO_POINTER (i)); + ++i; + } + + /* bad pointers, because they are allowed in the copy dest */ + copy1 = _DBUS_INT_TO_POINTER (0x342234); + copy2 = _DBUS_INT_TO_POINTER (23); + + _dbus_list_copy (&list1, ©1); + verify_list (&list1); + verify_list (©1); + _dbus_assert (lists_equal (&list1, ©1)); + + _dbus_list_copy (&list2, ©2); + verify_list (&list2); + verify_list (©2); + _dbus_assert (lists_equal (&list2, ©2)); + + /* Now test copying empty lists */ + _dbus_list_clear (&list1); + _dbus_list_clear (&list2); + _dbus_list_clear (©1); + _dbus_list_clear (©2); + + /* bad pointers, because they are allowed in the copy dest */ + copy1 = _DBUS_INT_TO_POINTER (0x342234); + copy2 = _DBUS_INT_TO_POINTER (23); + + _dbus_list_copy (&list1, ©1); + verify_list (&list1); + verify_list (©1); + _dbus_assert (lists_equal (&list1, ©1)); + + _dbus_list_copy (&list2, ©2); + verify_list (&list2); + verify_list (©2); + _dbus_assert (lists_equal (&list2, ©2)); + + _dbus_list_clear (&list1); + _dbus_list_clear (&list2); + + /* insert_before on empty list */ + _dbus_list_insert_before (&list1, NULL, + _DBUS_INT_TO_POINTER (0)); + verify_list (&list1); + + /* inserting before first element */ + _dbus_list_insert_before (&list1, list1, + _DBUS_INT_TO_POINTER (2)); + verify_list (&list1); + _dbus_assert (is_descending_sequence (&list1)); + + /* inserting in the middle */ + _dbus_list_insert_before (&list1, list1->next, + _DBUS_INT_TO_POINTER (1)); + verify_list (&list1); + _dbus_assert (is_descending_sequence (&list1)); + + /* using insert_before to append */ + _dbus_list_insert_before (&list1, NULL, + _DBUS_INT_TO_POINTER (-1)); + verify_list (&list1); + _dbus_assert (is_descending_sequence (&list1)); + + _dbus_list_clear (&list1); + + /* insert_after on empty list */ + _dbus_list_insert_after (&list1, NULL, + _DBUS_INT_TO_POINTER (0)); + verify_list (&list1); + + /* inserting after first element */ + _dbus_list_insert_after (&list1, list1, + _DBUS_INT_TO_POINTER (1)); + verify_list (&list1); + _dbus_assert (is_ascending_sequence (&list1)); + + /* inserting at the end */ + _dbus_list_insert_after (&list1, list1->next, + _DBUS_INT_TO_POINTER (2)); + verify_list (&list1); + _dbus_assert (is_ascending_sequence (&list1)); + + /* using insert_after to prepend */ + _dbus_list_insert_after (&list1, NULL, + _DBUS_INT_TO_POINTER (-1)); + verify_list (&list1); + _dbus_assert (is_ascending_sequence (&list1)); + + _dbus_list_clear (&list1); + + /* using remove_last */ + _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (2)); + _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (1)); + _dbus_list_append (&list1, _DBUS_INT_TO_POINTER (3)); + + _dbus_list_remove_last (&list1, _DBUS_INT_TO_POINTER (2)); + + verify_list (&list1); + _dbus_assert (is_ascending_sequence (&list1)); + + _dbus_list_clear (&list1); + + return TRUE; +} + +#endif diff --git a/dbus/dbus-list.h b/dbus/dbus-list.h new file mode 100644 index 00000000..663ad257 --- /dev/null +++ b/dbus/dbus-list.h @@ -0,0 +1,98 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-list.h Generic linked list utility (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_LIST_H +#define DBUS_LIST_H + +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +struct DBusList +{ + DBusList *prev; /**< Previous list node. */ + DBusList *next; /**< Next list node. */ + void *data; /**< Data stored at this element. */ +}; +dbus_bool_t _dbus_list_append (DBusList **list, + void *data); +dbus_bool_t _dbus_list_prepend (DBusList **list, + void *data); +dbus_bool_t _dbus_list_insert_before (DBusList **list, + DBusList *before_this_link, + void *data); +dbus_bool_t _dbus_list_insert_after (DBusList **list, + DBusList *after_this_link, + void *data); +void _dbus_list_insert_before_link (DBusList **list, + DBusList *before_this_link, + DBusList *link); +void _dbus_list_insert_after_link (DBusList **list, + DBusList *after_this_link, + DBusList *link); +dbus_bool_t _dbus_list_remove (DBusList **list, + void *data); +dbus_bool_t _dbus_list_remove_last (DBusList **list, + void *data); +void _dbus_list_remove_link (DBusList **list, + DBusList *link); +DBusList* _dbus_list_find_last (DBusList **list, + void *data); +void _dbus_list_clear (DBusList **list); +DBusList* _dbus_list_get_first_link (DBusList **list); +DBusList* _dbus_list_get_last_link (DBusList **list); +void* _dbus_list_get_last (DBusList **list); +void* _dbus_list_get_first (DBusList **list); +void* _dbus_list_pop_first (DBusList **list); +void* _dbus_list_pop_last (DBusList **list); +DBusList* _dbus_list_pop_first_link (DBusList **list); +DBusList* _dbus_list_pop_last_link (DBusList **list); +dbus_bool_t _dbus_list_copy (DBusList **list, + DBusList **dest); +int _dbus_list_get_length (DBusList **list); +DBusList* _dbus_list_alloc_link (void *data); +void _dbus_list_free_link (DBusList *link); +void _dbus_list_unlink (DBusList **list, + DBusList *link); +void _dbus_list_append_link (DBusList **list, + DBusList *link); +void _dbus_list_prepend_link (DBusList **list, + DBusList *link); +dbus_bool_t _dbus_list_length_is_one (DBusList **list); + + + + +void _dbus_list_foreach (DBusList **list, + DBusForeachFunction function, + void *data); + +#define _dbus_list_get_next_link(list, link) ((link)->next == *(list) ? NULL : (link)->next) +#define _dbus_list_get_prev_link(list, link) ((link) == *(list) ? NULL : (link)->prev) + +DBUS_END_DECLS + +#endif /* DBUS_LIST_H */ diff --git a/dbus/dbus-macros.h b/dbus/dbus-macros.h new file mode 100644 index 00000000..497dd450 --- /dev/null +++ b/dbus/dbus-macros.h @@ -0,0 +1,137 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-macros.h generic macros + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_MACROS_H +#define DBUS_MACROS_H + +#ifdef __cplusplus +# define DBUS_BEGIN_DECLS extern "C" { +# define DBUS_END_DECLS } +#else +# define DBUS_BEGIN_DECLS +# define DBUS_END_DECLS +#endif + +#ifndef TRUE +# define TRUE 1 +#endif +#ifndef FALSE +# define FALSE 0 +#endif + +#ifndef NULL +# ifdef __cplusplus +# define NULL (0L) +# else /* !__cplusplus */ +# define NULL ((void*) 0) +# endif /* !__cplusplus */ +#endif + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +# define DBUS_DEPRECATED __attribute__ ((__deprecated__)) +#elif defined(_MSC_VER) && (_MSC_VER >= 1300) +# define DBUS_DEPRECATED __declspec(deprecated) +#else +# define DBUS_DEPRECATED +#endif + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) +# define _DBUS_GNUC_EXTENSION __extension__ +#else +# define _DBUS_GNUC_EXTENSION +#endif + +/* Normally docs are in .c files, but there isn't a .c file for this. */ +/** + * @defgroup DBusMacros Utility macros + * @ingroup DBus + * @brief #TRUE, #FALSE, #NULL, and so on + * + * Utility macros. + * + * @{ + */ + +/** + * @def DBUS_BEGIN_DECLS + * + * Macro used prior to declaring functions in the D-Bus header + * files. Expands to "extern "C"" when using a C++ compiler, + * and expands to nothing when using a C compiler. + * + * Please don't use this in your own code, consider it + * D-Bus internal. + */ +/** + * @def DBUS_END_DECLS + * + * Macro used after declaring functions in the D-Bus header + * files. Expands to "}" when using a C++ compiler, + * and expands to nothing when using a C compiler. + * + * Please don't use this in your own code, consider it + * D-Bus internal. + */ +/** + * @def TRUE + * + * Expands to "1" + */ +/** + * @def FALSE + * + * Expands to "0" + */ +/** + * @def NULL + * + * A null pointer, defined appropriately for C or C++. + */ +/** + * @def DBUS_DEPRECATED + * + * Tells the compiler to warn about a function or type if it's used. + * Code marked in this way should also be enclosed in + * @code + * #ifndef DBUS_DISABLE_DEPRECATED + * deprecated stuff here + * #endif + * @endcode + * + * Please don't use this in your own code, consider it + * D-Bus internal. + */ +/** + * @def _DBUS_GNUC_EXTENSION + * + * Tells gcc not to warn about extensions to the C standard in the + * following expression, even if compiling with -pedantic. Do not use + * this macro in your own code; please consider it to be internal to libdbus. + */ + +/** @} */ + +#endif /* DBUS_MACROS_H */ diff --git a/dbus/dbus-mainloop.c b/dbus/dbus-mainloop.c new file mode 100644 index 00000000..a3833588 --- /dev/null +++ b/dbus/dbus-mainloop.c @@ -0,0 +1,908 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-mainloop.c Main loop utility + * + * Copyright (C) 2003, 2004 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-mainloop.h" + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#include +#include + +#define MAINLOOP_SPEW 0 + +#if MAINLOOP_SPEW +#ifdef DBUS_ENABLE_VERBOSE_MODE +static const char* +watch_flags_to_string (int flags) +{ + const char *watch_type; + + if ((flags & DBUS_WATCH_READABLE) && + (flags & DBUS_WATCH_WRITABLE)) + watch_type = "readwrite"; + else if (flags & DBUS_WATCH_READABLE) + watch_type = "read"; + else if (flags & DBUS_WATCH_WRITABLE) + watch_type = "write"; + else + watch_type = "not read or write"; + return watch_type; +} +#endif /* DBUS_ENABLE_VERBOSE_MODE */ +#endif /* MAINLOOP_SPEW */ + +struct DBusLoop +{ + int refcount; + DBusList *callbacks; + int callback_list_serial; + int watch_count; + int timeout_count; + int depth; /**< number of recursive runs */ + DBusList *need_dispatch; +}; + +typedef enum +{ + CALLBACK_WATCH, + CALLBACK_TIMEOUT +} CallbackType; + +typedef struct +{ + int refcount; + CallbackType type; + void *data; + DBusFreeFunction free_data_func; +} Callback; + +typedef struct +{ + Callback callback; + DBusWatchFunction function; + DBusWatch *watch; + /* last watch handle failed due to OOM */ + unsigned int last_iteration_oom : 1; +} WatchCallback; + +typedef struct +{ + Callback callback; + DBusTimeout *timeout; + DBusTimeoutFunction function; + unsigned long last_tv_sec; + unsigned long last_tv_usec; +} TimeoutCallback; + +#define WATCH_CALLBACK(callback) ((WatchCallback*)callback) +#define TIMEOUT_CALLBACK(callback) ((TimeoutCallback*)callback) + +static WatchCallback* +watch_callback_new (DBusWatch *watch, + DBusWatchFunction function, + void *data, + DBusFreeFunction free_data_func) +{ + WatchCallback *cb; + + cb = dbus_new (WatchCallback, 1); + if (cb == NULL) + return NULL; + + cb->watch = watch; + cb->function = function; + cb->last_iteration_oom = FALSE; + cb->callback.refcount = 1; + cb->callback.type = CALLBACK_WATCH; + cb->callback.data = data; + cb->callback.free_data_func = free_data_func; + + return cb; +} + +static TimeoutCallback* +timeout_callback_new (DBusTimeout *timeout, + DBusTimeoutFunction function, + void *data, + DBusFreeFunction free_data_func) +{ + TimeoutCallback *cb; + + cb = dbus_new (TimeoutCallback, 1); + if (cb == NULL) + return NULL; + + cb->timeout = timeout; + cb->function = function; + _dbus_get_current_time (&cb->last_tv_sec, + &cb->last_tv_usec); + cb->callback.refcount = 1; + cb->callback.type = CALLBACK_TIMEOUT; + cb->callback.data = data; + cb->callback.free_data_func = free_data_func; + + return cb; +} + +static Callback * +callback_ref (Callback *cb) +{ + _dbus_assert (cb->refcount > 0); + + cb->refcount += 1; + + return cb; +} + +static void +callback_unref (Callback *cb) +{ + _dbus_assert (cb->refcount > 0); + + cb->refcount -= 1; + + if (cb->refcount == 0) + { + if (cb->free_data_func) + (* cb->free_data_func) (cb->data); + + dbus_free (cb); + } +} + +static dbus_bool_t +add_callback (DBusLoop *loop, + Callback *cb) +{ + if (!_dbus_list_append (&loop->callbacks, cb)) + return FALSE; + + loop->callback_list_serial += 1; + + switch (cb->type) + { + case CALLBACK_WATCH: + loop->watch_count += 1; + break; + case CALLBACK_TIMEOUT: + loop->timeout_count += 1; + break; + } + + return TRUE; +} + +static void +remove_callback (DBusLoop *loop, + DBusList *link) +{ + Callback *cb = link->data; + + switch (cb->type) + { + case CALLBACK_WATCH: + loop->watch_count -= 1; + break; + case CALLBACK_TIMEOUT: + loop->timeout_count -= 1; + break; + } + + callback_unref (cb); + _dbus_list_remove_link (&loop->callbacks, link); + loop->callback_list_serial += 1; +} + +DBusLoop* +_dbus_loop_new (void) +{ + DBusLoop *loop; + + loop = dbus_new0 (DBusLoop, 1); + if (loop == NULL) + return NULL; + + loop->refcount = 1; + + return loop; +} + +DBusLoop * +_dbus_loop_ref (DBusLoop *loop) +{ + _dbus_assert (loop != NULL); + _dbus_assert (loop->refcount > 0); + + loop->refcount += 1; + + return loop; +} + +void +_dbus_loop_unref (DBusLoop *loop) +{ + _dbus_assert (loop != NULL); + _dbus_assert (loop->refcount > 0); + + loop->refcount -= 1; + if (loop->refcount == 0) + { + while (loop->need_dispatch) + { + DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch); + + dbus_connection_unref (connection); + } + + dbus_free (loop); + } +} + +dbus_bool_t +_dbus_loop_add_watch (DBusLoop *loop, + DBusWatch *watch, + DBusWatchFunction function, + void *data, + DBusFreeFunction free_data_func) +{ + WatchCallback *wcb; + + wcb = watch_callback_new (watch, function, data, free_data_func); + if (wcb == NULL) + return FALSE; + + if (!add_callback (loop, (Callback*) wcb)) + { + wcb->callback.free_data_func = NULL; /* don't want to have this side effect */ + callback_unref ((Callback*) wcb); + return FALSE; + } + + return TRUE; +} + +void +_dbus_loop_remove_watch (DBusLoop *loop, + DBusWatch *watch, + DBusWatchFunction function, + void *data) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&loop->callbacks); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); + Callback *this = link->data; + + if (this->type == CALLBACK_WATCH && + WATCH_CALLBACK (this)->watch == watch && + this->data == data && + WATCH_CALLBACK (this)->function == function) + { + remove_callback (loop, link); + + return; + } + + link = next; + } + + _dbus_warn ("could not find watch %p function %p data %p to remove\n", + watch, (void *)function, data); +} + +dbus_bool_t +_dbus_loop_add_timeout (DBusLoop *loop, + DBusTimeout *timeout, + DBusTimeoutFunction function, + void *data, + DBusFreeFunction free_data_func) +{ + TimeoutCallback *tcb; + + tcb = timeout_callback_new (timeout, function, data, free_data_func); + if (tcb == NULL) + return FALSE; + + if (!add_callback (loop, (Callback*) tcb)) + { + tcb->callback.free_data_func = NULL; /* don't want to have this side effect */ + callback_unref ((Callback*) tcb); + return FALSE; + } + + return TRUE; +} + +void +_dbus_loop_remove_timeout (DBusLoop *loop, + DBusTimeout *timeout, + DBusTimeoutFunction function, + void *data) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&loop->callbacks); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); + Callback *this = link->data; + + if (this->type == CALLBACK_TIMEOUT && + TIMEOUT_CALLBACK (this)->timeout == timeout && + this->data == data && + TIMEOUT_CALLBACK (this)->function == function) + { + remove_callback (loop, link); + + return; + } + + link = next; + } + + _dbus_warn ("could not find timeout %p function %p data %p to remove\n", + timeout, (void *)function, data); +} + +/* Convolutions from GLib, there really must be a better way + * to do this. + */ +static dbus_bool_t +check_timeout (unsigned long tv_sec, + unsigned long tv_usec, + TimeoutCallback *tcb, + int *timeout) +{ + long sec_remaining; + long msec_remaining; + unsigned long expiration_tv_sec; + unsigned long expiration_tv_usec; + long interval_seconds; + long interval_milliseconds; + int interval; + + /* I'm pretty sure this function could suck (a lot) less */ + + interval = dbus_timeout_get_interval (tcb->timeout); + + interval_seconds = interval / 1000L; + interval_milliseconds = interval % 1000L; + + expiration_tv_sec = tcb->last_tv_sec + interval_seconds; + expiration_tv_usec = tcb->last_tv_usec + interval_milliseconds * 1000; + if (expiration_tv_usec >= 1000000) + { + expiration_tv_usec -= 1000000; + expiration_tv_sec += 1; + } + + sec_remaining = expiration_tv_sec - tv_sec; + /* need to force this to be signed, as it is intended to sometimes + * produce a negative result + */ + msec_remaining = ((long) expiration_tv_usec - (long) tv_usec) / 1000L; + +#if MAINLOOP_SPEW + _dbus_verbose ("Interval is %ld seconds %ld msecs\n", + interval_seconds, + interval_milliseconds); + _dbus_verbose ("Now is %lu seconds %lu usecs\n", + tv_sec, tv_usec); + _dbus_verbose ("Last is %lu seconds %lu usecs\n", + tcb->last_tv_sec, tcb->last_tv_usec); + _dbus_verbose ("Exp is %lu seconds %lu usecs\n", + expiration_tv_sec, expiration_tv_usec); + _dbus_verbose ("Pre-correction, sec_remaining %ld msec_remaining %ld\n", + sec_remaining, msec_remaining); +#endif + + /* We do the following in a rather convoluted fashion to deal with + * the fact that we don't have an integral type big enough to hold + * the difference of two timevals in milliseconds. + */ + if (sec_remaining < 0 || (sec_remaining == 0 && msec_remaining < 0)) + { + *timeout = 0; + } + else + { + if (msec_remaining < 0) + { + msec_remaining += 1000; + sec_remaining -= 1; + } + + if (sec_remaining > (_DBUS_INT_MAX / 1000) || + msec_remaining > _DBUS_INT_MAX) + *timeout = _DBUS_INT_MAX; + else + *timeout = sec_remaining * 1000 + msec_remaining; + } + + if (*timeout > interval) + { + /* This indicates that the system clock probably moved backward */ + _dbus_verbose ("System clock set backward! Resetting timeout.\n"); + + tcb->last_tv_sec = tv_sec; + tcb->last_tv_usec = tv_usec; + + *timeout = interval; + } + +#if MAINLOOP_SPEW + _dbus_verbose (" timeout expires in %d milliseconds\n", *timeout); +#endif + + return *timeout == 0; +} + +dbus_bool_t +_dbus_loop_dispatch (DBusLoop *loop) +{ + +#if MAINLOOP_SPEW + _dbus_verbose (" %d connections to dispatch\n", _dbus_list_get_length (&loop->need_dispatch)); +#endif + + if (loop->need_dispatch == NULL) + return FALSE; + + next: + while (loop->need_dispatch != NULL) + { + DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch); + + while (TRUE) + { + DBusDispatchStatus status; + + status = dbus_connection_dispatch (connection); + + if (status == DBUS_DISPATCH_COMPLETE) + { + dbus_connection_unref (connection); + goto next; + } + else + { + if (status == DBUS_DISPATCH_NEED_MEMORY) + _dbus_wait_for_memory (); + } + } + } + + return TRUE; +} + +dbus_bool_t +_dbus_loop_queue_dispatch (DBusLoop *loop, + DBusConnection *connection) +{ + if (_dbus_list_append (&loop->need_dispatch, connection)) + { + dbus_connection_ref (connection); + return TRUE; + } + else + return FALSE; +} + +/* Returns TRUE if we invoked any timeouts or have ready file + * descriptors, which is just used in test code as a debug hack + */ + +dbus_bool_t +_dbus_loop_iterate (DBusLoop *loop, + dbus_bool_t block) +{ +#define N_STACK_DESCRIPTORS 64 + dbus_bool_t retval; + DBusPollFD *fds; + DBusPollFD stack_fds[N_STACK_DESCRIPTORS]; + int n_fds; + WatchCallback **watches_for_fds; + WatchCallback *stack_watches_for_fds[N_STACK_DESCRIPTORS]; + int i; + DBusList *link; + int n_ready; + int initial_serial; + long timeout; + dbus_bool_t oom_watch_pending; + int orig_depth; + + retval = FALSE; + + fds = NULL; + watches_for_fds = NULL; + n_fds = 0; + oom_watch_pending = FALSE; + orig_depth = loop->depth; + +#if MAINLOOP_SPEW + _dbus_verbose ("Iteration block=%d depth=%d timeout_count=%d watch_count=%d\n", + block, loop->depth, loop->timeout_count, loop->watch_count); +#endif + + if (loop->callbacks == NULL) + goto next_iteration; + + if (loop->watch_count > N_STACK_DESCRIPTORS) + { + fds = dbus_new0 (DBusPollFD, loop->watch_count); + + while (fds == NULL) + { + _dbus_wait_for_memory (); + fds = dbus_new0 (DBusPollFD, loop->watch_count); + } + + watches_for_fds = dbus_new (WatchCallback*, loop->watch_count); + while (watches_for_fds == NULL) + { + _dbus_wait_for_memory (); + watches_for_fds = dbus_new (WatchCallback*, loop->watch_count); + } + } + else + { + fds = stack_fds; + watches_for_fds = stack_watches_for_fds; + } + + /* fill our array of fds and watches */ + n_fds = 0; + link = _dbus_list_get_first_link (&loop->callbacks); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); + Callback *cb = link->data; + if (cb->type == CALLBACK_WATCH) + { + unsigned int flags; + WatchCallback *wcb = WATCH_CALLBACK (cb); + + if (wcb->last_iteration_oom) + { + /* we skip this one this time, but reenable it next time, + * and have a timeout on this iteration + */ + wcb->last_iteration_oom = FALSE; + oom_watch_pending = TRUE; + + retval = TRUE; /* return TRUE here to keep the loop going, + * since we don't know the watch is inactive + */ + +#if MAINLOOP_SPEW + _dbus_verbose (" skipping watch on fd %d as it was out of memory last time\n", + dbus_watch_get_socket (wcb->watch)); +#endif + } + else if (dbus_watch_get_enabled (wcb->watch)) + { + watches_for_fds[n_fds] = wcb; + + callback_ref (cb); + + flags = dbus_watch_get_flags (wcb->watch); + + fds[n_fds].fd = dbus_watch_get_socket (wcb->watch); + fds[n_fds].revents = 0; + fds[n_fds].events = 0; + if (flags & DBUS_WATCH_READABLE) + fds[n_fds].events |= _DBUS_POLLIN; + if (flags & DBUS_WATCH_WRITABLE) + fds[n_fds].events |= _DBUS_POLLOUT; + +#if MAINLOOP_SPEW + _dbus_verbose (" polling watch on fd %d %s\n", + fds[n_fds].fd, watch_flags_to_string (flags)); +#endif + + n_fds += 1; + } + else + { +#if MAINLOOP_SPEW + _dbus_verbose (" skipping disabled watch on fd %d %s\n", + dbus_watch_get_socket (wcb->watch), + watch_flags_to_string (dbus_watch_get_flags (wcb->watch))); +#endif + } + } + + link = next; + } + + timeout = -1; + if (loop->timeout_count > 0) + { + unsigned long tv_sec; + unsigned long tv_usec; + + _dbus_get_current_time (&tv_sec, &tv_usec); + + link = _dbus_list_get_first_link (&loop->callbacks); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); + Callback *cb = link->data; + + if (cb->type == CALLBACK_TIMEOUT && + dbus_timeout_get_enabled (TIMEOUT_CALLBACK (cb)->timeout)) + { + TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb); + int msecs_remaining; + + check_timeout (tv_sec, tv_usec, tcb, &msecs_remaining); + + if (timeout < 0) + timeout = msecs_remaining; + else + timeout = MIN (msecs_remaining, timeout); + +#if MAINLOOP_SPEW + _dbus_verbose (" timeout added, %d remaining, aggregate timeout %ld\n", + msecs_remaining, timeout); +#endif + + _dbus_assert (timeout >= 0); + + if (timeout == 0) + break; /* it's not going to get shorter... */ + } +#if MAINLOOP_SPEW + else if (cb->type == CALLBACK_TIMEOUT) + { + _dbus_verbose (" skipping disabled timeout\n"); + } +#endif + + link = next; + } + } + + /* Never block if we have stuff to dispatch */ + if (!block || loop->need_dispatch != NULL) + { + timeout = 0; +#if MAINLOOP_SPEW + _dbus_verbose (" timeout is 0 as we aren't blocking\n"); +#endif + } + + /* if a watch is OOM, don't wait longer than the OOM + * wait to re-enable it + */ + if (oom_watch_pending) + timeout = MIN (timeout, _dbus_get_oom_wait ()); + +#if MAINLOOP_SPEW + _dbus_verbose (" polling on %d descriptors timeout %ld\n", n_fds, timeout); +#endif + + n_ready = _dbus_poll (fds, n_fds, timeout); + + initial_serial = loop->callback_list_serial; + + if (loop->timeout_count > 0) + { + unsigned long tv_sec; + unsigned long tv_usec; + + _dbus_get_current_time (&tv_sec, &tv_usec); + + /* It'd be nice to avoid this O(n) thingy here */ + link = _dbus_list_get_first_link (&loop->callbacks); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); + Callback *cb = link->data; + + if (initial_serial != loop->callback_list_serial) + goto next_iteration; + + if (loop->depth != orig_depth) + goto next_iteration; + + if (cb->type == CALLBACK_TIMEOUT && + dbus_timeout_get_enabled (TIMEOUT_CALLBACK (cb)->timeout)) + { + TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb); + int msecs_remaining; + + if (check_timeout (tv_sec, tv_usec, + tcb, &msecs_remaining)) + { + /* Save last callback time and fire this timeout */ + tcb->last_tv_sec = tv_sec; + tcb->last_tv_usec = tv_usec; + +#if MAINLOOP_SPEW + _dbus_verbose (" invoking timeout\n"); +#endif + + (* tcb->function) (tcb->timeout, + cb->data); + + retval = TRUE; + } + else + { +#if MAINLOOP_SPEW + _dbus_verbose (" timeout has not expired\n"); +#endif + } + } +#if MAINLOOP_SPEW + else if (cb->type == CALLBACK_TIMEOUT) + { + _dbus_verbose (" skipping invocation of disabled timeout\n"); + } +#endif + + link = next; + } + } + + if (n_ready > 0) + { + i = 0; + while (i < n_fds) + { + /* FIXME I think this "restart if we change the watches" + * approach could result in starving watches + * toward the end of the list. + */ + if (initial_serial != loop->callback_list_serial) + goto next_iteration; + + if (loop->depth != orig_depth) + goto next_iteration; + + if (fds[i].revents != 0) + { + WatchCallback *wcb; + unsigned int condition; + + wcb = watches_for_fds[i]; + + condition = 0; + if (fds[i].revents & _DBUS_POLLIN) + condition |= DBUS_WATCH_READABLE; + if (fds[i].revents & _DBUS_POLLOUT) + condition |= DBUS_WATCH_WRITABLE; + if (fds[i].revents & _DBUS_POLLHUP) + condition |= DBUS_WATCH_HANGUP; + if (fds[i].revents & _DBUS_POLLERR) + condition |= DBUS_WATCH_ERROR; + + /* condition may still be 0 if we got some + * weird POLLFOO thing like POLLWRBAND + */ + + if (condition != 0 && + dbus_watch_get_enabled (wcb->watch)) + { + if (!(* wcb->function) (wcb->watch, + condition, + ((Callback*)wcb)->data)) + wcb->last_iteration_oom = TRUE; + +#if MAINLOOP_SPEW + _dbus_verbose (" Invoked watch, oom = %d\n", + wcb->last_iteration_oom); +#endif + + retval = TRUE; + } + } + + ++i; + } + } + + next_iteration: +#if MAINLOOP_SPEW + _dbus_verbose (" moving to next iteration\n"); +#endif + + if (fds && fds != stack_fds) + dbus_free (fds); + if (watches_for_fds) + { + i = 0; + while (i < n_fds) + { + callback_unref (&watches_for_fds[i]->callback); + ++i; + } + + if (watches_for_fds != stack_watches_for_fds) + dbus_free (watches_for_fds); + } + + if (_dbus_loop_dispatch (loop)) + retval = TRUE; + +#if MAINLOOP_SPEW + _dbus_verbose ("Returning %d\n", retval); +#endif + + return retval; +} + +void +_dbus_loop_run (DBusLoop *loop) +{ + int our_exit_depth; + + _dbus_assert (loop->depth >= 0); + + _dbus_loop_ref (loop); + + our_exit_depth = loop->depth; + loop->depth += 1; + + _dbus_verbose ("Running main loop, depth %d -> %d\n", + loop->depth - 1, loop->depth); + + while (loop->depth != our_exit_depth) + _dbus_loop_iterate (loop, TRUE); + + _dbus_loop_unref (loop); +} + +void +_dbus_loop_quit (DBusLoop *loop) +{ + _dbus_assert (loop->depth > 0); + + loop->depth -= 1; + + _dbus_verbose ("Quit main loop, depth %d -> %d\n", + loop->depth + 1, loop->depth); +} + +int +_dbus_get_oom_wait (void) +{ +#ifdef DBUS_BUILD_TESTS + /* make tests go fast */ + return 0; +#else + return 500; +#endif +} + +void +_dbus_wait_for_memory (void) +{ + _dbus_verbose ("Waiting for more memory\n"); + _dbus_sleep_milliseconds (_dbus_get_oom_wait ()); +} + +#endif /* !DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/dbus/dbus-mainloop.h b/dbus/dbus-mainloop.h new file mode 100644 index 00000000..656f8231 --- /dev/null +++ b/dbus/dbus-mainloop.h @@ -0,0 +1,76 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-mainloop.h Main loop utility + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_MAINLOOP_H +#define DBUS_MAINLOOP_H + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#include + +typedef struct DBusLoop DBusLoop; + +typedef dbus_bool_t (* DBusWatchFunction) (DBusWatch *watch, + unsigned int condition, + void *data); +typedef void (* DBusTimeoutFunction) (DBusTimeout *timeout, + void *data); + +DBusLoop* _dbus_loop_new (void); +DBusLoop* _dbus_loop_ref (DBusLoop *loop); +void _dbus_loop_unref (DBusLoop *loop); +dbus_bool_t _dbus_loop_add_watch (DBusLoop *loop, + DBusWatch *watch, + DBusWatchFunction function, + void *data, + DBusFreeFunction free_data_func); +void _dbus_loop_remove_watch (DBusLoop *loop, + DBusWatch *watch, + DBusWatchFunction function, + void *data); +dbus_bool_t _dbus_loop_add_timeout (DBusLoop *loop, + DBusTimeout *timeout, + DBusTimeoutFunction function, + void *data, + DBusFreeFunction free_data_func); +void _dbus_loop_remove_timeout (DBusLoop *loop, + DBusTimeout *timeout, + DBusTimeoutFunction function, + void *data); + +dbus_bool_t _dbus_loop_queue_dispatch (DBusLoop *loop, + DBusConnection *connection); + +void _dbus_loop_run (DBusLoop *loop); +void _dbus_loop_quit (DBusLoop *loop); +dbus_bool_t _dbus_loop_iterate (DBusLoop *loop, + dbus_bool_t block); +dbus_bool_t _dbus_loop_dispatch (DBusLoop *loop); + +int _dbus_get_oom_wait (void); +void _dbus_wait_for_memory (void); + +#endif /* !DOXYGEN_SHOULD_SKIP_THIS */ + +#endif /* DBUS_MAINLOOP_H */ + diff --git a/dbus/dbus-marshal-basic.c b/dbus/dbus-marshal-basic.c new file mode 100644 index 00000000..3d0d3d0b --- /dev/null +++ b/dbus/dbus-marshal-basic.c @@ -0,0 +1,1982 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-basic.c Marshalling routines for basic (primitive) types + * + * Copyright (C) 2002 CodeFactory AB + * Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-marshal-basic.h" +#include "dbus-signature.h" + +#include + +/** + * @defgroup DBusMarshal marshaling and unmarshaling + * @ingroup DBusInternals + * @brief functions to marshal/unmarshal data from the wire + * + * Types and functions related to converting primitive data types from + * wire format to native machine format, and vice versa. + * + * A signature is just a string with multiple types one after the other. + * for example a type is "i" or "(ii)", a signature is "i(ii)" + * where i is int and (ii) is struct { int; int; } + * + * @{ + */ + +static void +pack_2_octets (dbus_uint16_t value, + int byte_order, + unsigned char *data) +{ + _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 2) == data); + + if ((byte_order) == DBUS_LITTLE_ENDIAN) + *((dbus_uint16_t*)(data)) = DBUS_UINT16_TO_LE (value); + else + *((dbus_uint16_t*)(data)) = DBUS_UINT16_TO_BE (value); +} + +static void +pack_4_octets (dbus_uint32_t value, + int byte_order, + unsigned char *data) +{ + _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data); + + if ((byte_order) == DBUS_LITTLE_ENDIAN) + *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_LE (value); + else + *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_BE (value); +} + +static void +pack_8_octets (DBusBasicValue value, + int byte_order, + unsigned char *data) +{ + _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 8) == data); + +#ifdef DBUS_HAVE_INT64 + if ((byte_order) == DBUS_LITTLE_ENDIAN) + *((dbus_uint64_t*)(data)) = DBUS_UINT64_TO_LE (value.u64); + else + *((dbus_uint64_t*)(data)) = DBUS_UINT64_TO_BE (value.u64); +#else + *(DBus8ByteStruct*)data = value.u64; + swap_8_octets ((DBusBasicValue*)data, byte_order); +#endif +} + +/** + * Packs a 32 bit unsigned integer into a data pointer. + * + * @param value the value + * @param byte_order the byte order to use + * @param data the data pointer + */ +void +_dbus_pack_uint32 (dbus_uint32_t value, + int byte_order, + unsigned char *data) +{ + pack_4_octets (value, byte_order, data); +} + +#ifndef DBUS_HAVE_INT64 +/* from ORBit */ +static void +swap_bytes (unsigned char *data, + unsigned int len) +{ + unsigned char *p1 = data; + unsigned char *p2 = data + len - 1; + + while (p1 < p2) + { + unsigned char tmp = *p1; + *p1 = *p2; + *p2 = tmp; + + --p2; + ++p1; + } +} +#endif /* !DBUS_HAVE_INT64 */ + +static void +swap_8_octets (DBusBasicValue *value, + int byte_order) +{ + if (byte_order != DBUS_COMPILER_BYTE_ORDER) + { +#ifdef DBUS_HAVE_INT64 + value->u64 = DBUS_UINT64_SWAP_LE_BE (value->u64); +#else + swap_bytes ((unsigned char *)value, 8); +#endif + } +} + +#if 0 +static DBusBasicValue +unpack_8_octets (int byte_order, + const unsigned char *data) +{ + DBusBasicValue r; + + _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 8) == data); + _dbus_assert (sizeof (r) == 8); + +#ifdef DBUS_HAVE_INT64 + if (byte_order == DBUS_LITTLE_ENDIAN) + r.u64 = DBUS_UINT64_FROM_LE (*(dbus_uint64_t*)data); + else + r.u64 = DBUS_UINT64_FROM_BE (*(dbus_uint64_t*)data); +#else + r.u64 = *(DBus8ByteStruct*)data; + swap_8_octets (&r, byte_order); +#endif + + return r; +} +#endif + +#ifndef _dbus_unpack_uint16 +/** + * Unpacks a 16 bit unsigned integer from a data pointer + * + * @param byte_order The byte order to use + * @param data the data pointer + * @returns the integer + */ +dbus_uint16_t +_dbus_unpack_uint16 (int byte_order, + const unsigned char *data) +{ + _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 2) == data); + + if (byte_order == DBUS_LITTLE_ENDIAN) + return DBUS_UINT16_FROM_LE (*(dbus_uint16_t*)data); + else + return DBUS_UINT16_FROM_BE (*(dbus_uint16_t*)data); +} +#endif /* _dbus_unpack_uint16 */ + +#ifndef _dbus_unpack_uint32 +/** + * Unpacks a 32 bit unsigned integer from a data pointer + * + * @param byte_order The byte order to use + * @param data the data pointer + * @returns the integer + */ +dbus_uint32_t +_dbus_unpack_uint32 (int byte_order, + const unsigned char *data) +{ + _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data); + + if (byte_order == DBUS_LITTLE_ENDIAN) + return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data); + else + return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data); +} +#endif /* _dbus_unpack_uint32 */ + +static void +set_2_octets (DBusString *str, + int offset, + dbus_uint16_t value, + int byte_order) +{ + char *data; + + _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || + byte_order == DBUS_BIG_ENDIAN); + + data = _dbus_string_get_data_len (str, offset, 2); + + pack_2_octets (value, byte_order, data); +} + +static void +set_4_octets (DBusString *str, + int offset, + dbus_uint32_t value, + int byte_order) +{ + char *data; + + _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || + byte_order == DBUS_BIG_ENDIAN); + + data = _dbus_string_get_data_len (str, offset, 4); + + pack_4_octets (value, byte_order, data); +} + +static void +set_8_octets (DBusString *str, + int offset, + DBusBasicValue value, + int byte_order) +{ + char *data; + + _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || + byte_order == DBUS_BIG_ENDIAN); + + data = _dbus_string_get_data_len (str, offset, 8); + + pack_8_octets (value, byte_order, data); +} + +/** + * Sets the 4 bytes at the given offset to a marshaled unsigned + * integer, replacing anything found there previously. + * + * @param str the string to write the marshalled int to + * @param pos the byte offset where int should be written + * @param value the value + * @param byte_order the byte order to use + * + */ +void +_dbus_marshal_set_uint32 (DBusString *str, + int pos, + dbus_uint32_t value, + int byte_order) +{ + set_4_octets (str, pos, value, byte_order); +} + +/** + * Sets the existing marshaled string at the given offset with + * a new marshaled string. The given offset must point to + * an existing string or the wrong length will be deleted + * and replaced with the new string. + * + * Note: no attempt is made by this function to re-align + * any data which has been already marshalled after this + * string. Use with caution. + * + * @param str the string to write the marshalled string to + * @param pos the position of the marshaled string length + * @param value the value + * @param byte_order the byte order to use + * @param old_end_pos place to store byte after the nul byte of the old value + * @param new_end_pos place to store byte after the nul byte of the new value + * @returns #TRUE on success, #FALSE if no memory + * + */ +static dbus_bool_t +set_string (DBusString *str, + int pos, + const char *value, + int byte_order, + int *old_end_pos, + int *new_end_pos) +{ + int old_len, new_len; + DBusString dstr; + + _dbus_string_init_const (&dstr, value); + + _dbus_assert (_DBUS_ALIGN_VALUE (pos, 4) == (unsigned) pos); + old_len = _dbus_unpack_uint32 (byte_order, + _dbus_string_get_const_data_len (str, pos, 4)); + + new_len = _dbus_string_get_length (&dstr); + + if (!_dbus_string_replace_len (&dstr, 0, new_len, + str, pos + 4, old_len)) + return FALSE; + + _dbus_marshal_set_uint32 (str, pos, new_len, byte_order); + + if (old_end_pos) + *old_end_pos = pos + 4 + old_len + 1; + if (new_end_pos) + *new_end_pos = pos + 4 + new_len + 1; + + return TRUE; +} + +/** + * Sets the existing marshaled signature at the given offset to a new + * marshaled signature. Same basic ideas as set_string(). + * + * @param str the string to write the marshalled signature to + * @param pos the position of the marshaled signature length + * @param value the value + * @param byte_order the byte order to use + * @param old_end_pos place to store byte after the nul byte of the old value + * @param new_end_pos place to store byte after the nul byte of the new value + * @returns #TRUE on success, #FALSE if no memory + * + */ +static dbus_bool_t +set_signature (DBusString *str, + int pos, + const char *value, + int byte_order, + int *old_end_pos, + int *new_end_pos) +{ + int old_len, new_len; + DBusString dstr; + + _dbus_string_init_const (&dstr, value); + + old_len = _dbus_string_get_byte (str, pos); + new_len = _dbus_string_get_length (&dstr); + + if (!_dbus_string_replace_len (&dstr, 0, new_len, + str, pos + 1, old_len)) + return FALSE; + + _dbus_string_set_byte (str, pos, new_len); + + if (old_end_pos) + *old_end_pos = pos + 1 + old_len + 1; + if (new_end_pos) + *new_end_pos = pos + 1 + new_len + 1; + + return TRUE; +} + +/** + * Sets an existing basic type value to a new value. + * Arguments work the same way as _dbus_marshal_basic_type(). + * + * @param str the string + * @param pos location of the current value + * @param type the type of the current and new values + * @param value the address of the new value + * @param byte_order byte order for marshaling + * @param old_end_pos location to store end position of the old value, or #NULL + * @param new_end_pos location to store end position of the new value, or #NULL + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_marshal_set_basic (DBusString *str, + int pos, + int type, + const void *value, + int byte_order, + int *old_end_pos, + int *new_end_pos) +{ + const DBusBasicValue *vp; + + vp = value; + + switch (type) + { + case DBUS_TYPE_BYTE: + _dbus_string_set_byte (str, pos, vp->byt); + if (old_end_pos) + *old_end_pos = pos + 1; + if (new_end_pos) + *new_end_pos = pos + 1; + return TRUE; + break; + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + pos = _DBUS_ALIGN_VALUE (pos, 2); + set_2_octets (str, pos, vp->u16, byte_order); + if (old_end_pos) + *old_end_pos = pos + 2; + if (new_end_pos) + *new_end_pos = pos + 2; + return TRUE; + break; + case DBUS_TYPE_BOOLEAN: + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + pos = _DBUS_ALIGN_VALUE (pos, 4); + set_4_octets (str, pos, vp->u32, byte_order); + if (old_end_pos) + *old_end_pos = pos + 4; + if (new_end_pos) + *new_end_pos = pos + 4; + return TRUE; + break; + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + pos = _DBUS_ALIGN_VALUE (pos, 8); + set_8_octets (str, pos, *vp, byte_order); + if (old_end_pos) + *old_end_pos = pos + 8; + if (new_end_pos) + *new_end_pos = pos + 8; + return TRUE; + break; + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + pos = _DBUS_ALIGN_VALUE (pos, 4); + _dbus_assert (vp->str != NULL); + return set_string (str, pos, vp->str, byte_order, + old_end_pos, new_end_pos); + break; + case DBUS_TYPE_SIGNATURE: + _dbus_assert (vp->str != NULL); + return set_signature (str, pos, vp->str, byte_order, + old_end_pos, new_end_pos); + break; + default: + _dbus_assert_not_reached ("not a basic type"); + return FALSE; + break; + } +} + +/** + * Convenience function to demarshal a 32 bit unsigned integer. + * + * @param str the string containing the data + * @param byte_order the byte order + * @param pos the position in the string + * @param new_pos the new position of the string + * @returns the demarshaled integer. + */ +dbus_uint32_t +_dbus_marshal_read_uint32 (const DBusString *str, + int pos, + int byte_order, + int *new_pos) +{ + pos = _DBUS_ALIGN_VALUE (pos, 4); + + if (new_pos) + *new_pos = pos + 4; + + _dbus_assert (pos + 4 <= _dbus_string_get_length (str)); + + return _dbus_unpack_uint32 (byte_order, + _dbus_string_get_const_data (str) + pos); +} + +/** + * Demarshals a basic-typed value. The "value" pointer is always + * the address of a variable of the basic type. So e.g. + * if the basic type is "double" then the pointer is + * a double*, and if it's "char*" then the pointer is + * a "char**". + * + * A value of type #DBusBasicValue is guaranteed to be large enough to + * hold any of the types that may be returned, which is handy if you + * are trying to do things generically. For example you can pass + * a DBusBasicValue* in to this function, and then pass the same + * DBusBasicValue* in to _dbus_marshal_basic_type() in order to + * move a value from one place to another. + * + * @param str the string containing the data + * @param pos position in the string + * @param type type of value to demarshal + * @param value pointer to return value data + * @param byte_order the byte order + * @param new_pos pointer to update with new position, or #NULL + **/ +void +_dbus_marshal_read_basic (const DBusString *str, + int pos, + int type, + void *value, + int byte_order, + int *new_pos) +{ + const char *str_data; + + _dbus_assert (dbus_type_is_basic (type)); + + str_data = _dbus_string_get_const_data (str); + + /* Below we volatile types to avoid aliasing issues; + * see http://bugs.freedesktop.org/show_bug.cgi?id=20137 + */ + + switch (type) + { + case DBUS_TYPE_BYTE: + { + volatile unsigned char *vp = value; + *vp = (unsigned char) _dbus_string_get_byte (str, pos); + (pos)++; + } + break; + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + { + volatile dbus_uint16_t *vp = value; + pos = _DBUS_ALIGN_VALUE (pos, 2); + *vp = *(dbus_uint16_t *)(str_data + pos); + if (byte_order != DBUS_COMPILER_BYTE_ORDER) + *vp = DBUS_UINT16_SWAP_LE_BE (*vp); + pos += 2; + } + break; + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + case DBUS_TYPE_BOOLEAN: + { + volatile dbus_uint32_t *vp = value; + pos = _DBUS_ALIGN_VALUE (pos, 4); + *vp = *(dbus_uint32_t *)(str_data + pos); + if (byte_order != DBUS_COMPILER_BYTE_ORDER) + *vp = DBUS_UINT32_SWAP_LE_BE (*vp); + pos += 4; + } + break; + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + { + volatile dbus_uint64_t *vp = value; + pos = _DBUS_ALIGN_VALUE (pos, 8); +#ifdef DBUS_HAVE_INT64 + if (byte_order != DBUS_COMPILER_BYTE_ORDER) + *vp = DBUS_UINT64_SWAP_LE_BE (*(dbus_uint64_t*)(str_data + pos)); + else + *vp = *(dbus_uint64_t*)(str_data + pos); +#else + *vp = *(DBus8ByteStruct*) (str_data + pos); + swap_8_octets (vp, byte_order); +#endif + pos += 8; + } + break; + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + { + int len; + volatile char **vp = value; + + len = _dbus_marshal_read_uint32 (str, pos, byte_order, &pos); + + *vp = (char*) str_data + pos; + + pos += len + 1; /* length plus nul */ + } + break; + case DBUS_TYPE_SIGNATURE: + { + int len; + volatile char **vp = value; + + len = _dbus_string_get_byte (str, pos); + pos += 1; + + *vp = (char*) str_data + pos; + + pos += len + 1; /* length plus nul */ + } + break; + default: + _dbus_warn_check_failed ("type %s %d not a basic type\n", + _dbus_type_to_string (type), type); + _dbus_assert_not_reached ("not a basic type"); + break; + } + + if (new_pos) + *new_pos = pos; +} + +static dbus_bool_t +marshal_2_octets (DBusString *str, + int insert_at, + dbus_uint16_t value, + int byte_order, + int *pos_after) +{ + dbus_bool_t retval; + int orig_len; + + _dbus_assert (sizeof (value) == 2); + + if (byte_order != DBUS_COMPILER_BYTE_ORDER) + value = DBUS_UINT16_SWAP_LE_BE (value); + + orig_len = _dbus_string_get_length (str); + + retval = _dbus_string_insert_2_aligned (str, insert_at, + (const unsigned char *)&value); + + if (pos_after) + { + *pos_after = insert_at + (_dbus_string_get_length (str) - orig_len); + _dbus_assert (*pos_after <= _dbus_string_get_length (str)); + } + + return retval; +} + +static dbus_bool_t +marshal_4_octets (DBusString *str, + int insert_at, + dbus_uint32_t value, + int byte_order, + int *pos_after) +{ + dbus_bool_t retval; + int orig_len; + + _dbus_assert (sizeof (value) == 4); + + if (byte_order != DBUS_COMPILER_BYTE_ORDER) + value = DBUS_UINT32_SWAP_LE_BE (value); + + orig_len = _dbus_string_get_length (str); + + retval = _dbus_string_insert_4_aligned (str, insert_at, + (const unsigned char *)&value); + + if (pos_after) + { + *pos_after = insert_at + (_dbus_string_get_length (str) - orig_len); + _dbus_assert (*pos_after <= _dbus_string_get_length (str)); + } + + return retval; +} + +static dbus_bool_t +marshal_8_octets (DBusString *str, + int insert_at, + DBusBasicValue value, + int byte_order, + int *pos_after) +{ + dbus_bool_t retval; + int orig_len; + + _dbus_assert (sizeof (value) == 8); + + swap_8_octets (&value, byte_order); + + orig_len = _dbus_string_get_length (str); + + retval = _dbus_string_insert_8_aligned (str, insert_at, + (const unsigned char *)&value); + + if (pos_after) + *pos_after = insert_at + _dbus_string_get_length (str) - orig_len; + + return retval; +} + +enum + { + MARSHAL_AS_STRING, + MARSHAL_AS_SIGNATURE, + MARSHAL_AS_BYTE_ARRAY + }; + +static dbus_bool_t +marshal_len_followed_by_bytes (int marshal_as, + DBusString *str, + int insert_at, + const unsigned char *value, + int data_len, /* doesn't include nul if any */ + int byte_order, + int *pos_after) +{ + int pos; + DBusString value_str; + int value_len; + + _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || byte_order == DBUS_BIG_ENDIAN); + if (insert_at > _dbus_string_get_length (str)) + _dbus_warn ("insert_at = %d string len = %d data_len = %d\n", + insert_at, _dbus_string_get_length (str), data_len); + + if (marshal_as == MARSHAL_AS_BYTE_ARRAY) + value_len = data_len; + else + value_len = data_len + 1; /* value has a nul */ + + _dbus_string_init_const_len (&value_str, value, value_len); + + pos = insert_at; + + if (marshal_as == MARSHAL_AS_SIGNATURE) + { + _dbus_assert (data_len <= DBUS_MAXIMUM_SIGNATURE_LENGTH); + _dbus_assert (data_len <= 255); /* same as max sig len right now */ + + if (!_dbus_string_insert_byte (str, pos, data_len)) + goto oom; + + pos += 1; + } + else + { + if (!marshal_4_octets (str, pos, data_len, + byte_order, &pos)) + goto oom; + } + + if (!_dbus_string_copy_len (&value_str, 0, value_len, + str, pos)) + goto oom; + +#if 0 + /* too expensive */ + _dbus_assert (_dbus_string_equal_substring (&value_str, 0, value_len, + str, pos)); + _dbus_verbose_bytes_of_string (str, pos, value_len); +#endif + + pos += value_len; + + if (pos_after) + *pos_after = pos; + + return TRUE; + + oom: + /* Delete what we've inserted */ + _dbus_string_delete (str, insert_at, pos - insert_at); + + return FALSE; +} + +static dbus_bool_t +marshal_string (DBusString *str, + int insert_at, + const char *value, + int byte_order, + int *pos_after) +{ + return marshal_len_followed_by_bytes (MARSHAL_AS_STRING, + str, insert_at, value, + strlen (value), + byte_order, pos_after); +} + +static dbus_bool_t +marshal_signature (DBusString *str, + int insert_at, + const char *value, + int *pos_after) +{ + return marshal_len_followed_by_bytes (MARSHAL_AS_SIGNATURE, + str, insert_at, value, + strlen (value), + DBUS_COMPILER_BYTE_ORDER, /* irrelevant */ + pos_after); +} + +/** + * Marshals a basic-typed value. The "value" pointer is always the + * address of a variable containing the basic type value. + * So for example for int32 it will be dbus_int32_t*, and + * for string it will be const char**. This is for symmetry + * with _dbus_marshal_read_basic() and to have a simple + * consistent rule. + * + * @param str string to marshal to + * @param insert_at where to insert the value + * @param type type of value + * @param value pointer to a variable containing the value + * @param byte_order byte order + * @param pos_after #NULL or the position after the type + * @returns #TRUE on success + **/ +dbus_bool_t +_dbus_marshal_write_basic (DBusString *str, + int insert_at, + int type, + const void *value, + int byte_order, + int *pos_after) +{ + const DBusBasicValue *vp; + + _dbus_assert (dbus_type_is_basic (type)); + + vp = value; + + switch (type) + { + case DBUS_TYPE_BYTE: + if (!_dbus_string_insert_byte (str, insert_at, vp->byt)) + return FALSE; + if (pos_after) + *pos_after = insert_at + 1; + return TRUE; + break; + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + return marshal_2_octets (str, insert_at, vp->u16, + byte_order, pos_after); + break; + case DBUS_TYPE_BOOLEAN: + return marshal_4_octets (str, insert_at, vp->u32 != FALSE, + byte_order, pos_after); + break; + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + return marshal_4_octets (str, insert_at, vp->u32, + byte_order, pos_after); + break; + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + return marshal_8_octets (str, insert_at, *vp, byte_order, pos_after); + break; + + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + _dbus_assert (vp->str != NULL); + return marshal_string (str, insert_at, vp->str, byte_order, pos_after); + break; + case DBUS_TYPE_SIGNATURE: + _dbus_assert (vp->str != NULL); + return marshal_signature (str, insert_at, vp->str, pos_after); + break; + default: + _dbus_assert_not_reached ("not a basic type"); + return FALSE; + break; + } +} + +static dbus_bool_t +marshal_1_octets_array (DBusString *str, + int insert_at, + const unsigned char *value, + int n_elements, + int byte_order, + int *pos_after) +{ + int pos; + DBusString value_str; + + _dbus_string_init_const_len (&value_str, value, n_elements); + + pos = insert_at; + + if (!_dbus_string_copy_len (&value_str, 0, n_elements, + str, pos)) + return FALSE; + + pos += n_elements; + + if (pos_after) + *pos_after = pos; + + return TRUE; +} + +/** + * Swaps the elements of an array to the opposite byte order + * + * @param data start of array + * @param n_elements number of elements + * @param alignment size of each element + */ +void +_dbus_swap_array (unsigned char *data, + int n_elements, + int alignment) +{ + unsigned char *d; + unsigned char *end; + + _dbus_assert (_DBUS_ALIGN_ADDRESS (data, alignment) == data); + + /* we use const_data and cast it off so DBusString can be a const string + * for the unit tests. don't ask. + */ + d = data; + end = d + (n_elements * alignment); + + if (alignment == 8) + { + while (d != end) + { +#ifdef DBUS_HAVE_INT64 + *((dbus_uint64_t*)d) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)d)); +#else + swap_8_bytes ((DBusBasicValue*) d); +#endif + d += 8; + } + } + else if (alignment == 4) + { + while (d != end) + { + *((dbus_uint32_t*)d) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)d)); + d += 4; + } + } + else + { + _dbus_assert (alignment == 2); + + while (d != end) + { + *((dbus_uint16_t*)d) = DBUS_UINT16_SWAP_LE_BE (*((dbus_uint16_t*)d)); + d += 2; + } + } +} + +static void +swap_array (DBusString *str, + int array_start, + int n_elements, + int byte_order, + int alignment) +{ + _dbus_assert (_DBUS_ALIGN_VALUE (array_start, alignment) == (unsigned) array_start); + + if (byte_order != DBUS_COMPILER_BYTE_ORDER) + { + /* we use const_data and cast it off so DBusString can be a const string + * for the unit tests. don't ask. + */ + _dbus_swap_array ((unsigned char*) (_dbus_string_get_const_data (str) + array_start), + n_elements, alignment); + } +} + +static dbus_bool_t +marshal_fixed_multi (DBusString *str, + int insert_at, + const DBusBasicValue *value, + int n_elements, + int byte_order, + int alignment, + int *pos_after) +{ + int old_string_len; + int array_start; + DBusString t; + int len_in_bytes; + + _dbus_assert (n_elements <= DBUS_MAXIMUM_ARRAY_LENGTH / alignment); + + old_string_len = _dbus_string_get_length (str); + + len_in_bytes = n_elements * alignment; + array_start = insert_at; + + /* Note that we do alignment padding unconditionally + * even if the array is empty; this means that + * padding + len is always equal to the number of bytes + * in the array. + */ + + if (!_dbus_string_insert_alignment (str, &array_start, alignment)) + goto error; + + _dbus_string_init_const_len (&t, + (const unsigned char*) value, + len_in_bytes); + + if (!_dbus_string_copy (&t, 0, + str, array_start)) + goto error; + + swap_array (str, array_start, n_elements, byte_order, alignment); + + if (pos_after) + *pos_after = array_start + len_in_bytes; + + return TRUE; + + error: + _dbus_string_delete (str, insert_at, + _dbus_string_get_length (str) - old_string_len); + + return FALSE; +} + +/** + * Marshals a block of values of fixed-length type all at once, as an + * optimization. dbus_type_is_fixed() returns #TRUE for fixed-length + * types, which are the basic types minus the string-like types. + * + * The value argument should be the adddress of an + * array, so e.g. "const dbus_uint32_t**" + * + * @param str string to marshal to + * @param insert_at where to insert the value + * @param element_type type of array elements + * @param value address of an array to marshal + * @param n_elements number of elements in the array + * @param byte_order byte order + * @param pos_after #NULL or the position after the type + * @returns #TRUE on success + **/ +dbus_bool_t +_dbus_marshal_write_fixed_multi (DBusString *str, + int insert_at, + int element_type, + const void *value, + int n_elements, + int byte_order, + int *pos_after) +{ + const void* vp = *(const DBusBasicValue**)value; + + _dbus_assert (dbus_type_is_fixed (element_type)); + _dbus_assert (n_elements >= 0); + +#if 0 + _dbus_verbose ("writing %d elements of %s\n", + n_elements, _dbus_type_to_string (element_type)); +#endif + + switch (element_type) + { + case DBUS_TYPE_BYTE: + return marshal_1_octets_array (str, insert_at, vp, n_elements, byte_order, pos_after); + break; + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 2, pos_after); + /* FIXME: we canonicalize to 0 or 1 for the single boolean case + * should we here too ? */ + case DBUS_TYPE_BOOLEAN: + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 4, pos_after); + break; + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 8, pos_after); + break; + + default: + _dbus_assert_not_reached ("non fixed type in array write"); + break; + } + + return FALSE; +} + + +/** + * Skips over a basic-typed value, reporting the following position. + * + * @param str the string containing the data + * @param type type of value to read + * @param byte_order the byte order + * @param pos pointer to position in the string, + * updated on return to new position + **/ +void +_dbus_marshal_skip_basic (const DBusString *str, + int type, + int byte_order, + int *pos) +{ + _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN || + byte_order == DBUS_BIG_ENDIAN); + + switch (type) + { + case DBUS_TYPE_BYTE: + (*pos)++; + break; + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + *pos = _DBUS_ALIGN_VALUE (*pos, 2); + *pos += 2; + break; + case DBUS_TYPE_BOOLEAN: + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + *pos = _DBUS_ALIGN_VALUE (*pos, 4); + *pos += 4; + break; + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + *pos = _DBUS_ALIGN_VALUE (*pos, 8); + *pos += 8; + break; + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + { + int len; + + len = _dbus_marshal_read_uint32 (str, *pos, byte_order, pos); + + *pos += len + 1; /* length plus nul */ + } + break; + case DBUS_TYPE_SIGNATURE: + { + int len; + + len = _dbus_string_get_byte (str, *pos); + + *pos += len + 2; /* length byte plus length plus nul */ + } + break; + default: + _dbus_warn ("type %s not a basic type\n", + _dbus_type_to_string (type)); + _dbus_assert_not_reached ("not a basic type"); + break; + } +} + +/** + * Skips an array, returning the next position. + * + * @param str the string containing the data + * @param element_type the type of array elements + * @param byte_order the byte order + * @param pos pointer to position in the string, + * updated on return to new position + */ +void +_dbus_marshal_skip_array (const DBusString *str, + int element_type, + int byte_order, + int *pos) +{ + dbus_uint32_t array_len; + int i; + int alignment; + + i = _DBUS_ALIGN_VALUE (*pos, 4); + + array_len = _dbus_marshal_read_uint32 (str, i, byte_order, &i); + + alignment = _dbus_type_get_alignment (element_type); + + i = _DBUS_ALIGN_VALUE (i, alignment); + + *pos = i + array_len; +} + +/** + * Gets the alignment requirement for the given type; + * will be 1, 4, or 8. + * + * @param typecode the type + * @returns alignment of 1, 4, or 8 + */ +int +_dbus_type_get_alignment (int typecode) +{ + switch (typecode) + { + case DBUS_TYPE_BYTE: + case DBUS_TYPE_VARIANT: + case DBUS_TYPE_SIGNATURE: + return 1; + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + return 2; + case DBUS_TYPE_BOOLEAN: + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + /* this stuff is 4 since it starts with a length */ + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_ARRAY: + return 4; + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + /* struct is 8 since it could contain an 8-aligned item + * and it's simpler to just always align structs to 8; + * we want the amount of padding in a struct of a given + * type to be predictable, not location-dependent. + * DICT_ENTRY is always the same as struct. + */ + case DBUS_TYPE_STRUCT: + case DBUS_TYPE_DICT_ENTRY: + return 8; + + default: + _dbus_assert_not_reached ("unknown typecode in _dbus_type_get_alignment()"); + return 0; + } +} + + +/** + * Return #TRUE if the typecode is a valid typecode. + * #DBUS_TYPE_INVALID surprisingly enough is not considered valid, and + * random unknown bytes aren't either. This function is safe with + * untrusted data. + * + * @returns #TRUE if valid + */ +dbus_bool_t +_dbus_type_is_valid (int typecode) +{ + switch (typecode) + { + case DBUS_TYPE_BYTE: + case DBUS_TYPE_BOOLEAN: + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_SIGNATURE: + case DBUS_TYPE_ARRAY: + case DBUS_TYPE_STRUCT: + case DBUS_TYPE_DICT_ENTRY: + case DBUS_TYPE_VARIANT: + return TRUE; + + default: + return FALSE; + } +} + +/** + * Returns a string describing the given type. + * + * @param typecode the type to describe + * @returns a constant string describing the type + */ +const char * +_dbus_type_to_string (int typecode) +{ + switch (typecode) + { + case DBUS_TYPE_INVALID: + return "invalid"; + case DBUS_TYPE_BOOLEAN: + return "boolean"; + case DBUS_TYPE_BYTE: + return "byte"; + case DBUS_TYPE_INT16: + return "int16"; + case DBUS_TYPE_UINT16: + return "uint16"; + case DBUS_TYPE_INT32: + return "int32"; + case DBUS_TYPE_UINT32: + return "uint32"; + case DBUS_TYPE_INT64: + return "int64"; + case DBUS_TYPE_UINT64: + return "uint64"; + case DBUS_TYPE_DOUBLE: + return "double"; + case DBUS_TYPE_STRING: + return "string"; + case DBUS_TYPE_OBJECT_PATH: + return "object_path"; + case DBUS_TYPE_SIGNATURE: + return "signature"; + case DBUS_TYPE_STRUCT: + return "struct"; + case DBUS_TYPE_DICT_ENTRY: + return "dict_entry"; + case DBUS_TYPE_ARRAY: + return "array"; + case DBUS_TYPE_VARIANT: + return "variant"; + case DBUS_STRUCT_BEGIN_CHAR: + return "begin_struct"; + case DBUS_STRUCT_END_CHAR: + return "end_struct"; + case DBUS_DICT_ENTRY_BEGIN_CHAR: + return "begin_dict_entry"; + case DBUS_DICT_ENTRY_END_CHAR: + return "end_dict_entry"; + default: + return "unknown"; + } +} + +/** + * If in verbose mode, print a block of binary data. + * + * @param data the data + * @param len the length of the data + * @param offset where to start counting for byte indexes + */ +void +_dbus_verbose_bytes (const unsigned char *data, + int len, + int offset) +{ + int i; + const unsigned char *aligned; + + _dbus_assert (len >= 0); + + if (!_dbus_is_verbose()) + return; + + /* Print blanks on first row if appropriate */ + aligned = _DBUS_ALIGN_ADDRESS (data, 4); + if (aligned > data) + aligned -= 4; + _dbus_assert (aligned <= data); + + if (aligned != data) + { + _dbus_verbose ("%4ld\t%p: ", - (long)(data - aligned), aligned); + while (aligned != data) + { + _dbus_verbose (" "); + ++aligned; + } + } + + /* now print the bytes */ + i = 0; + while (i < len) + { + if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i]) + { + _dbus_verbose ("%4d\t%p: ", + offset + i, &data[i]); + } + + if (data[i] >= 32 && + data[i] <= 126) + _dbus_verbose (" '%c' ", data[i]); + else + _dbus_verbose ("0x%s%x ", + data[i] <= 0xf ? "0" : "", data[i]); + + ++i; + + if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i]) + { + if (i > 3) + _dbus_verbose ("BE: %d LE: %d", + _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]), + _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4])); + + if (i > 7 && + _DBUS_ALIGN_ADDRESS (&data[i], 8) == &data[i]) + { +#ifdef DBUS_INT64_PRINTF_MODIFIER + _dbus_verbose (" u64: 0x%" DBUS_INT64_PRINTF_MODIFIER "x", + *(dbus_uint64_t*)&data[i-8]); +#endif + _dbus_verbose (" dbl: %g", + *(double*)&data[i-8]); + } + + _dbus_verbose ("\n"); + } + } + + _dbus_verbose ("\n"); +} + +/** + * Dump the given part of the string to verbose log. + * + * @param str the string + * @param start the start of range to dump + * @param len length of range + */ +void +_dbus_verbose_bytes_of_string (const DBusString *str, + int start, + int len) +{ + const char *d; + int real_len; + + real_len = _dbus_string_get_length (str); + + _dbus_assert (start >= 0); + + if (start > real_len) + { + _dbus_verbose (" [%d,%d) is not inside string of length %d\n", + start, len, real_len); + return; + } + + if ((start + len) > real_len) + { + _dbus_verbose (" [%d,%d) extends outside string of length %d\n", + start, len, real_len); + len = real_len - start; + } + + d = _dbus_string_get_const_data_len (str, start, len); + + _dbus_verbose_bytes (d, len, start); +} + +static int +map_type_char_to_type (int t) +{ + if (t == DBUS_STRUCT_BEGIN_CHAR) + return DBUS_TYPE_STRUCT; + else if (t == DBUS_DICT_ENTRY_BEGIN_CHAR) + return DBUS_TYPE_DICT_ENTRY; + else + { + _dbus_assert (t != DBUS_STRUCT_END_CHAR); + _dbus_assert (t != DBUS_DICT_ENTRY_END_CHAR); + return t; + } +} + +/** + * Get the first type in the signature. The difference between this + * and just getting the first byte of the signature is that you won't + * get DBUS_STRUCT_BEGIN_CHAR, you'll get DBUS_TYPE_STRUCT + * instead. + * + * @param str string containing signature + * @param pos where the signature starts + * @returns the first type in the signature + */ +int +_dbus_first_type_in_signature (const DBusString *str, + int pos) +{ + return map_type_char_to_type (_dbus_string_get_byte (str, pos)); +} + +/** + * Similar to #_dbus_first_type_in_signature, but operates + * on a C string buffer. + * + * @param str a C string buffer + * @param pos where the signature starts + * @returns the first type in the signature + */ +int +_dbus_first_type_in_signature_c_str (const char *str, + int pos) +{ + return map_type_char_to_type (str[pos]); +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +/** + * Reads a block of fixed-length basic values, as an optimization + * vs. reading each one individually into a new buffer. + * + * This function returns the data in-place; it does not make a copy, + * and it does not swap the bytes. + * + * If you ask for #DBUS_TYPE_DOUBLE you will get a "const double*" back + * and the "value" argument should be a "const double**" and so on. + * + * @param str the string to read from + * @param pos position to read from + * @param element_type type of array elements + * @param value place to return the array + * @param n_elements number of array elements to read + * @param byte_order the byte order, used to read the array length + * @param new_pos #NULL or location to store a position after the elements + */ +void +_dbus_marshal_read_fixed_multi (const DBusString *str, + int pos, + int element_type, + void *value, + int n_elements, + int byte_order, + int *new_pos) +{ + int array_len; + int alignment; + + _dbus_assert (dbus_type_is_fixed (element_type)); + _dbus_assert (dbus_type_is_basic (element_type)); + +#if 0 + _dbus_verbose ("reading %d elements of %s\n", + n_elements, _dbus_type_to_string (element_type)); +#endif + + alignment = _dbus_type_get_alignment (element_type); + + pos = _DBUS_ALIGN_VALUE (pos, alignment); + + array_len = n_elements * alignment; + + *(const DBusBasicValue**) value = (void*) _dbus_string_get_const_data_len (str, pos, array_len); + if (new_pos) + *new_pos = pos + array_len; +} + +static void +swap_test_array (void *array, + int len_bytes, + int byte_order, + int alignment) +{ + DBusString t; + + if (alignment == 1) + return; + + _dbus_string_init_const_len (&t, array, len_bytes); + swap_array (&t, 0, len_bytes / alignment, byte_order, alignment); +} + +#define MARSHAL_BASIC(typename, byte_order, literal) \ + do { \ + v_##typename = literal; \ + if (!_dbus_marshal_write_basic (&str, pos, DBUS_TYPE_##typename, \ + &v_##typename, \ + byte_order, NULL)) \ + _dbus_assert_not_reached ("no memory"); \ + } while (0) + +#define DEMARSHAL_BASIC(typename, byte_order) \ + do { \ + _dbus_marshal_read_basic (&str, pos, DBUS_TYPE_##typename, &v_##typename, \ + byte_order, &pos); \ + } while (0) + +#define DEMARSHAL_BASIC_AND_CHECK(typename, byte_order, literal) \ + do { \ + DEMARSHAL_BASIC (typename, byte_order); \ + if (literal != v_##typename) \ + { \ + _dbus_verbose_bytes_of_string (&str, dump_pos, \ + _dbus_string_get_length (&str) - dump_pos); \ + _dbus_assert_not_reached ("demarshaled wrong value"); \ + } \ + } while (0) + +#define MARSHAL_TEST(typename, byte_order, literal) \ + do { \ + MARSHAL_BASIC (typename, byte_order, literal); \ + dump_pos = pos; \ + DEMARSHAL_BASIC_AND_CHECK (typename, byte_order, literal); \ + } while (0) + +#define MARSHAL_TEST_STRCMP(typename, byte_order, literal) \ + do { \ + MARSHAL_BASIC (typename, byte_order, literal); \ + dump_pos = pos; \ + DEMARSHAL_BASIC (typename, byte_order); \ + if (strcmp (literal, v_##typename) != 0) \ + { \ + _dbus_verbose_bytes_of_string (&str, dump_pos, \ + _dbus_string_get_length (&str) - dump_pos); \ + _dbus_warn ("literal '%s'\nvalue '%s'\n", literal, v_##typename); \ + _dbus_assert_not_reached ("demarshaled wrong value"); \ + } \ + } while (0) + +#define MARSHAL_FIXED_ARRAY(typename, byte_order, literal) \ + do { \ + int next; \ + v_UINT32 = sizeof(literal); \ + if (!_dbus_marshal_write_basic (&str, pos, DBUS_TYPE_UINT32, &v_UINT32, \ + byte_order, &next)) \ + _dbus_assert_not_reached ("no memory"); \ + v_ARRAY_##typename = literal; \ + if (!_dbus_marshal_write_fixed_multi (&str, next, DBUS_TYPE_##typename, \ + &v_ARRAY_##typename, _DBUS_N_ELEMENTS(literal), \ + byte_order, NULL)) \ + _dbus_assert_not_reached ("no memory"); \ + } while (0) + +#define DEMARSHAL_FIXED_ARRAY(typename, byte_order) \ + do { \ + int next; \ + alignment = _dbus_type_get_alignment (DBUS_TYPE_##typename); \ + v_UINT32 = _dbus_marshal_read_uint32 (&str, dump_pos, byte_order, &next); \ + _dbus_marshal_read_fixed_multi (&str, next, DBUS_TYPE_##typename, &v_ARRAY_##typename, \ + v_UINT32/alignment, \ + byte_order, NULL); \ + swap_test_array (v_ARRAY_##typename, v_UINT32, \ + byte_order, alignment); \ + } while (0) + +#define DEMARSHAL_FIXED_ARRAY_AND_CHECK(typename, byte_order, literal) \ + do { \ + DEMARSHAL_FIXED_ARRAY (typename, byte_order); \ + if (memcmp (literal, v_ARRAY_##typename, sizeof (literal) != 0)) \ + { \ + _dbus_verbose ("MARSHALED DATA\n"); \ + _dbus_verbose_bytes_of_string (&str, dump_pos, \ + _dbus_string_get_length (&str) - dump_pos); \ + _dbus_verbose ("LITERAL DATA\n"); \ + _dbus_verbose_bytes ((char*)literal, sizeof (literal), 0); \ + _dbus_verbose ("READ DATA\n"); \ + _dbus_verbose_bytes ((char*)v_ARRAY_##typename, sizeof (literal), 0); \ + _dbus_assert_not_reached ("demarshaled wrong fixed array value"); \ + } \ + } while (0) + +#define MARSHAL_TEST_FIXED_ARRAY(typename, byte_order, literal) \ + do { \ + MARSHAL_FIXED_ARRAY (typename, byte_order, literal); \ + dump_pos = pos; \ + DEMARSHAL_FIXED_ARRAY_AND_CHECK (typename, byte_order, literal); \ + } while (0) + +dbus_bool_t +_dbus_marshal_test (void) +{ + int alignment; + DBusString str; + int pos, dump_pos; + unsigned char array1[5] = { 3, 4, 0, 1, 9 }; + dbus_int16_t array2[3] = { 124, 457, 780 }; + dbus_int32_t array4[3] = { 123, 456, 789 }; +#ifdef DBUS_HAVE_INT64 + dbus_int64_t array8[3] = { DBUS_INT64_CONSTANT (0x123ffffffff), + DBUS_INT64_CONSTANT (0x456ffffffff), + DBUS_INT64_CONSTANT (0x789ffffffff) }; + dbus_int64_t *v_ARRAY_INT64; +#endif + unsigned char *v_ARRAY_BYTE; + dbus_int16_t *v_ARRAY_INT16; + dbus_uint16_t *v_ARRAY_UINT16; + dbus_int32_t *v_ARRAY_INT32; + dbus_uint32_t *v_ARRAY_UINT32; + DBusString t; + double v_DOUBLE; + double t_DOUBLE; + dbus_int16_t v_INT16; + dbus_uint16_t v_UINT16; + dbus_int32_t v_INT32; + dbus_uint32_t v_UINT32; + dbus_int64_t v_INT64; + dbus_uint64_t v_UINT64; + unsigned char v_BYTE; + dbus_bool_t v_BOOLEAN; + const char *v_STRING; + const char *v_SIGNATURE; + const char *v_OBJECT_PATH; + int byte_order; + + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("failed to init string"); + + pos = 0; + + /* Marshal doubles */ + MARSHAL_BASIC (DOUBLE, DBUS_BIG_ENDIAN, 3.14); + DEMARSHAL_BASIC (DOUBLE, DBUS_BIG_ENDIAN); + t_DOUBLE = 3.14; + if (!_DBUS_DOUBLES_BITWISE_EQUAL (t_DOUBLE, v_DOUBLE)) + _dbus_assert_not_reached ("got wrong double value"); + + MARSHAL_BASIC (DOUBLE, DBUS_LITTLE_ENDIAN, 3.14); + DEMARSHAL_BASIC (DOUBLE, DBUS_LITTLE_ENDIAN); + t_DOUBLE = 3.14; + if (!_DBUS_DOUBLES_BITWISE_EQUAL (t_DOUBLE, v_DOUBLE)) + _dbus_assert_not_reached ("got wrong double value"); + + /* Marshal signed 16 integers */ + MARSHAL_TEST (INT16, DBUS_BIG_ENDIAN, -12345); + MARSHAL_TEST (INT16, DBUS_LITTLE_ENDIAN, -12345); + + /* Marshal unsigned 16 integers */ + MARSHAL_TEST (UINT16, DBUS_BIG_ENDIAN, 0x1234); + MARSHAL_TEST (UINT16, DBUS_LITTLE_ENDIAN, 0x1234); + + /* Marshal signed integers */ + MARSHAL_TEST (INT32, DBUS_BIG_ENDIAN, -12345678); + MARSHAL_TEST (INT32, DBUS_LITTLE_ENDIAN, -12345678); + + /* Marshal unsigned integers */ + MARSHAL_TEST (UINT32, DBUS_BIG_ENDIAN, 0x12345678); + MARSHAL_TEST (UINT32, DBUS_LITTLE_ENDIAN, 0x12345678); + +#ifdef DBUS_HAVE_INT64 + /* Marshal signed integers */ + MARSHAL_TEST (INT64, DBUS_BIG_ENDIAN, DBUS_INT64_CONSTANT (-0x123456789abc7)); + MARSHAL_TEST (INT64, DBUS_LITTLE_ENDIAN, DBUS_INT64_CONSTANT (-0x123456789abc7)); + + /* Marshal unsigned integers */ + MARSHAL_TEST (UINT64, DBUS_BIG_ENDIAN, DBUS_UINT64_CONSTANT (0x123456789abc7)); + MARSHAL_TEST (UINT64, DBUS_LITTLE_ENDIAN, DBUS_UINT64_CONSTANT (0x123456789abc7)); +#endif /* DBUS_HAVE_INT64 */ + + /* Marshal byte */ + MARSHAL_TEST (BYTE, DBUS_BIG_ENDIAN, 5); + MARSHAL_TEST (BYTE, DBUS_LITTLE_ENDIAN, 5); + + /* Marshal all possible bools! */ + MARSHAL_TEST (BOOLEAN, DBUS_BIG_ENDIAN, FALSE); + MARSHAL_TEST (BOOLEAN, DBUS_LITTLE_ENDIAN, FALSE); + MARSHAL_TEST (BOOLEAN, DBUS_BIG_ENDIAN, TRUE); + MARSHAL_TEST (BOOLEAN, DBUS_LITTLE_ENDIAN, TRUE); + + /* Marshal strings */ + MARSHAL_TEST_STRCMP (STRING, DBUS_BIG_ENDIAN, ""); + MARSHAL_TEST_STRCMP (STRING, DBUS_LITTLE_ENDIAN, ""); + MARSHAL_TEST_STRCMP (STRING, DBUS_BIG_ENDIAN, "This is the dbus test string"); + MARSHAL_TEST_STRCMP (STRING, DBUS_LITTLE_ENDIAN, "This is the dbus test string"); + + /* object paths */ + MARSHAL_TEST_STRCMP (OBJECT_PATH, DBUS_BIG_ENDIAN, "/a/b/c"); + MARSHAL_TEST_STRCMP (OBJECT_PATH, DBUS_LITTLE_ENDIAN, "/a/b/c"); + + /* signatures */ + MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_BIG_ENDIAN, ""); + MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_LITTLE_ENDIAN, ""); + MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_BIG_ENDIAN, "a(ii)"); + MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_LITTLE_ENDIAN, "a(ii)"); + + /* Arrays */ + MARSHAL_TEST_FIXED_ARRAY (INT16, DBUS_BIG_ENDIAN, array2); + MARSHAL_TEST_FIXED_ARRAY (INT16, DBUS_LITTLE_ENDIAN, array2); + MARSHAL_TEST_FIXED_ARRAY (UINT16, DBUS_BIG_ENDIAN, array2); + MARSHAL_TEST_FIXED_ARRAY (UINT16, DBUS_LITTLE_ENDIAN, array2); + + MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_BIG_ENDIAN, array4); + MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_LITTLE_ENDIAN, array4); + MARSHAL_TEST_FIXED_ARRAY (UINT32, DBUS_BIG_ENDIAN, array4); + MARSHAL_TEST_FIXED_ARRAY (UINT32, DBUS_LITTLE_ENDIAN, array4); + + MARSHAL_TEST_FIXED_ARRAY (BYTE, DBUS_BIG_ENDIAN, array1); + MARSHAL_TEST_FIXED_ARRAY (BYTE, DBUS_LITTLE_ENDIAN, array1); + +#ifdef DBUS_HAVE_INT64 + MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_BIG_ENDIAN, array8); + MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_LITTLE_ENDIAN, array8); +#endif + +#if 0 + + /* + * FIXME restore the set/pack tests + */ + +#ifdef DBUS_HAVE_INT64 + /* set/pack 64-bit integers */ + _dbus_string_set_length (&str, 8); + + /* signed little */ + _dbus_marshal_set_int64 (&str, DBUS_LITTLE_ENDIAN, + 0, DBUS_INT64_CONSTANT (-0x123456789abc7)); + + _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) == + _dbus_unpack_int64 (DBUS_LITTLE_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* signed big */ + _dbus_marshal_set_int64 (&str, DBUS_BIG_ENDIAN, + 0, DBUS_INT64_CONSTANT (-0x123456789abc7)); + + _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) == + _dbus_unpack_int64 (DBUS_BIG_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* signed little pack */ + _dbus_pack_int64 (DBUS_INT64_CONSTANT (-0x123456789abc7), + DBUS_LITTLE_ENDIAN, + _dbus_string_get_data (&str)); + + _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) == + _dbus_unpack_int64 (DBUS_LITTLE_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* signed big pack */ + _dbus_pack_int64 (DBUS_INT64_CONSTANT (-0x123456789abc7), + DBUS_BIG_ENDIAN, + _dbus_string_get_data (&str)); + + _dbus_assert (DBUS_INT64_CONSTANT (-0x123456789abc7) == + _dbus_unpack_int64 (DBUS_BIG_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* unsigned little */ + _dbus_marshal_set_uint64 (&str, DBUS_LITTLE_ENDIAN, + 0, DBUS_UINT64_CONSTANT (0x123456789abc7)); + + _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) == + _dbus_unpack_uint64 (DBUS_LITTLE_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* unsigned big */ + _dbus_marshal_set_uint64 (&str, DBUS_BIG_ENDIAN, + 0, DBUS_UINT64_CONSTANT (0x123456789abc7)); + + _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) == + _dbus_unpack_uint64 (DBUS_BIG_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* unsigned little pack */ + _dbus_pack_uint64 (DBUS_UINT64_CONSTANT (0x123456789abc7), + DBUS_LITTLE_ENDIAN, + _dbus_string_get_data (&str)); + + _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) == + _dbus_unpack_uint64 (DBUS_LITTLE_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* unsigned big pack */ + _dbus_pack_uint64 (DBUS_UINT64_CONSTANT (0x123456789abc7), + DBUS_BIG_ENDIAN, + _dbus_string_get_data (&str)); + + _dbus_assert (DBUS_UINT64_CONSTANT (0x123456789abc7) == + _dbus_unpack_uint64 (DBUS_BIG_ENDIAN, + _dbus_string_get_const_data (&str))); +#endif /* DBUS_HAVE_INT64 */ + + /* set/pack 32-bit integers */ + _dbus_string_set_length (&str, 4); + + /* signed little */ + _dbus_marshal_set_int32 (&str, DBUS_LITTLE_ENDIAN, + 0, -0x123456); + + _dbus_assert (-0x123456 == + _dbus_unpack_int32 (DBUS_LITTLE_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* signed big */ + _dbus_marshal_set_int32 (&str, DBUS_BIG_ENDIAN, + 0, -0x123456); + + _dbus_assert (-0x123456 == + _dbus_unpack_int32 (DBUS_BIG_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* signed little pack */ + _dbus_pack_int32 (-0x123456, + DBUS_LITTLE_ENDIAN, + _dbus_string_get_data (&str)); + + _dbus_assert (-0x123456 == + _dbus_unpack_int32 (DBUS_LITTLE_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* signed big pack */ + _dbus_pack_int32 (-0x123456, + DBUS_BIG_ENDIAN, + _dbus_string_get_data (&str)); + + _dbus_assert (-0x123456 == + _dbus_unpack_int32 (DBUS_BIG_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* unsigned little */ + _dbus_marshal_set_uint32 (&str, + 0, 0x123456, + DBUS_LITTLE_ENDIAN); + + _dbus_assert (0x123456 == + _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* unsigned big */ + _dbus_marshal_set_uint32 (&str, + 0, 0x123456, + DBUS_BIG_ENDIAN); + + _dbus_assert (0x123456 == + _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* unsigned little pack */ + _dbus_pack_uint32 (0x123456, + DBUS_LITTLE_ENDIAN, + _dbus_string_get_data (&str)); + + _dbus_assert (0x123456 == + _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, + _dbus_string_get_const_data (&str))); + + /* unsigned big pack */ + _dbus_pack_uint32 (0x123456, + DBUS_BIG_ENDIAN, + _dbus_string_get_data (&str)); + + _dbus_assert (0x123456 == + _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, + _dbus_string_get_const_data (&str))); + +#endif /* set/pack tests for integers */ + + /* Strings in-place set */ + byte_order = DBUS_LITTLE_ENDIAN; + while (TRUE) + { + /* Init a string */ + _dbus_string_set_length (&str, 0); + + /* reset pos for the macros */ + pos = 0; + + MARSHAL_TEST_STRCMP (STRING, byte_order, "Hello world"); + + /* Set it to something longer */ + _dbus_string_init_const (&t, "Hello world foo"); + + v_STRING = _dbus_string_get_const_data (&t); + _dbus_marshal_set_basic (&str, 0, DBUS_TYPE_STRING, + &v_STRING, byte_order, NULL, NULL); + + _dbus_marshal_read_basic (&str, 0, DBUS_TYPE_STRING, + &v_STRING, byte_order, + NULL); + _dbus_assert (strcmp (v_STRING, "Hello world foo") == 0); + + /* Set it to something shorter */ + _dbus_string_init_const (&t, "Hello"); + + v_STRING = _dbus_string_get_const_data (&t); + _dbus_marshal_set_basic (&str, 0, DBUS_TYPE_STRING, + &v_STRING, byte_order, NULL, NULL); + _dbus_marshal_read_basic (&str, 0, DBUS_TYPE_STRING, + &v_STRING, byte_order, + NULL); + _dbus_assert (strcmp (v_STRING, "Hello") == 0); + + /* Do the other byte order */ + if (byte_order == DBUS_LITTLE_ENDIAN) + byte_order = DBUS_BIG_ENDIAN; + else + break; + } + + /* Clean up */ + _dbus_string_free (&str); + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-marshal-basic.h b/dbus/dbus-marshal-basic.h new file mode 100644 index 00000000..68ced4d2 --- /dev/null +++ b/dbus/dbus-marshal-basic.h @@ -0,0 +1,261 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-basic.h Marshalling routines for basic (primitive) types + * + * Copyright (C) 2002 CodeFactory AB + * Copyright (C) 2004, 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_MARSHAL_BASIC_H +#define DBUS_MARSHAL_BASIC_H + +#include +#include +#include +#include +#include + +#ifndef PACKAGE +#error "config.h not included here" +#endif + +#ifdef WORDS_BIGENDIAN +#define DBUS_COMPILER_BYTE_ORDER DBUS_BIG_ENDIAN +#else +#define DBUS_COMPILER_BYTE_ORDER DBUS_LITTLE_ENDIAN +#endif + +#define DBUS_UINT16_SWAP_LE_BE_CONSTANT(val) ((dbus_uint16_t) ( \ + (dbus_uint16_t) ((dbus_uint16_t) (val) >> 8) | \ + (dbus_uint16_t) ((dbus_uint16_t) (val) << 8))) + +#define DBUS_UINT32_SWAP_LE_BE_CONSTANT(val) ((dbus_uint32_t) ( \ + (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x000000ffU) << 24) | \ + (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x0000ff00U) << 8) | \ + (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x00ff0000U) >> 8) | \ + (((dbus_uint32_t) (val) & (dbus_uint32_t) 0xff000000U) >> 24))) + +#ifdef DBUS_HAVE_INT64 + +#define DBUS_UINT64_SWAP_LE_BE_CONSTANT(val) ((dbus_uint64_t) ( \ + (((dbus_uint64_t) (val) & \ + (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x00000000000000ff)) << 56) | \ + (((dbus_uint64_t) (val) & \ + (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x000000000000ff00)) << 40) | \ + (((dbus_uint64_t) (val) & \ + (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x0000000000ff0000)) << 24) | \ + (((dbus_uint64_t) (val) & \ + (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x00000000ff000000)) << 8) | \ + (((dbus_uint64_t) (val) & \ + (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x000000ff00000000)) >> 8) | \ + (((dbus_uint64_t) (val) & \ + (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x0000ff0000000000)) >> 24) | \ + (((dbus_uint64_t) (val) & \ + (dbus_uint64_t) DBUS_UINT64_CONSTANT (0x00ff000000000000)) >> 40) | \ + (((dbus_uint64_t) (val) & \ + (dbus_uint64_t) DBUS_UINT64_CONSTANT (0xff00000000000000)) >> 56))) +#endif /* DBUS_HAVE_INT64 */ + +#define DBUS_UINT16_SWAP_LE_BE(val) (DBUS_UINT16_SWAP_LE_BE_CONSTANT (val)) +#define DBUS_INT16_SWAP_LE_BE(val) ((dbus_int16_t)DBUS_UINT16_SWAP_LE_BE_CONSTANT (val)) + +#define DBUS_UINT32_SWAP_LE_BE(val) (DBUS_UINT32_SWAP_LE_BE_CONSTANT (val)) +#define DBUS_INT32_SWAP_LE_BE(val) ((dbus_int32_t)DBUS_UINT32_SWAP_LE_BE_CONSTANT (val)) + +#ifdef DBUS_HAVE_INT64 +# define DBUS_UINT64_SWAP_LE_BE(val) (DBUS_UINT64_SWAP_LE_BE_CONSTANT (val)) +# define DBUS_INT64_SWAP_LE_BE(val) ((dbus_int64_t)DBUS_UINT64_SWAP_LE_BE_CONSTANT (val)) +#endif /* DBUS_HAVE_INT64 */ + +#ifdef WORDS_BIGENDIAN + +# define DBUS_INT16_TO_BE(val) ((dbus_int16_t) (val)) +# define DBUS_UINT16_TO_BE(val) ((dbus_uint16_t) (val)) +# define DBUS_INT16_TO_LE(val) (DBUS_INT16_SWAP_LE_BE (val)) +# define DBUS_UINT16_TO_LE(val) (DBUS_UINT16_SWAP_LE_BE (val)) +# define DBUS_INT32_TO_BE(val) ((dbus_int32_t) (val)) +# define DBUS_UINT32_TO_BE(val) ((dbus_uint32_t) (val)) +# define DBUS_INT32_TO_LE(val) (DBUS_INT32_SWAP_LE_BE (val)) +# define DBUS_UINT32_TO_LE(val) (DBUS_UINT32_SWAP_LE_BE (val)) +# ifdef DBUS_HAVE_INT64 +# define DBUS_INT64_TO_BE(val) ((dbus_int64_t) (val)) +# define DBUS_UINT64_TO_BE(val) ((dbus_uint64_t) (val)) +# define DBUS_INT64_TO_LE(val) (DBUS_INT64_SWAP_LE_BE (val)) +# define DBUS_UINT64_TO_LE(val) (DBUS_UINT64_SWAP_LE_BE (val)) +# endif /* DBUS_HAVE_INT64 */ + +#else /* WORDS_BIGENDIAN */ + +# define DBUS_INT16_TO_LE(val) ((dbus_int16_t) (val)) +# define DBUS_UINT16_TO_LE(val) ((dbus_uint16_t) (val)) +# define DBUS_INT16_TO_BE(val) ((dbus_int16_t) DBUS_UINT16_SWAP_LE_BE (val)) +# define DBUS_UINT16_TO_BE(val) (DBUS_UINT16_SWAP_LE_BE (val)) +# define DBUS_INT32_TO_LE(val) ((dbus_int32_t) (val)) +# define DBUS_UINT32_TO_LE(val) ((dbus_uint32_t) (val)) +# define DBUS_INT32_TO_BE(val) ((dbus_int32_t) DBUS_UINT32_SWAP_LE_BE (val)) +# define DBUS_UINT32_TO_BE(val) (DBUS_UINT32_SWAP_LE_BE (val)) +# ifdef DBUS_HAVE_INT64 +# define DBUS_INT64_TO_LE(val) ((dbus_int64_t) (val)) +# define DBUS_UINT64_TO_LE(val) ((dbus_uint64_t) (val)) +# define DBUS_INT64_TO_BE(val) ((dbus_int64_t) DBUS_UINT64_SWAP_LE_BE (val)) +# define DBUS_UINT64_TO_BE(val) (DBUS_UINT64_SWAP_LE_BE (val)) +# endif /* DBUS_HAVE_INT64 */ +#endif + +/* The transformation is symmetric, so the FROM just maps to the TO. */ +#define DBUS_INT16_FROM_LE(val) (DBUS_INT16_TO_LE (val)) +#define DBUS_UINT16_FROM_LE(val) (DBUS_UINT16_TO_LE (val)) +#define DBUS_INT16_FROM_BE(val) (DBUS_INT16_TO_BE (val)) +#define DBUS_UINT16_FROM_BE(val) (DBUS_UINT16_TO_BE (val)) +#define DBUS_INT32_FROM_LE(val) (DBUS_INT32_TO_LE (val)) +#define DBUS_UINT32_FROM_LE(val) (DBUS_UINT32_TO_LE (val)) +#define DBUS_INT32_FROM_BE(val) (DBUS_INT32_TO_BE (val)) +#define DBUS_UINT32_FROM_BE(val) (DBUS_UINT32_TO_BE (val)) +#ifdef DBUS_HAVE_INT64 +# define DBUS_INT64_FROM_LE(val) (DBUS_INT64_TO_LE (val)) +# define DBUS_UINT64_FROM_LE(val) (DBUS_UINT64_TO_LE (val)) +# define DBUS_INT64_FROM_BE(val) (DBUS_INT64_TO_BE (val)) +# define DBUS_UINT64_FROM_BE(val) (DBUS_UINT64_TO_BE (val)) +#endif /* DBUS_HAVE_INT64 */ + +#ifndef DBUS_HAVE_INT64 +/** + * An 8-byte struct you could use to access int64 without having + * int64 support + */ +typedef struct +{ + dbus_uint32_t first32; /**< first 32 bits in the 8 bytes (beware endian issues) */ + dbus_uint32_t second32; /**< second 32 bits in the 8 bytes (beware endian issues) */ +} DBus8ByteStruct; +#endif /* DBUS_HAVE_INT64 */ + +/** + * A simple 8-byte value union that lets you access 8 bytes as if they + * were various types; useful when dealing with basic types via + * void pointers and varargs. + */ +typedef union +{ + dbus_int16_t i16; /**< as int16 */ + dbus_uint16_t u16; /**< as int16 */ + dbus_int32_t i32; /**< as int32 */ + dbus_uint32_t u32; /**< as int32 */ +#ifdef DBUS_HAVE_INT64 + dbus_int64_t i64; /**< as int64 */ + dbus_uint64_t u64; /**< as int64 */ +#else + DBus8ByteStruct u64; /**< as 8-byte-struct */ +#endif + double dbl; /**< as double */ + unsigned char byt; /**< as byte */ + char *str; /**< as char* */ +} DBusBasicValue; + +#ifdef DBUS_DISABLE_ASSERT +#define _dbus_unpack_uint16(byte_order, data) \ + (((byte_order) == DBUS_LITTLE_ENDIAN) ? \ + DBUS_UINT16_FROM_LE (*(dbus_uint16_t*)(data)) : \ + DBUS_UINT16_FROM_BE (*(dbus_uint16_t*)(data))) + +#define _dbus_unpack_uint32(byte_order, data) \ + (((byte_order) == DBUS_LITTLE_ENDIAN) ? \ + DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)(data)) : \ + DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)(data))) +#endif + +#ifndef _dbus_unpack_uint16 +dbus_uint16_t _dbus_unpack_uint16 (int byte_order, + const unsigned char *data); +#endif + +void _dbus_pack_uint32 (dbus_uint32_t value, + int byte_order, + unsigned char *data); +#ifndef _dbus_unpack_uint32 +dbus_uint32_t _dbus_unpack_uint32 (int byte_order, + const unsigned char *data); +#endif + +dbus_bool_t _dbus_marshal_set_basic (DBusString *str, + int pos, + int type, + const void *value, + int byte_order, + int *old_end_pos, + int *new_end_pos); +dbus_bool_t _dbus_marshal_write_basic (DBusString *str, + int insert_at, + int type, + const void *value, + int byte_order, + int *pos_after); +dbus_bool_t _dbus_marshal_write_fixed_multi (DBusString *str, + int insert_at, + int element_type, + const void *value, + int n_elements, + int byte_order, + int *pos_after); +void _dbus_marshal_read_basic (const DBusString *str, + int pos, + int type, + void *value, + int byte_order, + int *new_pos); +void _dbus_marshal_read_fixed_multi (const DBusString *str, + int pos, + int element_type, + void *value, + int n_elements, + int byte_order, + int *new_pos); +void _dbus_marshal_skip_basic (const DBusString *str, + int type, + int byte_order, + int *pos); +void _dbus_marshal_skip_array (const DBusString *str, + int element_type, + int byte_order, + int *pos); +void _dbus_marshal_set_uint32 (DBusString *str, + int pos, + dbus_uint32_t value, + int byte_order); +dbus_uint32_t _dbus_marshal_read_uint32 (const DBusString *str, + int pos, + int byte_order, + int *new_pos); +dbus_bool_t _dbus_type_is_valid (int typecode); +int _dbus_type_get_alignment (int typecode); +dbus_bool_t _dbus_type_is_fixed (int typecode); +int _dbus_type_get_alignment (int typecode); +const char* _dbus_type_to_string (int typecode); + +int _dbus_first_type_in_signature (const DBusString *str, + int pos); + +int _dbus_first_type_in_signature_c_str (const char *str, + int pos); + +void _dbus_swap_array (unsigned char *data, + int n_elements, + int alignment); + +#endif /* DBUS_MARSHAL_BASIC_H */ diff --git a/dbus/dbus-marshal-byteswap-util.c b/dbus/dbus-marshal-byteswap-util.c new file mode 100644 index 00000000..edb74cad --- /dev/null +++ b/dbus/dbus-marshal-byteswap-util.c @@ -0,0 +1,105 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-byteswap-util.c Would be in dbus-marshal-byteswap.c but tests/bus only + * + * Copyright (C) 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#ifdef DBUS_BUILD_TESTS +#include "dbus-marshal-byteswap.h" +#include "dbus-test.h" +#include + +static void +do_byteswap_test (int byte_order) +{ + int sequence; + DBusString signature; + DBusString body; + int opposite_order; + + if (!_dbus_string_init (&signature) || !_dbus_string_init (&body)) + _dbus_assert_not_reached ("oom"); + + opposite_order = byte_order == DBUS_LITTLE_ENDIAN ? DBUS_BIG_ENDIAN : DBUS_LITTLE_ENDIAN; + + sequence = 0; + while (dbus_internal_do_not_use_generate_bodies (sequence, + byte_order, + &signature, &body)) + { + DBusString copy; + DBusTypeReader body_reader; + DBusTypeReader copy_reader; + + if (!_dbus_string_init (©)) + _dbus_assert_not_reached ("oom"); + + if (!_dbus_string_copy (&body, 0, ©, 0)) + _dbus_assert_not_reached ("oom"); + + _dbus_marshal_byteswap (&signature, 0, + byte_order, + opposite_order, + ©, 0); + + _dbus_type_reader_init (&body_reader, byte_order, &signature, 0, + &body, 0); + _dbus_type_reader_init (©_reader, opposite_order, &signature, 0, + ©, 0); + + if (!_dbus_type_reader_equal_values (&body_reader, ©_reader)) + { + _dbus_verbose_bytes_of_string (&signature, 0, + _dbus_string_get_length (&signature)); + _dbus_verbose_bytes_of_string (&body, 0, + _dbus_string_get_length (&body)); + _dbus_verbose_bytes_of_string (©, 0, + _dbus_string_get_length (©)); + + _dbus_warn ("Byte-swapped data did not have same values as original data\n"); + _dbus_assert_not_reached ("test failed"); + } + + _dbus_string_free (©); + + _dbus_string_set_length (&signature, 0); + _dbus_string_set_length (&body, 0); + ++sequence; + } + + _dbus_string_free (&signature); + _dbus_string_free (&body); + + printf (" %d blocks swapped from order '%c' to '%c'\n", + sequence, byte_order, opposite_order); +} + +dbus_bool_t +_dbus_marshal_byteswap_test (void) +{ + do_byteswap_test (DBUS_LITTLE_ENDIAN); + do_byteswap_test (DBUS_BIG_ENDIAN); + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-marshal-byteswap.c b/dbus/dbus-marshal-byteswap.c new file mode 100644 index 00000000..6af5e5e4 --- /dev/null +++ b/dbus/dbus-marshal-byteswap.c @@ -0,0 +1,246 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-byteswap.c Swap a block of marshaled data + * + * Copyright (C) 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-marshal-byteswap.h" +#include "dbus-marshal-basic.h" +#include "dbus-signature.h" + +/** + * @addtogroup DBusMarshal + * @{ + */ + +static void +byteswap_body_helper (DBusTypeReader *reader, + dbus_bool_t walk_reader_to_end, + int old_byte_order, + int new_byte_order, + unsigned char *p, + unsigned char **new_p) +{ + int current_type; + + while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID) + { + switch (current_type) + { + case DBUS_TYPE_BYTE: + ++p; + break; + + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + { + p = _DBUS_ALIGN_ADDRESS (p, 2); + *((dbus_uint16_t*)p) = DBUS_UINT16_SWAP_LE_BE (*((dbus_uint16_t*)p)); + p += 2; + } + break; + + case DBUS_TYPE_BOOLEAN: + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + { + p = _DBUS_ALIGN_ADDRESS (p, 4); + *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p)); + p += 4; + } + break; + + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + { + p = _DBUS_ALIGN_ADDRESS (p, 8); +#ifdef DBUS_HAVE_INT64 + *((dbus_uint64_t*)p) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)p)); +#else + _dbus_swap_array (p, 1, 8); +#endif + p += 8; + } + break; + + case DBUS_TYPE_ARRAY: + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + { + dbus_uint32_t array_len; + + p = _DBUS_ALIGN_ADDRESS (p, 4); + + array_len = _dbus_unpack_uint32 (old_byte_order, p); + + *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p)); + p += 4; + + if (current_type == DBUS_TYPE_ARRAY) + { + int elem_type; + int alignment; + + elem_type = _dbus_type_reader_get_element_type (reader); + alignment = _dbus_type_get_alignment (elem_type); + + _dbus_assert ((array_len / alignment) < DBUS_MAXIMUM_ARRAY_LENGTH); + + p = _DBUS_ALIGN_ADDRESS (p, alignment); + + if (dbus_type_is_fixed (elem_type)) + { + if (alignment > 1) + _dbus_swap_array (p, array_len / alignment, alignment); + p += array_len; + } + else + { + DBusTypeReader sub; + const unsigned char *array_end; + + array_end = p + array_len; + + _dbus_type_reader_recurse (reader, &sub); + + while (p < array_end) + { + byteswap_body_helper (&sub, + FALSE, + old_byte_order, + new_byte_order, + p, &p); + } + } + } + else + { + _dbus_assert (current_type == DBUS_TYPE_STRING || + current_type == DBUS_TYPE_OBJECT_PATH); + + p += (array_len + 1); /* + 1 for nul */ + } + } + break; + + case DBUS_TYPE_SIGNATURE: + { + dbus_uint32_t sig_len; + + sig_len = *p; + + p += (sig_len + 2); /* +2 for len and nul */ + } + break; + + case DBUS_TYPE_VARIANT: + { + /* 1 byte sig len, sig typecodes, align to + * contained-type-boundary, values. + */ + dbus_uint32_t sig_len; + DBusString sig; + DBusTypeReader sub; + int contained_alignment; + + sig_len = *p; + ++p; + + _dbus_string_init_const_len (&sig, p, sig_len); + + p += (sig_len + 1); /* 1 for nul */ + + contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (&sig, 0)); + + p = _DBUS_ALIGN_ADDRESS (p, contained_alignment); + + _dbus_type_reader_init_types_only (&sub, &sig, 0); + + byteswap_body_helper (&sub, FALSE, old_byte_order, new_byte_order, p, &p); + } + break; + + case DBUS_TYPE_STRUCT: + case DBUS_TYPE_DICT_ENTRY: + { + DBusTypeReader sub; + + p = _DBUS_ALIGN_ADDRESS (p, 8); + + _dbus_type_reader_recurse (reader, &sub); + + byteswap_body_helper (&sub, TRUE, old_byte_order, new_byte_order, p, &p); + } + break; + + default: + _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature"); + break; + } + + if (walk_reader_to_end) + _dbus_type_reader_next (reader); + else + break; + } + + if (new_p) + *new_p = p; +} + +/** + * Byteswaps the marshaled data in the given value_str. + * + * @param signature the types in the value_str + * @param signature_start where in signature is the signature + * @param old_byte_order the old byte order + * @param new_byte_order the new byte order + * @param value_str the string containing the body + * @param value_pos where the values start + */ +void +_dbus_marshal_byteswap (const DBusString *signature, + int signature_start, + int old_byte_order, + int new_byte_order, + DBusString *value_str, + int value_pos) +{ + DBusTypeReader reader; + + _dbus_assert (value_pos >= 0); + _dbus_assert (value_pos <= _dbus_string_get_length (value_str)); + + if (old_byte_order == new_byte_order) + return; + + _dbus_type_reader_init_types_only (&reader, + signature, signature_start); + + byteswap_body_helper (&reader, TRUE, + old_byte_order, new_byte_order, + _dbus_string_get_data_len (value_str, value_pos, 0), + NULL); +} + +/** @} */ + +/* Tests in dbus-marshal-byteswap-util.c */ diff --git a/dbus/dbus-marshal-byteswap.h b/dbus/dbus-marshal-byteswap.h new file mode 100644 index 00000000..764e353d --- /dev/null +++ b/dbus/dbus-marshal-byteswap.h @@ -0,0 +1,42 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-byteswap.h Swap a block of marshaled data + * + * Copyright (C) 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_MARSHAL_BYTESWAP_H +#define DBUS_MARSHAL_BYTESWAP_H + +#include +#include +#include + +#ifndef PACKAGE +#error "config.h not included here" +#endif + +void _dbus_marshal_byteswap (const DBusString *signature, + int signature_start, + int old_byte_order, + int new_byte_order, + DBusString *value_str, + int value_pos); + +#endif /* DBUS_MARSHAL_BYTESWAP_H */ diff --git a/dbus/dbus-marshal-header.c b/dbus/dbus-marshal-header.c new file mode 100644 index 00000000..ec98a5ee --- /dev/null +++ b/dbus/dbus-marshal-header.c @@ -0,0 +1,1489 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-header.c Managing marshaling/demarshaling of message headers + * + * Copyright (C) 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus/dbus-shared.h" +#include "dbus-marshal-header.h" +#include "dbus-marshal-recursive.h" +#include "dbus-marshal-byteswap.h" + +/** + * @addtogroup DBusMarshal + * + * @{ + */ + + +/* Not thread locked, but strictly const/read-only so should be OK + */ +/** Static #DBusString containing the signature of a message header */ +_DBUS_STRING_DEFINE_STATIC(_dbus_header_signature_str, DBUS_HEADER_SIGNATURE); +/** Static #DBusString containing the local interface */ +_DBUS_STRING_DEFINE_STATIC(_dbus_local_interface_str, DBUS_INTERFACE_LOCAL); +/** Static #DBusString containing the local path */ +_DBUS_STRING_DEFINE_STATIC(_dbus_local_path_str, DBUS_PATH_LOCAL); + +/** Offset from start of _dbus_header_signature_str to the signature of the fields array */ +#define FIELDS_ARRAY_SIGNATURE_OFFSET 6 +/** Offset from start of _dbus_header_signature_str to the signature of an element of the fields array */ +#define FIELDS_ARRAY_ELEMENT_SIGNATURE_OFFSET 7 + + +/** Offset to byte order from start of header */ +#define BYTE_ORDER_OFFSET 0 +/** Offset to type from start of header */ +#define TYPE_OFFSET 1 +/** Offset to flags from start of header */ +#define FLAGS_OFFSET 2 +/** Offset to version from start of header */ +#define VERSION_OFFSET 3 +/** Offset to body length from start of header */ +#define BODY_LENGTH_OFFSET 4 +/** Offset to client serial from start of header */ +#define SERIAL_OFFSET 8 +/** Offset to fields array length from start of header */ +#define FIELDS_ARRAY_LENGTH_OFFSET 12 +/** Offset to first field in header */ +#define FIRST_FIELD_OFFSET 16 + +typedef struct +{ + unsigned char code; /**< the field code */ + unsigned char type; /**< the value type */ +} HeaderFieldType; + +static const HeaderFieldType +_dbus_header_field_types[DBUS_HEADER_FIELD_LAST+1] = { + { DBUS_HEADER_FIELD_INVALID, DBUS_TYPE_INVALID }, + { DBUS_HEADER_FIELD_PATH, DBUS_TYPE_OBJECT_PATH }, + { DBUS_HEADER_FIELD_INTERFACE, DBUS_TYPE_STRING }, + { DBUS_HEADER_FIELD_MEMBER, DBUS_TYPE_STRING }, + { DBUS_HEADER_FIELD_ERROR_NAME, DBUS_TYPE_STRING }, + { DBUS_HEADER_FIELD_REPLY_SERIAL, DBUS_TYPE_UINT32 }, + { DBUS_HEADER_FIELD_DESTINATION, DBUS_TYPE_STRING }, + { DBUS_HEADER_FIELD_SENDER, DBUS_TYPE_STRING }, + { DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE } +}; + +/** Macro to look up the correct type for a field */ +#define EXPECTED_TYPE_OF_FIELD(field) (_dbus_header_field_types[field].type) + +/** The most padding we could ever need for a header */ +#define MAX_POSSIBLE_HEADER_PADDING 7 +static dbus_bool_t +reserve_header_padding (DBusHeader *header) +{ + _dbus_assert (header->padding <= MAX_POSSIBLE_HEADER_PADDING); + + if (!_dbus_string_lengthen (&header->data, + MAX_POSSIBLE_HEADER_PADDING - header->padding)) + return FALSE; + header->padding = MAX_POSSIBLE_HEADER_PADDING; + return TRUE; +} + +static void +correct_header_padding (DBusHeader *header) +{ + int unpadded_len; + + _dbus_assert (header->padding == 7); + + _dbus_string_shorten (&header->data, header->padding); + unpadded_len = _dbus_string_get_length (&header->data); + + if (!_dbus_string_align_length (&header->data, 8)) + _dbus_assert_not_reached ("couldn't pad header though enough padding was preallocated"); + + header->padding = _dbus_string_get_length (&header->data) - unpadded_len; +} + +/** Compute the end of the header, ignoring padding */ +#define HEADER_END_BEFORE_PADDING(header) \ + (_dbus_string_get_length (&(header)->data) - (header)->padding) + +/** + * Invalidates all fields in the cache. This may be used when the + * cache is totally uninitialized (contains junk) so should not + * look at what's in there now. + * + * @param header the header + */ +static void +_dbus_header_cache_invalidate_all (DBusHeader *header) +{ + int i; + + i = 0; + while (i <= DBUS_HEADER_FIELD_LAST) + { + header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_UNKNOWN; + ++i; + } +} + +/** + * Caches one field + * + * @param header the header + * @param field_code the field + * @param variant_reader the reader for the variant in the field + */ +static void +_dbus_header_cache_one (DBusHeader *header, + int field_code, + DBusTypeReader *variant_reader) +{ + header->fields[field_code].value_pos = + _dbus_type_reader_get_value_pos (variant_reader); + +#if 0 + _dbus_verbose ("cached value_pos %d for field %d\n", + header->fields[field_code].value_pos, field_code) +#endif +} + +/** + * Revalidates the fields cache + * + * @param header the header + */ +static void +_dbus_header_cache_revalidate (DBusHeader *header) +{ + DBusTypeReader array; + DBusTypeReader reader; + int i; + + i = 0; + while (i <= DBUS_HEADER_FIELD_LAST) + { + header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT; + ++i; + } + + _dbus_type_reader_init (&reader, + header->byte_order, + &_dbus_header_signature_str, + FIELDS_ARRAY_SIGNATURE_OFFSET, + &header->data, + FIELDS_ARRAY_LENGTH_OFFSET); + + _dbus_type_reader_recurse (&reader, &array); + + while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID) + { + DBusTypeReader sub; + DBusTypeReader variant; + unsigned char field_code; + + _dbus_type_reader_recurse (&array, &sub); + + _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE); + _dbus_type_reader_read_basic (&sub, &field_code); + + /* Unknown fields should be ignored */ + if (field_code > DBUS_HEADER_FIELD_LAST) + goto next_field; + + _dbus_type_reader_next (&sub); + + _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_VARIANT); + _dbus_type_reader_recurse (&sub, &variant); + + _dbus_header_cache_one (header, field_code, &variant); + + next_field: + _dbus_type_reader_next (&array); + } +} + +/** + * Checks for a field, updating the cache if required. + * + * @param header the header + * @param field the field to check + * @returns #FALSE if the field doesn't exist + */ +static dbus_bool_t +_dbus_header_cache_check (DBusHeader *header, + int field) +{ + _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); + + if (header->fields[field].value_pos == _DBUS_HEADER_FIELD_VALUE_UNKNOWN) + _dbus_header_cache_revalidate (header); + + if (header->fields[field].value_pos == _DBUS_HEADER_FIELD_VALUE_NONEXISTENT) + return FALSE; + + return TRUE; +} + +/** + * Checks whether a field is known not to exist. It may exist + * even if it's not known to exist. + * + * @param header the header + * @param field the field to check + * @returns #FALSE if the field definitely doesn't exist + */ +static dbus_bool_t +_dbus_header_cache_known_nonexistent (DBusHeader *header, + int field) +{ + _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); + + return (header->fields[field].value_pos == _DBUS_HEADER_FIELD_VALUE_NONEXISTENT); +} + +/** + * Writes a struct of { byte, variant } with the given basic type. + * + * @param writer the writer (should be ready to write a struct) + * @param type the type of the value + * @param value the value as for _dbus_marshal_set_basic() + * @returns #FALSE if no memory + */ +static dbus_bool_t +write_basic_field (DBusTypeWriter *writer, + int field, + int type, + const void *value) +{ + DBusTypeWriter sub; + DBusTypeWriter variant; + int start; + int padding; + unsigned char field_byte; + DBusString contained_type; + char buf[2]; + + start = writer->value_pos; + padding = _dbus_string_get_length (writer->value_str) - start; + + if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT, + NULL, 0, &sub)) + goto append_failed; + + field_byte = field; + if (!_dbus_type_writer_write_basic (&sub, DBUS_TYPE_BYTE, + &field_byte)) + goto append_failed; + + buf[0] = type; + buf[1] = '\0'; + _dbus_string_init_const_len (&contained_type, buf, 1); + + if (!_dbus_type_writer_recurse (&sub, DBUS_TYPE_VARIANT, + &contained_type, 0, &variant)) + goto append_failed; + + if (!_dbus_type_writer_write_basic (&variant, type, value)) + goto append_failed; + + if (!_dbus_type_writer_unrecurse (&sub, &variant)) + goto append_failed; + + if (!_dbus_type_writer_unrecurse (writer, &sub)) + goto append_failed; + + return TRUE; + + append_failed: + _dbus_string_delete (writer->value_str, + start, + _dbus_string_get_length (writer->value_str) - start - padding); + return FALSE; +} + +/** + * Sets a struct of { byte, variant } with the given basic type. + * + * @param reader the reader (should be iterating over the array pointing at the field to set) + * @param type the type of the value + * @param value the value as for _dbus_marshal_set_basic() + * @param realign_root where to realign from + * @returns #FALSE if no memory + */ +static dbus_bool_t +set_basic_field (DBusTypeReader *reader, + int field, + int type, + const void *value, + const DBusTypeReader *realign_root) +{ + DBusTypeReader sub; + DBusTypeReader variant; + + _dbus_type_reader_recurse (reader, &sub); + + _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE); +#ifndef DBUS_DISABLE_ASSERT + { + unsigned char v_BYTE; + _dbus_type_reader_read_basic (&sub, &v_BYTE); + _dbus_assert (((int) v_BYTE) == field); + } +#endif + + if (!_dbus_type_reader_next (&sub)) + _dbus_assert_not_reached ("no variant field?"); + + _dbus_type_reader_recurse (&sub, &variant); + _dbus_assert (_dbus_type_reader_get_current_type (&variant) == type); + + if (!_dbus_type_reader_set_basic (&variant, value, realign_root)) + return FALSE; + + return TRUE; +} + +/** + * Gets the type of the message. + * + * @param header the header + * @returns the type + */ +int +_dbus_header_get_message_type (DBusHeader *header) +{ + int type; + + type = _dbus_string_get_byte (&header->data, TYPE_OFFSET); + _dbus_assert (type != DBUS_MESSAGE_TYPE_INVALID); + + return type; +} + +/** + * Sets the serial number of a header. This can only be done once on + * a header. + * + * @param header the header + * @param serial the serial + */ +void +_dbus_header_set_serial (DBusHeader *header, + dbus_uint32_t serial) +{ + /* we use this function to set the serial on outgoing + * messages, and to reset the serial in dbus_message_copy; + * this assertion should catch a double-set on outgoing. + */ + _dbus_assert (_dbus_header_get_serial (header) == 0 || + serial == 0); + + _dbus_marshal_set_uint32 (&header->data, + SERIAL_OFFSET, + serial, + header->byte_order); +} + +/** + * See dbus_message_get_serial() + * + * @param header the header + * @returns the client serial + */ +dbus_uint32_t +_dbus_header_get_serial (DBusHeader *header) +{ + return _dbus_marshal_read_uint32 (&header->data, + SERIAL_OFFSET, + header->byte_order, + NULL); +} + +/** + * Re-initializes a header that was previously initialized and never + * freed. After this, to make the header valid you have to call + * _dbus_header_create(). + * + * @param header header to re-initialize + * @param byte_order byte order of the header + */ +void +_dbus_header_reinit (DBusHeader *header, + int byte_order) +{ + _dbus_string_set_length (&header->data, 0); + + header->byte_order = byte_order; + header->padding = 0; + + _dbus_header_cache_invalidate_all (header); +} + +/** + * Initializes a header, but doesn't prepare it for use; + * to make the header valid, you have to call _dbus_header_create(). + * + * @param header header to initialize + * @param byte_order byte order of the header + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_header_init (DBusHeader *header, + int byte_order) +{ + if (!_dbus_string_init_preallocated (&header->data, 32)) + return FALSE; + + _dbus_header_reinit (header, byte_order); + + return TRUE; +} + +/** + * Frees a header. + * + * @param header the header + */ +void +_dbus_header_free (DBusHeader *header) +{ + _dbus_string_free (&header->data); +} + +/** + * Initializes dest with a copy of the given header. + * Resets the message serial to 0 on the copy. + * + * @param header header to copy + * @param dest destination for copy + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_header_copy (const DBusHeader *header, + DBusHeader *dest) +{ + *dest = *header; + + if (!_dbus_string_init_preallocated (&dest->data, + _dbus_string_get_length (&header->data))) + return FALSE; + + if (!_dbus_string_copy (&header->data, 0, &dest->data, 0)) + { + _dbus_string_free (&dest->data); + return FALSE; + } + + /* Reset the serial */ + _dbus_header_set_serial (dest, 0); + + return TRUE; +} + +/** + * Fills in the primary fields of the header, so the header is ready + * for use. #NULL may be specified for some or all of the fields to + * avoid adding those fields. Some combinations of fields don't make + * sense, and passing them in will trigger an assertion failure. + * + * @param header the header + * @param message_type the message type + * @param destination destination field or #NULL + * @param path path field or #NULL + * @param interface interface field or #NULL + * @param member member field or #NULL + * @param error_name error name or #NULL + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_header_create (DBusHeader *header, + int message_type, + const char *destination, + const char *path, + const char *interface, + const char *member, + const char *error_name) +{ + unsigned char v_BYTE; + dbus_uint32_t v_UINT32; + DBusTypeWriter writer; + DBusTypeWriter array; + + _dbus_assert (((interface || message_type != DBUS_MESSAGE_TYPE_SIGNAL) && member) || + (error_name) || + !(interface || member || error_name)); + _dbus_assert (_dbus_string_get_length (&header->data) == 0); + + if (!reserve_header_padding (header)) + return FALSE; + + _dbus_type_writer_init_values_only (&writer, header->byte_order, + &_dbus_header_signature_str, 0, + &header->data, + HEADER_END_BEFORE_PADDING (header)); + + v_BYTE = header->byte_order; + if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE, + &v_BYTE)) + goto oom; + + v_BYTE = message_type; + if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE, + &v_BYTE)) + goto oom; + + v_BYTE = 0; /* flags */ + if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE, + &v_BYTE)) + goto oom; + + v_BYTE = DBUS_MAJOR_PROTOCOL_VERSION; + if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE, + &v_BYTE)) + goto oom; + + v_UINT32 = 0; /* body length */ + if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_UINT32, + &v_UINT32)) + goto oom; + + v_UINT32 = 0; /* serial */ + if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_UINT32, + &v_UINT32)) + goto oom; + + if (!_dbus_type_writer_recurse (&writer, DBUS_TYPE_ARRAY, + &_dbus_header_signature_str, + FIELDS_ARRAY_SIGNATURE_OFFSET, + &array)) + goto oom; + + /* Marshal all the fields (Marshall Fields?) */ + + if (path != NULL) + { + if (!write_basic_field (&array, + DBUS_HEADER_FIELD_PATH, + DBUS_TYPE_OBJECT_PATH, + &path)) + goto oom; + } + + if (destination != NULL) + { + if (!write_basic_field (&array, + DBUS_HEADER_FIELD_DESTINATION, + DBUS_TYPE_STRING, + &destination)) + goto oom; + } + + if (interface != NULL) + { + if (!write_basic_field (&array, + DBUS_HEADER_FIELD_INTERFACE, + DBUS_TYPE_STRING, + &interface)) + goto oom; + } + + if (member != NULL) + { + if (!write_basic_field (&array, + DBUS_HEADER_FIELD_MEMBER, + DBUS_TYPE_STRING, + &member)) + goto oom; + } + + if (error_name != NULL) + { + if (!write_basic_field (&array, + DBUS_HEADER_FIELD_ERROR_NAME, + DBUS_TYPE_STRING, + &error_name)) + goto oom; + } + + if (!_dbus_type_writer_unrecurse (&writer, &array)) + goto oom; + + correct_header_padding (header); + + return TRUE; + + oom: + _dbus_string_delete (&header->data, 0, + _dbus_string_get_length (&header->data) - header->padding); + correct_header_padding (header); + + return FALSE; +} + +/** + * Given data long enough to contain the length of the message body + * and the fields array, check whether the data is long enough to + * contain the entire message (assuming the claimed lengths are + * accurate). Also checks that the lengths are in sanity parameters. + * + * @param max_message_length maximum length of a valid message + * @param validity return location for why the data is invalid if it is + * @param byte_order return location for byte order + * @param fields_array_len return location for claimed fields array length + * @param header_len return location for claimed header length + * @param body_len return location for claimed body length + * @param str the data + * @param start start of data, 8-aligned + * @param len length of data + * @returns #TRUE if the data is long enough for the claimed length, and the lengths were valid + */ +dbus_bool_t +_dbus_header_have_message_untrusted (int max_message_length, + DBusValidity *validity, + int *byte_order, + int *fields_array_len, + int *header_len, + int *body_len, + const DBusString *str, + int start, + int len) + +{ + dbus_uint32_t header_len_unsigned; + dbus_uint32_t fields_array_len_unsigned; + dbus_uint32_t body_len_unsigned; + + _dbus_assert (start >= 0); + _dbus_assert (start < _DBUS_INT32_MAX / 2); + _dbus_assert (len >= 0); + + _dbus_assert (start == (int) _DBUS_ALIGN_VALUE (start, 8)); + + *byte_order = _dbus_string_get_byte (str, start + BYTE_ORDER_OFFSET); + + if (*byte_order != DBUS_LITTLE_ENDIAN && *byte_order != DBUS_BIG_ENDIAN) + { + *validity = DBUS_INVALID_BAD_BYTE_ORDER; + return FALSE; + } + + _dbus_assert (FIELDS_ARRAY_LENGTH_OFFSET + 4 <= len); + fields_array_len_unsigned = _dbus_marshal_read_uint32 (str, start + FIELDS_ARRAY_LENGTH_OFFSET, + *byte_order, NULL); + + if (fields_array_len_unsigned > (unsigned) max_message_length) + { + *validity = DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH; + return FALSE; + } + + _dbus_assert (BODY_LENGTH_OFFSET + 4 < len); + body_len_unsigned = _dbus_marshal_read_uint32 (str, start + BODY_LENGTH_OFFSET, + *byte_order, NULL); + + if (body_len_unsigned > (unsigned) max_message_length) + { + *validity = DBUS_INVALID_INSANE_BODY_LENGTH; + return FALSE; + } + + header_len_unsigned = FIRST_FIELD_OFFSET + fields_array_len_unsigned; + header_len_unsigned = _DBUS_ALIGN_VALUE (header_len_unsigned, 8); + + /* overflow should be impossible since the lengths aren't allowed to + * be huge. + */ + _dbus_assert (max_message_length < _DBUS_INT32_MAX / 2); + if (body_len_unsigned + header_len_unsigned > (unsigned) max_message_length) + { + *validity = DBUS_INVALID_MESSAGE_TOO_LONG; + return FALSE; + } + + _dbus_assert (body_len_unsigned < (unsigned) _DBUS_INT32_MAX); + _dbus_assert (fields_array_len_unsigned < (unsigned) _DBUS_INT32_MAX); + _dbus_assert (header_len_unsigned < (unsigned) _DBUS_INT32_MAX); + + *body_len = body_len_unsigned; + *fields_array_len = fields_array_len_unsigned; + *header_len = header_len_unsigned; + + *validity = DBUS_VALID; + + _dbus_verbose ("have %d bytes, need body %u + header %u = %u\n", + len, body_len_unsigned, header_len_unsigned, + body_len_unsigned + header_len_unsigned); + + return (body_len_unsigned + header_len_unsigned) <= (unsigned) len; +} + +static DBusValidity +check_mandatory_fields (DBusHeader *header) +{ +#define REQUIRE_FIELD(name) do { if (header->fields[DBUS_HEADER_FIELD_##name].value_pos < 0) return DBUS_INVALID_MISSING_##name; } while (0) + + switch (_dbus_header_get_message_type (header)) + { + case DBUS_MESSAGE_TYPE_SIGNAL: + REQUIRE_FIELD (INTERFACE); + /* FALL THRU - signals also require the path and member */ + case DBUS_MESSAGE_TYPE_METHOD_CALL: + REQUIRE_FIELD (PATH); + REQUIRE_FIELD (MEMBER); + break; + case DBUS_MESSAGE_TYPE_ERROR: + REQUIRE_FIELD (ERROR_NAME); + REQUIRE_FIELD (REPLY_SERIAL); + break; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + REQUIRE_FIELD (REPLY_SERIAL); + break; + default: + /* other message types allowed but ignored */ + break; + } + + return DBUS_VALID; +} + +static DBusValidity +load_and_validate_field (DBusHeader *header, + int field, + DBusTypeReader *variant_reader) +{ + int type; + int expected_type; + const DBusString *value_str; + int value_pos; + int str_data_pos; + dbus_uint32_t v_UINT32; + int bad_string_code; + dbus_bool_t (* string_validation_func) (const DBusString *str, + int start, int len); + + /* Supposed to have been checked already */ + _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); + _dbus_assert (field != DBUS_HEADER_FIELD_INVALID); + + /* Before we can cache a field, we need to know it has the right type */ + type = _dbus_type_reader_get_current_type (variant_reader); + + _dbus_assert (_dbus_header_field_types[field].code == field); + + expected_type = EXPECTED_TYPE_OF_FIELD (field); + if (type != expected_type) + { + _dbus_verbose ("Field %d should have type %d but has %d\n", + field, expected_type, type); + return DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE; + } + + /* If the field was provided twice, we aren't happy */ + if (header->fields[field].value_pos >= 0) + { + _dbus_verbose ("Header field %d seen a second time\n", field); + return DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE; + } + + /* Now we can cache and look at the field content */ + _dbus_verbose ("initially caching field %d\n", field); + _dbus_header_cache_one (header, field, variant_reader); + + string_validation_func = NULL; + + /* make compiler happy that all this is initialized */ + v_UINT32 = 0; + value_str = NULL; + value_pos = -1; + str_data_pos = -1; + bad_string_code = DBUS_VALID; + + if (expected_type == DBUS_TYPE_UINT32) + { + _dbus_header_get_field_basic (header, field, expected_type, + &v_UINT32); + } + else if (expected_type == DBUS_TYPE_STRING || + expected_type == DBUS_TYPE_OBJECT_PATH || + expected_type == DBUS_TYPE_SIGNATURE) + { + _dbus_header_get_field_raw (header, field, + &value_str, &value_pos); + str_data_pos = _DBUS_ALIGN_VALUE (value_pos, 4) + 4; + } + else + { + _dbus_assert_not_reached ("none of the known fields should have this type"); + } + + switch (field) + { + case DBUS_HEADER_FIELD_DESTINATION: + string_validation_func = _dbus_validate_bus_name; + bad_string_code = DBUS_INVALID_BAD_DESTINATION; + break; + case DBUS_HEADER_FIELD_INTERFACE: + string_validation_func = _dbus_validate_interface; + bad_string_code = DBUS_INVALID_BAD_INTERFACE; + + if (_dbus_string_equal_substring (&_dbus_local_interface_str, + 0, + _dbus_string_get_length (&_dbus_local_interface_str), + value_str, str_data_pos)) + { + _dbus_verbose ("Message is on the local interface\n"); + return DBUS_INVALID_USES_LOCAL_INTERFACE; + } + break; + + case DBUS_HEADER_FIELD_MEMBER: + string_validation_func = _dbus_validate_member; + bad_string_code = DBUS_INVALID_BAD_MEMBER; + break; + + case DBUS_HEADER_FIELD_ERROR_NAME: + string_validation_func = _dbus_validate_error_name; + bad_string_code = DBUS_INVALID_BAD_ERROR_NAME; + break; + + case DBUS_HEADER_FIELD_SENDER: + string_validation_func = _dbus_validate_bus_name; + bad_string_code = DBUS_INVALID_BAD_SENDER; + break; + + case DBUS_HEADER_FIELD_PATH: + /* OBJECT_PATH was validated generically due to its type */ + string_validation_func = NULL; + + if (_dbus_string_equal_substring (&_dbus_local_path_str, + 0, + _dbus_string_get_length (&_dbus_local_path_str), + value_str, str_data_pos)) + { + _dbus_verbose ("Message is from the local path\n"); + return DBUS_INVALID_USES_LOCAL_PATH; + } + break; + + case DBUS_HEADER_FIELD_REPLY_SERIAL: + /* Can't be 0 */ + if (v_UINT32 == 0) + { + return DBUS_INVALID_BAD_SERIAL; + } + break; + + case DBUS_HEADER_FIELD_SIGNATURE: + /* SIGNATURE validated generically due to its type */ + string_validation_func = NULL; + break; + + default: + _dbus_assert_not_reached ("unknown field shouldn't be seen here"); + break; + } + + if (string_validation_func) + { + dbus_uint32_t len; + + _dbus_assert (bad_string_code != DBUS_VALID); + + len = _dbus_marshal_read_uint32 (value_str, value_pos, + header->byte_order, NULL); + +#if 0 + _dbus_verbose ("Validating string header field; code %d if fails\n", + bad_string_code); +#endif + if (!(*string_validation_func) (value_str, str_data_pos, len)) + return bad_string_code; + } + + return DBUS_VALID; +} + +/** + * Creates a message header from potentially-untrusted data. The + * return value is #TRUE if there was enough memory and the data was + * valid. If it returns #TRUE, the header will be created. If it + * returns #FALSE and *validity == #DBUS_VALIDITY_UNKNOWN_OOM_ERROR, + * then there wasn't enough memory. If it returns #FALSE + * and *validity != #DBUS_VALIDITY_UNKNOWN_OOM_ERROR then the data was + * invalid. + * + * The byte_order, fields_array_len, and body_len args should be from + * _dbus_header_have_message_untrusted(). Validation performed in + * _dbus_header_have_message_untrusted() is assumed to have been + * already done. + * + * @param header the header (must be initialized) + * @param mode whether to do validation + * @param validity return location for invalidity reason + * @param byte_order byte order from header + * @param fields_array_len claimed length of fields array + * @param body_len claimed length of body + * @param header_len claimed length of header + * @param str a string + * @param start start of header, 8-aligned + * @param len length of string to look at + * @returns #FALSE if no memory or data was invalid, #TRUE otherwise + */ +dbus_bool_t +_dbus_header_load (DBusHeader *header, + DBusValidationMode mode, + DBusValidity *validity, + int byte_order, + int fields_array_len, + int header_len, + int body_len, + const DBusString *str, + int start, + int len) +{ + int leftover; + DBusValidity v; + DBusTypeReader reader; + DBusTypeReader array_reader; + unsigned char v_byte; + dbus_uint32_t v_uint32; + dbus_uint32_t serial; + int padding_start; + int padding_len; + int i; + + _dbus_assert (start == (int) _DBUS_ALIGN_VALUE (start, 8)); + _dbus_assert (header_len <= len); + _dbus_assert (_dbus_string_get_length (&header->data) == 0); + + if (!_dbus_string_copy_len (str, start, header_len, &header->data, 0)) + { + _dbus_verbose ("Failed to copy buffer into new header\n"); + *validity = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; + return FALSE; + } + + if (mode == DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) + { + leftover = len - header_len - body_len - start; + } + else + { + v = _dbus_validate_body_with_reason (&_dbus_header_signature_str, 0, + byte_order, + &leftover, + str, start, len); + + if (v != DBUS_VALID) + { + *validity = v; + goto invalid; + } + } + + _dbus_assert (leftover < len); + + padding_len = header_len - (FIRST_FIELD_OFFSET + fields_array_len); + padding_start = start + FIRST_FIELD_OFFSET + fields_array_len; + _dbus_assert (start + header_len == (int) _DBUS_ALIGN_VALUE (padding_start, 8)); + _dbus_assert (start + header_len == padding_start + padding_len); + + if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) + { + if (!_dbus_string_validate_nul (str, padding_start, padding_len)) + { + *validity = DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; + goto invalid; + } + } + + header->padding = padding_len; + + if (mode == DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) + { + *validity = DBUS_VALID; + return TRUE; + } + + /* We now know the data is well-formed, but we have to check that + * it's valid. + */ + + _dbus_type_reader_init (&reader, + byte_order, + &_dbus_header_signature_str, 0, + str, start); + + /* BYTE ORDER */ + _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); + _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == BYTE_ORDER_OFFSET); + _dbus_type_reader_read_basic (&reader, &v_byte); + _dbus_type_reader_next (&reader); + + _dbus_assert (v_byte == byte_order); + header->byte_order = byte_order; + + /* MESSAGE TYPE */ + _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); + _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == TYPE_OFFSET); + _dbus_type_reader_read_basic (&reader, &v_byte); + _dbus_type_reader_next (&reader); + + /* unknown message types are supposed to be ignored, so only validation here is + * that it isn't invalid + */ + if (v_byte == DBUS_MESSAGE_TYPE_INVALID) + { + *validity = DBUS_INVALID_BAD_MESSAGE_TYPE; + goto invalid; + } + + /* FLAGS */ + _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); + _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == FLAGS_OFFSET); + _dbus_type_reader_read_basic (&reader, &v_byte); + _dbus_type_reader_next (&reader); + + /* unknown flags should be ignored */ + + /* PROTOCOL VERSION */ + _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE); + _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == VERSION_OFFSET); + _dbus_type_reader_read_basic (&reader, &v_byte); + _dbus_type_reader_next (&reader); + + if (v_byte != DBUS_MAJOR_PROTOCOL_VERSION) + { + *validity = DBUS_INVALID_BAD_PROTOCOL_VERSION; + goto invalid; + } + + /* BODY LENGTH */ + _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_UINT32); + _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == BODY_LENGTH_OFFSET); + _dbus_type_reader_read_basic (&reader, &v_uint32); + _dbus_type_reader_next (&reader); + + _dbus_assert (body_len == (signed) v_uint32); + + /* SERIAL */ + _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_UINT32); + _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == SERIAL_OFFSET); + _dbus_type_reader_read_basic (&reader, &serial); + _dbus_type_reader_next (&reader); + + if (serial == 0) + { + *validity = DBUS_INVALID_BAD_SERIAL; + goto invalid; + } + + _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_ARRAY); + _dbus_assert (_dbus_type_reader_get_value_pos (&reader) == FIELDS_ARRAY_LENGTH_OFFSET); + + _dbus_type_reader_recurse (&reader, &array_reader); + while (_dbus_type_reader_get_current_type (&array_reader) != DBUS_TYPE_INVALID) + { + DBusTypeReader struct_reader; + DBusTypeReader variant_reader; + unsigned char field_code; + + _dbus_assert (_dbus_type_reader_get_current_type (&array_reader) == DBUS_TYPE_STRUCT); + + _dbus_type_reader_recurse (&array_reader, &struct_reader); + + _dbus_assert (_dbus_type_reader_get_current_type (&struct_reader) == DBUS_TYPE_BYTE); + _dbus_type_reader_read_basic (&struct_reader, &field_code); + _dbus_type_reader_next (&struct_reader); + + if (field_code == DBUS_HEADER_FIELD_INVALID) + { + _dbus_verbose ("invalid header field code\n"); + *validity = DBUS_INVALID_HEADER_FIELD_CODE; + goto invalid; + } + + if (field_code > DBUS_HEADER_FIELD_LAST) + { + _dbus_verbose ("unknown header field code %d, skipping\n", + field_code); + goto next_field; + } + + _dbus_assert (_dbus_type_reader_get_current_type (&struct_reader) == DBUS_TYPE_VARIANT); + _dbus_type_reader_recurse (&struct_reader, &variant_reader); + + v = load_and_validate_field (header, field_code, &variant_reader); + if (v != DBUS_VALID) + { + _dbus_verbose ("Field %d was invalid\n", field_code); + *validity = v; + goto invalid; + } + + next_field: + _dbus_type_reader_next (&array_reader); + } + + /* Anything we didn't fill in is now known not to exist */ + i = 0; + while (i <= DBUS_HEADER_FIELD_LAST) + { + if (header->fields[i].value_pos == _DBUS_HEADER_FIELD_VALUE_UNKNOWN) + header->fields[i].value_pos = _DBUS_HEADER_FIELD_VALUE_NONEXISTENT; + ++i; + } + + v = check_mandatory_fields (header); + if (v != DBUS_VALID) + { + _dbus_verbose ("Mandatory fields were missing, code %d\n", v); + *validity = v; + goto invalid; + } + + *validity = DBUS_VALID; + return TRUE; + + invalid: + _dbus_string_set_length (&header->data, 0); + return FALSE; +} + +/** + * Fills in the correct body length. + * + * @param header the header + * @param body_len the length of the body + */ +void +_dbus_header_update_lengths (DBusHeader *header, + int body_len) +{ + _dbus_marshal_set_uint32 (&header->data, + BODY_LENGTH_OFFSET, + body_len, + header->byte_order); +} + +static dbus_bool_t +find_field_for_modification (DBusHeader *header, + int field, + DBusTypeReader *reader, + DBusTypeReader *realign_root) +{ + dbus_bool_t retval; + + retval = FALSE; + + _dbus_type_reader_init (realign_root, + header->byte_order, + &_dbus_header_signature_str, + FIELDS_ARRAY_SIGNATURE_OFFSET, + &header->data, + FIELDS_ARRAY_LENGTH_OFFSET); + + _dbus_type_reader_recurse (realign_root, reader); + + while (_dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID) + { + DBusTypeReader sub; + unsigned char field_code; + + _dbus_type_reader_recurse (reader, &sub); + + _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE); + _dbus_type_reader_read_basic (&sub, &field_code); + + if (field_code == (unsigned) field) + { + _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_STRUCT); + retval = TRUE; + goto done; + } + + _dbus_type_reader_next (reader); + } + + done: + return retval; +} + +/** + * Sets the value of a field with basic type. If the value is a string + * value, it isn't allowed to be #NULL. If the field doesn't exist, + * it will be created. + * + * @param header the header + * @param field the field to set + * @param type the type of the value + * @param value the value as for _dbus_marshal_set_basic() + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_header_set_field_basic (DBusHeader *header, + int field, + int type, + const void *value) +{ + _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); + + if (!reserve_header_padding (header)) + return FALSE; + + /* If the field exists we set, otherwise we append */ + if (_dbus_header_cache_check (header, field)) + { + DBusTypeReader reader; + DBusTypeReader realign_root; + + if (!find_field_for_modification (header, field, + &reader, &realign_root)) + _dbus_assert_not_reached ("field was marked present in cache but wasn't found"); + + if (!set_basic_field (&reader, field, type, value, &realign_root)) + return FALSE; + } + else + { + DBusTypeWriter writer; + DBusTypeWriter array; + + _dbus_type_writer_init_values_only (&writer, + header->byte_order, + &_dbus_header_signature_str, + FIELDS_ARRAY_SIGNATURE_OFFSET, + &header->data, + FIELDS_ARRAY_LENGTH_OFFSET); + + /* recurse into array without creating a new length, and jump to + * end of array. + */ + if (!_dbus_type_writer_append_array (&writer, + &_dbus_header_signature_str, + FIELDS_ARRAY_ELEMENT_SIGNATURE_OFFSET, + &array)) + _dbus_assert_not_reached ("recurse into ARRAY should not have used memory"); + + _dbus_assert (array.u.array.len_pos == FIELDS_ARRAY_LENGTH_OFFSET); + _dbus_assert (array.u.array.start_pos == FIRST_FIELD_OFFSET); + _dbus_assert (array.value_pos == HEADER_END_BEFORE_PADDING (header)); + + if (!write_basic_field (&array, + field, type, value)) + return FALSE; + + if (!_dbus_type_writer_unrecurse (&writer, &array)) + _dbus_assert_not_reached ("unrecurse from ARRAY should not have used memory"); + } + + correct_header_padding (header); + + /* We could be smarter about this (only invalidate fields after the + * one we modified, or even only if the one we modified changed + * length). But this hack is a start. + */ + _dbus_header_cache_invalidate_all (header); + + return TRUE; +} + +/** + * Gets the value of a field with basic type. If the field + * doesn't exist, returns #FALSE, otherwise returns #TRUE. + * + * @param header the header + * @param field the field to get + * @param type the type of the value + * @param value the value as for _dbus_marshal_read_basic() + * @returns #FALSE if the field doesn't exist + */ +dbus_bool_t +_dbus_header_get_field_basic (DBusHeader *header, + int field, + int type, + void *value) +{ + _dbus_assert (field != DBUS_HEADER_FIELD_INVALID); + _dbus_assert (field <= DBUS_HEADER_FIELD_LAST); + _dbus_assert (_dbus_header_field_types[field].code == field); + /* in light of this you might ask why the type is passed in; + * the only rationale I can think of is so the caller has + * to specify its expectation and breaks if we change it + */ + _dbus_assert (type == EXPECTED_TYPE_OF_FIELD (field)); + + if (!_dbus_header_cache_check (header, field)) + return FALSE; + + _dbus_assert (header->fields[field].value_pos >= 0); + + _dbus_marshal_read_basic (&header->data, + header->fields[field].value_pos, + type, value, header->byte_order, + NULL); + + return TRUE; +} + +/** + * Gets the raw marshaled data for a field. If the field doesn't + * exist, returns #FALSE, otherwise returns #TRUE. Returns the start + * of the marshaled data, i.e. usually the byte where the length + * starts (for strings and arrays) or for basic types just the value + * itself. + * + * @param header the header + * @param field the field to get + * @param str return location for the data string + * @param pos return location for start of field value + * @returns #FALSE if the field doesn't exist + */ +dbus_bool_t +_dbus_header_get_field_raw (DBusHeader *header, + int field, + const DBusString **str, + int *pos) +{ + if (!_dbus_header_cache_check (header, field)) + return FALSE; + + if (str) + *str = &header->data; + if (pos) + *pos = header->fields[field].value_pos; + + return TRUE; +} + +/** + * Deletes a field, if it exists. + * + * @param header the header + * @param field the field to delete + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_header_delete_field (DBusHeader *header, + int field) +{ + DBusTypeReader reader; + DBusTypeReader realign_root; + + if (_dbus_header_cache_known_nonexistent (header, field)) + return TRUE; /* nothing to do */ + + /* Scan to the field we want, delete and realign, reappend + * padding. Field may turn out not to exist. + */ + if (!find_field_for_modification (header, field, + &reader, &realign_root)) + return TRUE; /* nothing to do */ + + if (!reserve_header_padding (header)) + return FALSE; + + if (!_dbus_type_reader_delete (&reader, + &realign_root)) + return FALSE; + + correct_header_padding (header); + + _dbus_header_cache_invalidate_all (header); + + _dbus_assert (!_dbus_header_cache_check (header, field)); /* Expensive assertion ... */ + + return TRUE; +} + +/** + * Toggles a message flag bit, turning on the bit if value = TRUE and + * flipping it off if value = FALSE. + * + * @param header the header + * @param flag the message flag to toggle + * @param value toggle on or off + */ +void +_dbus_header_toggle_flag (DBusHeader *header, + dbus_uint32_t flag, + dbus_bool_t value) +{ + unsigned char *flags_p; + + flags_p = _dbus_string_get_data_len (&header->data, FLAGS_OFFSET, 1); + + if (value) + *flags_p |= flag; + else + *flags_p &= ~flag; +} + +/** + * Gets a message flag bit, returning TRUE if the bit is set. + * + * @param header the header + * @param flag the message flag to get + * @returns #TRUE if the flag is set + */ +dbus_bool_t +_dbus_header_get_flag (DBusHeader *header, + dbus_uint32_t flag) +{ + const unsigned char *flags_p; + + flags_p = _dbus_string_get_const_data_len (&header->data, FLAGS_OFFSET, 1); + + return (*flags_p & flag) != 0; +} + +/** + * Swaps the header into the given order if required. + * + * @param header the header + * @param new_order the new byte order + */ +void +_dbus_header_byteswap (DBusHeader *header, + int new_order) +{ + if (header->byte_order == new_order) + return; + + _dbus_marshal_byteswap (&_dbus_header_signature_str, + 0, header->byte_order, + new_order, + &header->data, 0); + + header->byte_order = new_order; +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +dbus_bool_t +_dbus_marshal_header_test (void) +{ + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-marshal-header.h b/dbus/dbus-marshal-header.h new file mode 100644 index 00000000..f4038630 --- /dev/null +++ b/dbus/dbus-marshal-header.h @@ -0,0 +1,133 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-header.h Managing marshaling/demarshaling of message headers + * + * Copyright (C) 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_MARSHAL_HEADER_H +#define DBUS_MARSHAL_HEADER_H + +#include +#include +#include + +#ifndef PACKAGE +#error "config.h not included here" +#endif + +typedef struct DBusHeader DBusHeader; +typedef struct DBusHeaderField DBusHeaderField; + +#define _DBUS_HEADER_FIELD_VALUE_UNKNOWN -1 +#define _DBUS_HEADER_FIELD_VALUE_NONEXISTENT -2 + +/** + * Cached information about a header field in the message + */ +struct DBusHeaderField +{ + int value_pos; /**< Position of field value, or -1/-2 */ +}; + +/** + * Message header data and some cached details of it. + */ +struct DBusHeader +{ + DBusString data; /**< Header network data, stored + * separately from body so we can + * independently realloc it. + */ + + DBusHeaderField fields[DBUS_HEADER_FIELD_LAST + 1]; /**< Track the location + * of each field in header + */ + + dbus_uint32_t padding : 3; /**< bytes of alignment in header */ + dbus_uint32_t byte_order : 8; /**< byte order of header */ +}; + +dbus_bool_t _dbus_header_init (DBusHeader *header, + int byte_order); +void _dbus_header_free (DBusHeader *header); +void _dbus_header_reinit (DBusHeader *header, + int byte_order); +dbus_bool_t _dbus_header_create (DBusHeader *header, + int type, + const char *destination, + const char *path, + const char *interface, + const char *member, + const char *error_name); +dbus_bool_t _dbus_header_copy (const DBusHeader *header, + DBusHeader *dest); +int _dbus_header_get_message_type (DBusHeader *header); +void _dbus_header_set_serial (DBusHeader *header, + dbus_uint32_t serial); +dbus_uint32_t _dbus_header_get_serial (DBusHeader *header); +void _dbus_header_update_lengths (DBusHeader *header, + int body_len); +dbus_bool_t _dbus_header_set_field_basic (DBusHeader *header, + int field, + int type, + const void *value); +dbus_bool_t _dbus_header_get_field_basic (DBusHeader *header, + int field, + int type, + void *value); +dbus_bool_t _dbus_header_get_field_raw (DBusHeader *header, + int field, + const DBusString **str, + int *pos); +dbus_bool_t _dbus_header_delete_field (DBusHeader *header, + int field); +void _dbus_header_toggle_flag (DBusHeader *header, + dbus_uint32_t flag, + dbus_bool_t value); +dbus_bool_t _dbus_header_get_flag (DBusHeader *header, + dbus_uint32_t flag); +dbus_bool_t _dbus_header_ensure_signature (DBusHeader *header, + DBusString **type_str, + int *type_pos); +dbus_bool_t _dbus_header_have_message_untrusted (int max_message_length, + DBusValidity *validity, + int *byte_order, + int *fields_array_len, + int *header_len, + int *body_len, + const DBusString *str, + int start, + int len); +dbus_bool_t _dbus_header_load (DBusHeader *header, + DBusValidationMode mode, + DBusValidity *validity, + int byte_order, + int fields_array_len, + int header_len, + int body_len, + const DBusString *str, + int start, + int len); +void _dbus_header_byteswap (DBusHeader *header, + int new_order); + + + +#endif /* DBUS_MARSHAL_HEADER_H */ diff --git a/dbus/dbus-marshal-recursive-util.c b/dbus/dbus-marshal-recursive-util.c new file mode 100644 index 00000000..f4d59f3f --- /dev/null +++ b/dbus/dbus-marshal-recursive-util.c @@ -0,0 +1,3565 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-recursive-util.c Would be in dbus-marshal-recursive.c, but only used in bus/tests + * + * Copyright (C) 2004, 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include + +#ifdef DBUS_BUILD_TESTS + +#include "dbus-marshal-recursive.h" +#include "dbus-marshal-basic.h" +#include "dbus-signature.h" +#include "dbus-internals.h" +#include + +static void +basic_value_zero (DBusBasicValue *value) +{ + +#ifdef DBUS_HAVE_INT64 + value->u64 = 0; +#else + value->u64.first32 = 0; + value->u64.second32 = 0; +#endif +} + +static dbus_bool_t +basic_value_equal (int type, + DBusBasicValue *lhs, + DBusBasicValue *rhs) +{ + if (type == DBUS_TYPE_STRING || + type == DBUS_TYPE_SIGNATURE || + type == DBUS_TYPE_OBJECT_PATH) + { + return strcmp (lhs->str, rhs->str) == 0; + } + else + { +#ifdef DBUS_HAVE_INT64 + return lhs->u64 == rhs->u64; +#else + return lhs->u64.first32 == rhs->u64.first32 && + lhs->u64.second32 == rhs->u64.second32; +#endif + } +} + +static dbus_bool_t +equal_values_helper (DBusTypeReader *lhs, + DBusTypeReader *rhs) +{ + int lhs_type; + int rhs_type; + + lhs_type = _dbus_type_reader_get_current_type (lhs); + rhs_type = _dbus_type_reader_get_current_type (rhs); + + if (lhs_type != rhs_type) + return FALSE; + + if (lhs_type == DBUS_TYPE_INVALID) + return TRUE; + + if (dbus_type_is_basic (lhs_type)) + { + DBusBasicValue lhs_value; + DBusBasicValue rhs_value; + + basic_value_zero (&lhs_value); + basic_value_zero (&rhs_value); + + _dbus_type_reader_read_basic (lhs, &lhs_value); + _dbus_type_reader_read_basic (rhs, &rhs_value); + + return basic_value_equal (lhs_type, &lhs_value, &rhs_value); + } + else + { + DBusTypeReader lhs_sub; + DBusTypeReader rhs_sub; + + _dbus_type_reader_recurse (lhs, &lhs_sub); + _dbus_type_reader_recurse (rhs, &rhs_sub); + + return equal_values_helper (&lhs_sub, &rhs_sub); + } +} + +/** + * See whether the two readers point to identical data blocks. + * + * @param lhs reader 1 + * @param rhs reader 2 + * @returns #TRUE if the data blocks have the same values + */ +dbus_bool_t +_dbus_type_reader_equal_values (const DBusTypeReader *lhs, + const DBusTypeReader *rhs) +{ + DBusTypeReader copy_lhs = *lhs; + DBusTypeReader copy_rhs = *rhs; + + return equal_values_helper (©_lhs, ©_rhs); +} + +/* TESTS */ + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#include "dbus-test.h" +#include "dbus-list.h" +#include +#include + +/* Whether to do the OOM stuff (only with other expensive tests) */ +#define TEST_OOM_HANDLING 0 +/* We do start offset 0 through 9, to get various alignment cases. Still this + * obviously makes the test suite run 10x as slow. + */ +#define MAX_INITIAL_OFFSET 9 + +/* Largest iteration count to test copying, realignment, + * etc. with. i.e. we only test this stuff with some of the smaller + * data sets. + */ +#define MAX_ITERATIONS_FOR_EXPENSIVE_TESTS 1000 + +typedef struct +{ + int byte_order; + int initial_offset; + DBusString signature; + DBusString body; +} DataBlock; + +typedef struct +{ + int saved_sig_len; + int saved_body_len; +} DataBlockState; + +#define N_FENCE_BYTES 5 +#define FENCE_BYTES_STR "abcde" +#define INITIAL_PADDING_BYTE '\0' + +static dbus_bool_t +data_block_init (DataBlock *block, + int byte_order, + int initial_offset) +{ + if (!_dbus_string_init (&block->signature)) + return FALSE; + + if (!_dbus_string_init (&block->body)) + { + _dbus_string_free (&block->signature); + return FALSE; + } + + if (!_dbus_string_insert_bytes (&block->signature, 0, initial_offset, + INITIAL_PADDING_BYTE) || + !_dbus_string_insert_bytes (&block->body, 0, initial_offset, + INITIAL_PADDING_BYTE) || + !_dbus_string_append (&block->signature, FENCE_BYTES_STR) || + !_dbus_string_append (&block->body, FENCE_BYTES_STR)) + { + _dbus_string_free (&block->signature); + _dbus_string_free (&block->body); + return FALSE; + } + + block->byte_order = byte_order; + block->initial_offset = initial_offset; + + return TRUE; +} + +static void +data_block_save (DataBlock *block, + DataBlockState *state) +{ + state->saved_sig_len = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES; + state->saved_body_len = _dbus_string_get_length (&block->body) - N_FENCE_BYTES; +} + +static void +data_block_restore (DataBlock *block, + DataBlockState *state) +{ + _dbus_string_delete (&block->signature, + state->saved_sig_len, + _dbus_string_get_length (&block->signature) - state->saved_sig_len - N_FENCE_BYTES); + _dbus_string_delete (&block->body, + state->saved_body_len, + _dbus_string_get_length (&block->body) - state->saved_body_len - N_FENCE_BYTES); +} + +static void +data_block_verify (DataBlock *block) +{ + if (!_dbus_string_ends_with_c_str (&block->signature, + FENCE_BYTES_STR)) + { + int offset; + + offset = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - 8; + if (offset < 0) + offset = 0; + + _dbus_verbose_bytes_of_string (&block->signature, + offset, + _dbus_string_get_length (&block->signature) - offset); + _dbus_assert_not_reached ("block did not verify: bad bytes at end of signature"); + } + if (!_dbus_string_ends_with_c_str (&block->body, + FENCE_BYTES_STR)) + { + int offset; + + offset = _dbus_string_get_length (&block->body) - N_FENCE_BYTES - 8; + if (offset < 0) + offset = 0; + + _dbus_verbose_bytes_of_string (&block->body, + offset, + _dbus_string_get_length (&block->body) - offset); + _dbus_assert_not_reached ("block did not verify: bad bytes at end of body"); + } + + _dbus_assert (_dbus_string_validate_nul (&block->signature, + 0, block->initial_offset)); + _dbus_assert (_dbus_string_validate_nul (&block->body, + 0, block->initial_offset)); +} + +static void +data_block_free (DataBlock *block) +{ + data_block_verify (block); + + _dbus_string_free (&block->signature); + _dbus_string_free (&block->body); +} + +static void +data_block_reset (DataBlock *block) +{ + data_block_verify (block); + + _dbus_string_delete (&block->signature, + block->initial_offset, + _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - block->initial_offset); + _dbus_string_delete (&block->body, + block->initial_offset, + _dbus_string_get_length (&block->body) - N_FENCE_BYTES - block->initial_offset); + + data_block_verify (block); +} + +static void +data_block_init_reader_writer (DataBlock *block, + DBusTypeReader *reader, + DBusTypeWriter *writer) +{ + if (reader) + _dbus_type_reader_init (reader, + block->byte_order, + &block->signature, + block->initial_offset, + &block->body, + block->initial_offset); + + if (writer) + _dbus_type_writer_init (writer, + block->byte_order, + &block->signature, + _dbus_string_get_length (&block->signature) - N_FENCE_BYTES, + &block->body, + _dbus_string_get_length (&block->body) - N_FENCE_BYTES); +} + +static void +real_check_expected_type (DBusTypeReader *reader, + int expected, + const char *funcname, + int line) +{ + int t; + + t = _dbus_type_reader_get_current_type (reader); + + if (t != expected) + { + _dbus_warn ("Read type %s while expecting %s at %s line %d\n", + _dbus_type_to_string (t), + _dbus_type_to_string (expected), + funcname, line); + + _dbus_assert_not_reached ("read wrong type"); + } +} + +#define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__) + +#define NEXT_EXPECTING_TRUE(reader) do { if (!_dbus_type_reader_next (reader)) \ + { \ + _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n", \ + _DBUS_FUNCTION_NAME, __LINE__); \ + _dbus_assert_not_reached ("test failed"); \ + } \ +} while (0) + +#define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader)) \ + { \ + _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n", \ + _DBUS_FUNCTION_NAME, __LINE__); \ + _dbus_assert_not_reached ("test failed"); \ + } \ + check_expected_type (reader, DBUS_TYPE_INVALID); \ +} while (0) + +typedef struct TestTypeNode TestTypeNode; +typedef struct TestTypeNodeClass TestTypeNodeClass; +typedef struct TestTypeNodeContainer TestTypeNodeContainer; +typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass; + +struct TestTypeNode +{ + const TestTypeNodeClass *klass; +}; + +struct TestTypeNodeContainer +{ + TestTypeNode base; + DBusList *children; +}; + +struct TestTypeNodeClass +{ + int typecode; + + int instance_size; + + int subclass_detail; /* a bad hack to avoid a bunch of subclass casting */ + + dbus_bool_t (* construct) (TestTypeNode *node); + void (* destroy) (TestTypeNode *node); + + dbus_bool_t (* write_value) (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); + dbus_bool_t (* read_value) (TestTypeNode *node, + DBusTypeReader *reader, + int seed); + dbus_bool_t (* set_value) (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); + dbus_bool_t (* build_signature) (TestTypeNode *node, + DBusString *str); + dbus_bool_t (* write_multi) (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed, + int count); + dbus_bool_t (* read_multi) (TestTypeNode *node, + DBusTypeReader *reader, + int seed, + int count); +}; + +struct TestTypeNodeContainerClass +{ + TestTypeNodeClass base; +}; + +/* FIXME this could be chilled out substantially by unifying + * the basic types into basic_write_value/basic_read_value + * and by merging read_value and set_value into one function + * taking a flag argument. + */ +static dbus_bool_t int16_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t int16_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t int16_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static dbus_bool_t int16_write_multi (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed, + int count); +static dbus_bool_t int16_read_multi (TestTypeNode *node, + DBusTypeReader *reader, + int seed, + int count); +static dbus_bool_t int32_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t int32_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t int32_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static dbus_bool_t int32_write_multi (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed, + int count); +static dbus_bool_t int32_read_multi (TestTypeNode *node, + DBusTypeReader *reader, + int seed, + int count); +static dbus_bool_t int64_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t int64_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t int64_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static dbus_bool_t string_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t string_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t string_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static dbus_bool_t bool_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t bool_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t bool_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static dbus_bool_t byte_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t byte_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t byte_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static dbus_bool_t double_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t double_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t double_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static dbus_bool_t object_path_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t object_path_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t object_path_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static dbus_bool_t signature_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t signature_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t signature_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static dbus_bool_t struct_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t struct_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t struct_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static dbus_bool_t struct_build_signature (TestTypeNode *node, + DBusString *str); +static dbus_bool_t dict_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t dict_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t dict_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static dbus_bool_t dict_build_signature (TestTypeNode *node, + DBusString *str); +static dbus_bool_t array_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t array_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t array_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static dbus_bool_t array_build_signature (TestTypeNode *node, + DBusString *str); +static dbus_bool_t variant_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed); +static dbus_bool_t variant_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed); +static dbus_bool_t variant_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed); +static void container_destroy (TestTypeNode *node); + + + +static const TestTypeNodeClass int16_class = { + DBUS_TYPE_INT16, + sizeof (TestTypeNode), + 0, + NULL, + NULL, + int16_write_value, + int16_read_value, + int16_set_value, + NULL, + int16_write_multi, + int16_read_multi +}; + +static const TestTypeNodeClass uint16_class = { + DBUS_TYPE_UINT16, + sizeof (TestTypeNode), + 0, + NULL, + NULL, + int16_write_value, /* recycle from int16 */ + int16_read_value, /* recycle from int16 */ + int16_set_value, /* recycle from int16 */ + NULL, + int16_write_multi, /* recycle from int16 */ + int16_read_multi /* recycle from int16 */ +}; + +static const TestTypeNodeClass int32_class = { + DBUS_TYPE_INT32, + sizeof (TestTypeNode), + 0, + NULL, + NULL, + int32_write_value, + int32_read_value, + int32_set_value, + NULL, + int32_write_multi, + int32_read_multi +}; + +static const TestTypeNodeClass uint32_class = { + DBUS_TYPE_UINT32, + sizeof (TestTypeNode), + 0, + NULL, + NULL, + int32_write_value, /* recycle from int32 */ + int32_read_value, /* recycle from int32 */ + int32_set_value, /* recycle from int32 */ + NULL, + int32_write_multi, /* recycle from int32 */ + int32_read_multi /* recycle from int32 */ +}; + +static const TestTypeNodeClass int64_class = { + DBUS_TYPE_INT64, + sizeof (TestTypeNode), + 0, + NULL, + NULL, + int64_write_value, + int64_read_value, + int64_set_value, + NULL, + NULL, /* FIXME */ + NULL /* FIXME */ +}; + +static const TestTypeNodeClass uint64_class = { + DBUS_TYPE_UINT64, + sizeof (TestTypeNode), + 0, + NULL, + NULL, + int64_write_value, /* recycle from int64 */ + int64_read_value, /* recycle from int64 */ + int64_set_value, /* recycle from int64 */ + NULL, + NULL, /* FIXME */ + NULL /* FIXME */ +}; + +static const TestTypeNodeClass string_0_class = { + DBUS_TYPE_STRING, + sizeof (TestTypeNode), + 0, /* string length */ + NULL, + NULL, + string_write_value, + string_read_value, + string_set_value, + NULL, + NULL, + NULL +}; + +static const TestTypeNodeClass string_1_class = { + DBUS_TYPE_STRING, + sizeof (TestTypeNode), + 1, /* string length */ + NULL, + NULL, + string_write_value, + string_read_value, + string_set_value, + NULL, + NULL, + NULL +}; + +/* with nul, a len 3 string should fill 4 bytes and thus is "special" */ +static const TestTypeNodeClass string_3_class = { + DBUS_TYPE_STRING, + sizeof (TestTypeNode), + 3, /* string length */ + NULL, + NULL, + string_write_value, + string_read_value, + string_set_value, + NULL, + NULL, + NULL +}; + +/* with nul, a len 8 string should fill 9 bytes and thus is "special" (far-fetched I suppose) */ +static const TestTypeNodeClass string_8_class = { + DBUS_TYPE_STRING, + sizeof (TestTypeNode), + 8, /* string length */ + NULL, + NULL, + string_write_value, + string_read_value, + string_set_value, + NULL, + NULL, + NULL +}; + +static const TestTypeNodeClass bool_class = { + DBUS_TYPE_BOOLEAN, + sizeof (TestTypeNode), + 0, + NULL, + NULL, + bool_write_value, + bool_read_value, + bool_set_value, + NULL, + NULL, /* FIXME */ + NULL /* FIXME */ +}; + +static const TestTypeNodeClass byte_class = { + DBUS_TYPE_BYTE, + sizeof (TestTypeNode), + 0, + NULL, + NULL, + byte_write_value, + byte_read_value, + byte_set_value, + NULL, + NULL, /* FIXME */ + NULL /* FIXME */ +}; + +static const TestTypeNodeClass double_class = { + DBUS_TYPE_DOUBLE, + sizeof (TestTypeNode), + 0, + NULL, + NULL, + double_write_value, + double_read_value, + double_set_value, + NULL, + NULL, /* FIXME */ + NULL /* FIXME */ +}; + +static const TestTypeNodeClass object_path_class = { + DBUS_TYPE_OBJECT_PATH, + sizeof (TestTypeNode), + 0, + NULL, + NULL, + object_path_write_value, + object_path_read_value, + object_path_set_value, + NULL, + NULL, + NULL +}; + +static const TestTypeNodeClass signature_class = { + DBUS_TYPE_SIGNATURE, + sizeof (TestTypeNode), + 0, + NULL, + NULL, + signature_write_value, + signature_read_value, + signature_set_value, + NULL, + NULL, + NULL +}; + +static const TestTypeNodeClass struct_1_class = { + DBUS_TYPE_STRUCT, + sizeof (TestTypeNodeContainer), + 1, /* number of times children appear as fields */ + NULL, + container_destroy, + struct_write_value, + struct_read_value, + struct_set_value, + struct_build_signature, + NULL, + NULL +}; + +static const TestTypeNodeClass struct_2_class = { + DBUS_TYPE_STRUCT, + sizeof (TestTypeNodeContainer), + 2, /* number of times children appear as fields */ + NULL, + container_destroy, + struct_write_value, + struct_read_value, + struct_set_value, + struct_build_signature, + NULL, + NULL +}; + +static const TestTypeNodeClass dict_1_class = { + DBUS_TYPE_ARRAY, /* this is correct, a dict is an array of dict entry */ + sizeof (TestTypeNodeContainer), + 1, /* number of entries */ + NULL, + container_destroy, + dict_write_value, + dict_read_value, + dict_set_value, + dict_build_signature, + NULL, + NULL +}; + +static dbus_bool_t arrays_write_fixed_in_blocks = FALSE; + +static const TestTypeNodeClass array_0_class = { + DBUS_TYPE_ARRAY, + sizeof (TestTypeNodeContainer), + 0, /* number of array elements */ + NULL, + container_destroy, + array_write_value, + array_read_value, + array_set_value, + array_build_signature, + NULL, + NULL +}; + +static const TestTypeNodeClass array_1_class = { + DBUS_TYPE_ARRAY, + sizeof (TestTypeNodeContainer), + 1, /* number of array elements */ + NULL, + container_destroy, + array_write_value, + array_read_value, + array_set_value, + array_build_signature, + NULL, + NULL +}; + +static const TestTypeNodeClass array_2_class = { + DBUS_TYPE_ARRAY, + sizeof (TestTypeNodeContainer), + 2, /* number of array elements */ + NULL, + container_destroy, + array_write_value, + array_read_value, + array_set_value, + array_build_signature, + NULL, + NULL +}; + +static const TestTypeNodeClass array_9_class = { + DBUS_TYPE_ARRAY, + sizeof (TestTypeNodeContainer), + 9, /* number of array elements */ + NULL, + container_destroy, + array_write_value, + array_read_value, + array_set_value, + array_build_signature, + NULL, + NULL +}; + +static const TestTypeNodeClass variant_class = { + DBUS_TYPE_VARIANT, + sizeof (TestTypeNodeContainer), + 0, + NULL, + container_destroy, + variant_write_value, + variant_read_value, + variant_set_value, + NULL, + NULL, + NULL +}; + +static const TestTypeNodeClass* const +basic_nodes[] = { + &int16_class, + &uint16_class, + &int32_class, + &uint32_class, + &int64_class, + &uint64_class, + &bool_class, + &byte_class, + &double_class, + &string_0_class, + &string_1_class, + &string_3_class, + &string_8_class, + &object_path_class, + &signature_class +}; +#define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes)) + +static const TestTypeNodeClass* const +container_nodes[] = { + &struct_1_class, + &array_1_class, + &struct_2_class, + &array_0_class, + &array_2_class, + &variant_class, + &dict_1_class /* last since we want struct and array before it */ + /* array_9_class is omitted on purpose, it's too slow; + * we only use it in one hardcoded test below + */ +}; +#define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes)) + +static TestTypeNode* +node_new (const TestTypeNodeClass *klass) +{ + TestTypeNode *node; + + node = dbus_malloc0 (klass->instance_size); + if (node == NULL) + return NULL; + + node->klass = klass; + + if (klass->construct) + { + if (!(* klass->construct) (node)) + { + dbus_free (node); + return NULL; + } + } + + return node; +} + +static void +node_destroy (TestTypeNode *node) +{ + if (node->klass->destroy) + (* node->klass->destroy) (node); + dbus_free (node); +} + +static dbus_bool_t +node_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + dbus_bool_t retval; + + retval = (* node->klass->write_value) (node, block, writer, seed); + +#if 0 + /* Handy to see where things break, but too expensive to do all the time */ + data_block_verify (block); +#endif + + return retval; +} + +static dbus_bool_t +node_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + /* DBusTypeReader restored; */ + + if (!(* node->klass->read_value) (node, reader, seed)) + return FALSE; + + return TRUE; +} + +/* Warning: if this one fails due to OOM, it has side effects (can + * modify only some of the sub-values). OK in a test suite, but we + * never do this in real code. + */ +static dbus_bool_t +node_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + if (!(* node->klass->set_value) (node, reader, realign_root, seed)) + return FALSE; + + return TRUE; +} + +static dbus_bool_t +node_build_signature (TestTypeNode *node, + DBusString *str) +{ + if (node->klass->build_signature) + return (* node->klass->build_signature) (node, str); + else + return _dbus_string_append_byte (str, node->klass->typecode); +} + +static dbus_bool_t +node_append_child (TestTypeNode *node, + TestTypeNode *child) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + + _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer)); + + if (!_dbus_list_append (&container->children, child)) + _dbus_assert_not_reached ("no memory"); /* we never check the return value on node_append_child anyhow - it's run from outside the malloc-failure test code */ + + return TRUE; +} + +static dbus_bool_t +node_write_multi (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed, + int n_copies) +{ + dbus_bool_t retval; + + _dbus_assert (node->klass->write_multi != NULL); + retval = (* node->klass->write_multi) (node, block, writer, seed, n_copies); + +#if 0 + /* Handy to see where things break, but too expensive to do all the time */ + data_block_verify (block); +#endif + + return retval; +} + +static dbus_bool_t +node_read_multi (TestTypeNode *node, + DBusTypeReader *reader, + int seed, + int n_copies) +{ + _dbus_assert (node->klass->read_multi != NULL); + + if (!(* node->klass->read_multi) (node, reader, seed, n_copies)) + return FALSE; + + return TRUE; +} + +static int n_iterations_completed_total = 0; +static int n_iterations_completed_this_test = 0; +static int n_iterations_expected_this_test = 0; + +typedef struct +{ + const DBusString *signature; + DataBlock *block; + int type_offset; + TestTypeNode **nodes; + int n_nodes; +} NodeIterationData; + +static dbus_bool_t +run_test_copy (NodeIterationData *nid) +{ + DataBlock *src; + DataBlock dest; + dbus_bool_t retval; + DBusTypeReader reader; + DBusTypeWriter writer; + + _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + + src = nid->block; + + retval = FALSE; + + if (!data_block_init (&dest, src->byte_order, src->initial_offset)) + return FALSE; + + data_block_init_reader_writer (src, &reader, NULL); + data_block_init_reader_writer (&dest, NULL, &writer); + + /* DBusTypeWriter assumes it's writing into an existing signature, + * so doesn't add nul on its own. We have to do that. + */ + if (!_dbus_string_insert_byte (&dest.signature, + dest.initial_offset, '\0')) + goto out; + + if (!_dbus_type_writer_write_reader (&writer, &reader)) + goto out; + + /* Data blocks should now be identical */ + if (!_dbus_string_equal (&src->signature, &dest.signature)) + { + _dbus_verbose ("SOURCE\n"); + _dbus_verbose_bytes_of_string (&src->signature, 0, + _dbus_string_get_length (&src->signature)); + _dbus_verbose ("DEST\n"); + _dbus_verbose_bytes_of_string (&dest.signature, 0, + _dbus_string_get_length (&dest.signature)); + _dbus_assert_not_reached ("signatures did not match"); + } + + if (!_dbus_string_equal (&src->body, &dest.body)) + { + _dbus_verbose ("SOURCE\n"); + _dbus_verbose_bytes_of_string (&src->body, 0, + _dbus_string_get_length (&src->body)); + _dbus_verbose ("DEST\n"); + _dbus_verbose_bytes_of_string (&dest.body, 0, + _dbus_string_get_length (&dest.body)); + _dbus_assert_not_reached ("bodies did not match"); + } + + retval = TRUE; + + out: + + data_block_free (&dest); + + return retval; +} + +static dbus_bool_t +run_test_values_only_write (NodeIterationData *nid) +{ + DBusTypeReader reader; + DBusTypeWriter writer; + int i; + dbus_bool_t retval; + int sig_len; + + _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + + retval = FALSE; + + data_block_reset (nid->block); + + sig_len = _dbus_string_get_length (nid->signature); + + _dbus_type_writer_init_values_only (&writer, + nid->block->byte_order, + nid->signature, 0, + &nid->block->body, + _dbus_string_get_length (&nid->block->body) - N_FENCE_BYTES); + _dbus_type_reader_init (&reader, + nid->block->byte_order, + nid->signature, 0, + &nid->block->body, + nid->block->initial_offset); + + i = 0; + while (i < nid->n_nodes) + { + if (!node_write_value (nid->nodes[i], nid->block, &writer, i)) + goto out; + + ++i; + } + + /* if we wrote any typecodes then this would fail */ + _dbus_assert (sig_len == _dbus_string_get_length (nid->signature)); + + /* But be sure we wrote out the values correctly */ + i = 0; + while (i < nid->n_nodes) + { + if (!node_read_value (nid->nodes[i], &reader, i)) + goto out; + + if (i + 1 == nid->n_nodes) + NEXT_EXPECTING_FALSE (&reader); + else + NEXT_EXPECTING_TRUE (&reader); + + ++i; + } + + retval = TRUE; + + out: + data_block_reset (nid->block); + return retval; +} + +/* offset the seed for setting, so we set different numbers than + * we originally wrote. Don't offset by a huge number since in + * some cases it's value = possibilities[seed % n_possibilities] + * and we don't want to wrap around. bool_from_seed + * is just seed % 2 even. + */ +#define SET_SEED 1 +static dbus_bool_t +run_test_set_values (NodeIterationData *nid) +{ + DBusTypeReader reader; + DBusTypeReader realign_root; + dbus_bool_t retval; + int i; + + _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + + retval = FALSE; + + data_block_init_reader_writer (nid->block, + &reader, NULL); + + realign_root = reader; + + i = 0; + while (i < nid->n_nodes) + { + if (!node_set_value (nid->nodes[i], + &reader, &realign_root, + i + SET_SEED)) + goto out; + + if (i + 1 == nid->n_nodes) + NEXT_EXPECTING_FALSE (&reader); + else + NEXT_EXPECTING_TRUE (&reader); + + ++i; + } + + /* Check that the new values were set */ + + reader = realign_root; + + i = 0; + while (i < nid->n_nodes) + { + if (!node_read_value (nid->nodes[i], &reader, + i + SET_SEED)) + goto out; + + if (i + 1 == nid->n_nodes) + NEXT_EXPECTING_FALSE (&reader); + else + NEXT_EXPECTING_TRUE (&reader); + + ++i; + } + + retval = TRUE; + + out: + return retval; +} + +static dbus_bool_t +run_test_delete_values (NodeIterationData *nid) +{ + DBusTypeReader reader; + dbus_bool_t retval; + int t; + + _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + + retval = FALSE; + + data_block_init_reader_writer (nid->block, + &reader, NULL); + + while ((t = _dbus_type_reader_get_current_type (&reader)) != DBUS_TYPE_INVALID) + { + /* Right now, deleting only works on array elements. We delete + * all array elements, and then verify that there aren't any + * left. + */ + if (t == DBUS_TYPE_ARRAY) + { + DBusTypeReader array; + int n_elements; + int elem_type; + + _dbus_type_reader_recurse (&reader, &array); + n_elements = 0; + while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID) + { + n_elements += 1; + _dbus_type_reader_next (&array); + } + + /* reset to start of array */ + _dbus_type_reader_recurse (&reader, &array); + _dbus_verbose ("recursing into deletion loop reader.value_pos = %d array.value_pos = %d array.u.start_pos = %d\n", + reader.value_pos, array.value_pos, array.u.array.start_pos); + while ((elem_type = _dbus_type_reader_get_current_type (&array)) != DBUS_TYPE_INVALID) + { + /* We don't want to always delete from the same part of the array. */ + static int cycle = 0; + int elem; + + _dbus_assert (n_elements > 0); + + elem = cycle; + if (elem == 3 || elem >= n_elements) /* end of array */ + elem = n_elements - 1; + + _dbus_verbose ("deleting array element %d of %d type %s cycle %d reader pos %d elem pos %d\n", + elem, n_elements, _dbus_type_to_string (elem_type), + cycle, reader.value_pos, array.value_pos); + while (elem > 0) + { + if (!_dbus_type_reader_next (&array)) + _dbus_assert_not_reached ("should have had another element\n"); + --elem; + } + + if (!_dbus_type_reader_delete (&array, &reader)) + goto out; + + n_elements -= 1; + + /* reset */ + _dbus_type_reader_recurse (&reader, &array); + + if (cycle > 2) + cycle = 0; + else + cycle += 1; + } + } + _dbus_type_reader_next (&reader); + } + + /* Check that there are no array elements left */ + data_block_init_reader_writer (nid->block, + &reader, NULL); + + while ((t = _dbus_type_reader_get_current_type (&reader)) != DBUS_TYPE_INVALID) + { + _dbus_type_reader_next (&reader); + } + + retval = TRUE; + + out: + return retval; +} + +static dbus_bool_t +run_test_nodes_iteration (void *data) +{ + NodeIterationData *nid = data; + DBusTypeReader reader; + DBusTypeWriter writer; + int i; + dbus_bool_t retval; + + /* Stuff to do: + * 1. write the value + * 2. strcmp-compare with the signature we built + * 3. read the value + * 4. type-iterate the signature and the value and see if they are the same type-wise + */ + retval = FALSE; + + data_block_init_reader_writer (nid->block, + &reader, &writer); + + /* DBusTypeWriter assumes it's writing into an existing signature, + * so doesn't add nul on its own. We have to do that. + */ + if (!_dbus_string_insert_byte (&nid->block->signature, + nid->type_offset, '\0')) + goto out; + + i = 0; + while (i < nid->n_nodes) + { + if (!node_write_value (nid->nodes[i], nid->block, &writer, i)) + goto out; + + ++i; + } + + if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature), + &nid->block->signature, nid->type_offset)) + { + _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n", + _dbus_string_get_const_data (nid->signature), + _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0), + nid->type_offset); + _dbus_assert_not_reached ("wrong signature"); + } + + i = 0; + while (i < nid->n_nodes) + { + if (!node_read_value (nid->nodes[i], &reader, i)) + goto out; + + if (i + 1 == nid->n_nodes) + NEXT_EXPECTING_FALSE (&reader); + else + NEXT_EXPECTING_TRUE (&reader); + + ++i; + } + + if (n_iterations_expected_this_test <= MAX_ITERATIONS_FOR_EXPENSIVE_TESTS) + { + /* this set values test uses code from copy and + * values_only_write so would ideally be last so you get a + * simpler test case for problems with copying or values_only + * writing; but it also needs an already-written DataBlock so it + * has to go first. Comment it out if it breaks, and see if the + * later tests also break - debug them first if so. + */ + if (!run_test_set_values (nid)) + goto out; + + if (!run_test_delete_values (nid)) + goto out; + + if (!run_test_copy (nid)) + goto out; + + if (!run_test_values_only_write (nid)) + goto out; + } + + /* FIXME type-iterate both signature and value and compare the resulting + * tree to the node tree perhaps + */ + + retval = TRUE; + + out: + + data_block_reset (nid->block); + + return retval; +} + +static void +run_test_nodes_in_one_configuration (TestTypeNode **nodes, + int n_nodes, + const DBusString *signature, + int byte_order, + int initial_offset) +{ + DataBlock block; + NodeIterationData nid; + + if (!data_block_init (&block, byte_order, initial_offset)) + _dbus_assert_not_reached ("no memory"); + + nid.signature = signature; + nid.block = █ + nid.type_offset = initial_offset; + nid.nodes = nodes; + nid.n_nodes = n_nodes; + + if (TEST_OOM_HANDLING && + n_iterations_expected_this_test <= MAX_ITERATIONS_FOR_EXPENSIVE_TESTS) + { + _dbus_test_oom_handling ("running test node", + run_test_nodes_iteration, + &nid); + } + else + { + if (!run_test_nodes_iteration (&nid)) + _dbus_assert_not_reached ("no memory"); + } + + data_block_free (&block); +} + +static void +run_test_nodes (TestTypeNode **nodes, + int n_nodes) +{ + int i; + DBusString signature; + + if (!_dbus_string_init (&signature)) + _dbus_assert_not_reached ("no memory"); + + i = 0; + while (i < n_nodes) + { + if (! node_build_signature (nodes[i], &signature)) + _dbus_assert_not_reached ("no memory"); + + ++i; + } + + _dbus_verbose (">>> test nodes with signature '%s'\n", + _dbus_string_get_const_data (&signature)); + + i = 0; + while (i <= MAX_INITIAL_OFFSET) + { + run_test_nodes_in_one_configuration (nodes, n_nodes, &signature, + DBUS_LITTLE_ENDIAN, i); + run_test_nodes_in_one_configuration (nodes, n_nodes, &signature, + DBUS_BIG_ENDIAN, i); + + ++i; + } + + n_iterations_completed_this_test += 1; + n_iterations_completed_total += 1; + + if (n_iterations_completed_this_test == n_iterations_expected_this_test) + { + fprintf (stderr, " 100%% %d this test (%d cumulative)\n", + n_iterations_completed_this_test, + n_iterations_completed_total); + } + /* this happens to turn out well with mod == 1 */ + else if ((n_iterations_completed_this_test % + (int)(n_iterations_expected_this_test / 10.0)) == 1) + { + fprintf (stderr, " %d%% ", (int) (n_iterations_completed_this_test / (double) n_iterations_expected_this_test * 100)); + } + + _dbus_string_free (&signature); +} + +#define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS) + +static TestTypeNode* +value_generator (int *ip) +{ + int i = *ip; + const TestTypeNodeClass *child_klass; + const TestTypeNodeClass *container_klass; + TestTypeNode *child; + TestTypeNode *node; + + _dbus_assert (i <= N_VALUES); + + if (i == N_VALUES) + { + return NULL; + } + else if (i < N_BASICS) + { + node = node_new (basic_nodes[i]); + } + else + { + /* imagine an array: + * container 0 of basic 0 + * container 0 of basic 1 + * container 0 of basic 2 + * container 1 of basic 0 + * container 1 of basic 1 + * container 1 of basic 2 + */ + i -= N_BASICS; + + container_klass = container_nodes[i / N_BASICS]; + child_klass = basic_nodes[i % N_BASICS]; + + node = node_new (container_klass); + child = node_new (child_klass); + + node_append_child (node, child); + } + + *ip += 1; /* increment the generator */ + + return node; +} + +static void +build_body (TestTypeNode **nodes, + int n_nodes, + int byte_order, + DBusString *signature, + DBusString *body) +{ + int i; + DataBlock block; + DBusTypeReader reader; + DBusTypeWriter writer; + + i = 0; + while (i < n_nodes) + { + if (! node_build_signature (nodes[i], signature)) + _dbus_assert_not_reached ("no memory"); + + ++i; + } + + if (!data_block_init (&block, byte_order, 0)) + _dbus_assert_not_reached ("no memory"); + + data_block_init_reader_writer (&block, + &reader, &writer); + + /* DBusTypeWriter assumes it's writing into an existing signature, + * so doesn't add nul on its own. We have to do that. + */ + if (!_dbus_string_insert_byte (&block.signature, + 0, '\0')) + _dbus_assert_not_reached ("no memory"); + + i = 0; + while (i < n_nodes) + { + if (!node_write_value (nodes[i], &block, &writer, i)) + _dbus_assert_not_reached ("no memory"); + + ++i; + } + + if (!_dbus_string_copy_len (&block.body, 0, + _dbus_string_get_length (&block.body) - N_FENCE_BYTES, + body, 0)) + _dbus_assert_not_reached ("oom"); + + data_block_free (&block); +} + +dbus_bool_t +dbus_internal_do_not_use_generate_bodies (int sequence, + int byte_order, + DBusString *signature, + DBusString *body) +{ + TestTypeNode *nodes[1]; + int i; + int n_nodes; + + nodes[0] = value_generator (&sequence); + + if (nodes[0] == NULL) + return FALSE; + + n_nodes = 1; + + build_body (nodes, n_nodes, byte_order, signature, body); + + + i = 0; + while (i < n_nodes) + { + node_destroy (nodes[i]); + ++i; + } + + return TRUE; +} + +static void +make_and_run_values_inside_container (const TestTypeNodeClass *container_klass, + int n_nested) +{ + TestTypeNode *root; + TestTypeNode *container; + TestTypeNode *child; + int i; + + root = node_new (container_klass); + container = root; + for (i = 1; i < n_nested; i++) + { + child = node_new (container_klass); + node_append_child (container, child); + container = child; + } + + /* container should now be the most-nested container */ + + i = 0; + while ((child = value_generator (&i))) + { + node_append_child (container, child); + + run_test_nodes (&root, 1); + + _dbus_list_clear (&((TestTypeNodeContainer*)container)->children); + node_destroy (child); + } + + node_destroy (root); +} + +static void +start_next_test (const char *format, + int expected) +{ + n_iterations_completed_this_test = 0; + n_iterations_expected_this_test = expected; + + fprintf (stderr, ">>> >>> "); + fprintf (stderr, format, + n_iterations_expected_this_test); +} + +static void +make_and_run_test_nodes (void) +{ + int i, j, k, m; + + /* We try to do this in order of "complicatedness" so that test + * failures tend to show up in the simplest test case that + * demonstrates the failure. There are also some tests that run + * more than once for this reason, first while going through simple + * cases, second while going through a broader range of complex + * cases. + */ + /* Each basic node. The basic nodes should include: + * + * - each fixed-size type (in such a way that it has different values each time, + * so we can tell if we mix two of them up) + * - strings of various lengths + * - object path + * - signature + */ + /* Each container node. The container nodes should include: + * + * struct with 1 and 2 copies of the contained item + * array with 0, 1, 2 copies of the contained item + * variant + */ + /* Let a "value" be a basic node, or a container containing a single basic node. + * Let n_values be the number of such values i.e. (n_container * n_basic + n_basic) + * When iterating through all values to make combinations, do the basic types + * first and the containers second. + */ + /* Each item is shown with its number of iterations to complete so + * we can keep a handle on this unit test + */ + + /* FIXME test just an empty body, no types at all */ + + start_next_test ("Each value by itself %d iterations\n", N_VALUES); + { + TestTypeNode *node; + i = 0; + while ((node = value_generator (&i))) + { + run_test_nodes (&node, 1); + + node_destroy (node); + } + } + + start_next_test ("Each value by itself with arrays as blocks %d iterations\n", N_VALUES); + arrays_write_fixed_in_blocks = TRUE; + { + TestTypeNode *node; + i = 0; + while ((node = value_generator (&i))) + { + run_test_nodes (&node, 1); + + node_destroy (node); + } + } + arrays_write_fixed_in_blocks = FALSE; + + start_next_test ("All values in one big toplevel %d iteration\n", 1); + { + TestTypeNode *nodes[N_VALUES]; + + i = 0; + while ((nodes[i] = value_generator (&i))) + ; + + run_test_nodes (nodes, N_VALUES); + + for (i = 0; i < N_VALUES; i++) + node_destroy (nodes[i]); + } + + start_next_test ("Each value,value pair combination as toplevel, in both orders %d iterations\n", + N_VALUES * N_VALUES); + { + TestTypeNode *nodes[2]; + + i = 0; + while ((nodes[0] = value_generator (&i))) + { + j = 0; + while ((nodes[1] = value_generator (&j))) + { + run_test_nodes (nodes, 2); + + node_destroy (nodes[1]); + } + + node_destroy (nodes[0]); + } + } + + start_next_test ("Each container containing each value %d iterations\n", + N_CONTAINERS * N_VALUES); + for (i = 0; i < N_CONTAINERS; i++) + { + const TestTypeNodeClass *container_klass = container_nodes[i]; + + make_and_run_values_inside_container (container_klass, 1); + } + + start_next_test ("Each container containing each value with arrays as blocks %d iterations\n", + N_CONTAINERS * N_VALUES); + arrays_write_fixed_in_blocks = TRUE; + for (i = 0; i < N_CONTAINERS; i++) + { + const TestTypeNodeClass *container_klass = container_nodes[i]; + + make_and_run_values_inside_container (container_klass, 1); + } + arrays_write_fixed_in_blocks = FALSE; + + start_next_test ("Each container of same container of each value %d iterations\n", + N_CONTAINERS * N_VALUES); + for (i = 0; i < N_CONTAINERS; i++) + { + const TestTypeNodeClass *container_klass = container_nodes[i]; + + make_and_run_values_inside_container (container_klass, 2); + } + + start_next_test ("Each container of same container of same container of each value %d iterations\n", + N_CONTAINERS * N_VALUES); + for (i = 0; i < N_CONTAINERS; i++) + { + const TestTypeNodeClass *container_klass = container_nodes[i]; + + make_and_run_values_inside_container (container_klass, 3); + } + + start_next_test ("Each value,value pair inside a struct %d iterations\n", + N_VALUES * N_VALUES); + { + TestTypeNode *val1, *val2; + TestTypeNode *node; + + node = node_new (&struct_1_class); + + i = 0; + while ((val1 = value_generator (&i))) + { + j = 0; + while ((val2 = value_generator (&j))) + { + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + + node_append_child (node, val1); + node_append_child (node, val2); + + run_test_nodes (&node, 1); + + _dbus_list_clear (&container->children); + node_destroy (val2); + } + node_destroy (val1); + } + node_destroy (node); + } + + start_next_test ("All values in one big struct %d iteration\n", + 1); + { + TestTypeNode *node; + TestTypeNode *child; + + node = node_new (&struct_1_class); + + i = 0; + while ((child = value_generator (&i))) + node_append_child (node, child); + + run_test_nodes (&node, 1); + + node_destroy (node); + } + + start_next_test ("Each value in a large array %d iterations\n", + N_VALUES); + { + TestTypeNode *val; + TestTypeNode *node; + + node = node_new (&array_9_class); + + i = 0; + while ((val = value_generator (&i))) + { + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + + node_append_child (node, val); + + run_test_nodes (&node, 1); + + _dbus_list_clear (&container->children); + node_destroy (val); + } + + node_destroy (node); + } + + start_next_test ("Each container of each container of each value %d iterations\n", + N_CONTAINERS * N_CONTAINERS * N_VALUES); + for (i = 0; i < N_CONTAINERS; i++) + { + const TestTypeNodeClass *outer_container_klass = container_nodes[i]; + TestTypeNode *outer_container = node_new (outer_container_klass); + + for (j = 0; j < N_CONTAINERS; j++) + { + TestTypeNode *child; + const TestTypeNodeClass *inner_container_klass = container_nodes[j]; + TestTypeNode *inner_container = node_new (inner_container_klass); + + node_append_child (outer_container, inner_container); + + m = 0; + while ((child = value_generator (&m))) + { + node_append_child (inner_container, child); + + run_test_nodes (&outer_container, 1); + + _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children); + node_destroy (child); + } + _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children); + node_destroy (inner_container); + } + node_destroy (outer_container); + } + + start_next_test ("Each container of each container of each container of each value %d iterations\n", + N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES); + for (i = 0; i < N_CONTAINERS; i++) + { + const TestTypeNodeClass *outer_container_klass = container_nodes[i]; + TestTypeNode *outer_container = node_new (outer_container_klass); + + for (j = 0; j < N_CONTAINERS; j++) + { + const TestTypeNodeClass *inner_container_klass = container_nodes[j]; + TestTypeNode *inner_container = node_new (inner_container_klass); + + node_append_child (outer_container, inner_container); + + for (k = 0; k < N_CONTAINERS; k++) + { + TestTypeNode *child; + const TestTypeNodeClass *center_container_klass = container_nodes[k]; + TestTypeNode *center_container = node_new (center_container_klass); + + node_append_child (inner_container, center_container); + + m = 0; + while ((child = value_generator (&m))) + { + node_append_child (center_container, child); + + run_test_nodes (&outer_container, 1); + + _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children); + node_destroy (child); + } + _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children); + node_destroy (center_container); + } + _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children); + node_destroy (inner_container); + } + node_destroy (outer_container); + } + +#if 0 + /* This one takes a really long time, so comment it out for now */ + start_next_test ("Each value,value,value triplet combination as toplevel, in all orders %d iterations\n", + N_VALUES * N_VALUES * N_VALUES); + { + TestTypeNode *nodes[3]; + + i = 0; + while ((nodes[0] = value_generator (&i))) + { + j = 0; + while ((nodes[1] = value_generator (&j))) + { + k = 0; + while ((nodes[2] = value_generator (&k))) + { + run_test_nodes (nodes, 3); + + node_destroy (nodes[2]); + } + node_destroy (nodes[1]); + } + node_destroy (nodes[0]); + } + } +#endif /* #if 0 expensive test */ + + fprintf (stderr, "%d total iterations of recursive marshaling tests\n", + n_iterations_completed_total); + fprintf (stderr, "each iteration ran at initial offsets 0 through %d in both big and little endian\n", + MAX_INITIAL_OFFSET); + fprintf (stderr, "out of memory handling %s tested\n", + TEST_OOM_HANDLING ? "was" : "was not"); +} + +dbus_bool_t +_dbus_marshal_recursive_test (void) +{ + make_and_run_test_nodes (); + + return TRUE; +} + +/* + * + * + * Implementations of each type node class + * + * + * + */ +#define MAX_MULTI_COUNT 5 + +#define SAMPLE_INT16 1234 +#define SAMPLE_INT16_ALTERNATE 6785 +static dbus_int16_t +int16_from_seed (int seed) +{ + /* Generate an integer value that's predictable from seed. We could + * just use seed itself, but that would only ever touch one byte of + * the int so would miss some kinds of bug. + */ + dbus_int16_t v; + + v = 42; /* just to quiet compiler afaik */ + switch (seed % 5) + { + case 0: + v = SAMPLE_INT16; + break; + case 1: + v = SAMPLE_INT16_ALTERNATE; + break; + case 2: + v = -1; + break; + case 3: + v = _DBUS_INT16_MAX; + break; + case 4: + v = 1; + break; + } + + if (seed > 1) + v *= seed; /* wraps around eventually, which is fine */ + + return v; +} + +static dbus_bool_t +int16_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + /* also used for uint16 */ + dbus_int16_t v; + + v = int16_from_seed (seed); + + return _dbus_type_writer_write_basic (writer, + node->klass->typecode, + &v); +} + +static dbus_bool_t +int16_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + /* also used for uint16 */ + dbus_int16_t v; + + check_expected_type (reader, node->klass->typecode); + + _dbus_type_reader_read_basic (reader, + (dbus_int16_t*) &v); + + _dbus_assert (v == int16_from_seed (seed)); + + return TRUE; +} + +static dbus_bool_t +int16_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + /* also used for uint16 */ + dbus_int16_t v; + + v = int16_from_seed (seed); + + return _dbus_type_reader_set_basic (reader, + &v, + realign_root); +} + +static dbus_bool_t +int16_write_multi (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed, + int count) +{ + /* also used for uint16 */ + dbus_int16_t values[MAX_MULTI_COUNT]; + dbus_int16_t *v_ARRAY_INT16 = values; + int i; + + for (i = 0; i < count; ++i) + values[i] = int16_from_seed (seed + i); + + return _dbus_type_writer_write_fixed_multi (writer, + node->klass->typecode, + &v_ARRAY_INT16, count); +} + +static dbus_bool_t +int16_read_multi (TestTypeNode *node, + DBusTypeReader *reader, + int seed, + int count) +{ + /* also used for uint16 */ + dbus_int16_t *values; + int n_elements; + int i; + + check_expected_type (reader, node->klass->typecode); + + _dbus_type_reader_read_fixed_multi (reader, + &values, + &n_elements); + + if (n_elements != count) + _dbus_warn ("got %d elements expected %d\n", n_elements, count); + _dbus_assert (n_elements == count); + + for (i = 0; i < count; i++) + _dbus_assert (((dbus_int16_t)_dbus_unpack_uint16 (reader->byte_order, + (const unsigned char*)values + (i * 2))) == + int16_from_seed (seed + i)); + + return TRUE; +} + + +#define SAMPLE_INT32 12345678 +#define SAMPLE_INT32_ALTERNATE 53781429 +static dbus_int32_t +int32_from_seed (int seed) +{ + /* Generate an integer value that's predictable from seed. We could + * just use seed itself, but that would only ever touch one byte of + * the int so would miss some kinds of bug. + */ + dbus_int32_t v; + + v = 42; /* just to quiet compiler afaik */ + switch (seed % 5) + { + case 0: + v = SAMPLE_INT32; + break; + case 1: + v = SAMPLE_INT32_ALTERNATE; + break; + case 2: + v = -1; + break; + case 3: + v = _DBUS_INT_MAX; + break; + case 4: + v = 1; + break; + } + + if (seed > 1) + v *= seed; /* wraps around eventually, which is fine */ + + return v; +} + +static dbus_bool_t +int32_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + /* also used for uint32 */ + dbus_int32_t v; + + v = int32_from_seed (seed); + + return _dbus_type_writer_write_basic (writer, + node->klass->typecode, + &v); +} + +static dbus_bool_t +int32_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + /* also used for uint32 */ + dbus_int32_t v; + + check_expected_type (reader, node->klass->typecode); + + _dbus_type_reader_read_basic (reader, + (dbus_int32_t*) &v); + + _dbus_assert (v == int32_from_seed (seed)); + + return TRUE; +} + +static dbus_bool_t +int32_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + /* also used for uint32 */ + dbus_int32_t v; + + v = int32_from_seed (seed); + + return _dbus_type_reader_set_basic (reader, + &v, + realign_root); +} + +static dbus_bool_t +int32_write_multi (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed, + int count) +{ + /* also used for uint32 */ + dbus_int32_t values[MAX_MULTI_COUNT]; + dbus_int32_t *v_ARRAY_INT32 = values; + int i; + + for (i = 0; i < count; ++i) + values[i] = int32_from_seed (seed + i); + + return _dbus_type_writer_write_fixed_multi (writer, + node->klass->typecode, + &v_ARRAY_INT32, count); +} + +static dbus_bool_t +int32_read_multi (TestTypeNode *node, + DBusTypeReader *reader, + int seed, + int count) +{ + /* also used for uint32 */ + dbus_int32_t *values; + int n_elements; + int i; + + check_expected_type (reader, node->klass->typecode); + + _dbus_type_reader_read_fixed_multi (reader, + &values, + &n_elements); + + if (n_elements != count) + _dbus_warn ("got %d elements expected %d\n", n_elements, count); + _dbus_assert (n_elements == count); + + for (i = 0; i < count; i++) + _dbus_assert (((int)_dbus_unpack_uint32 (reader->byte_order, + (const unsigned char*)values + (i * 4))) == + int32_from_seed (seed + i)); + + return TRUE; +} + +#ifdef DBUS_HAVE_INT64 +static dbus_int64_t +int64_from_seed (int seed) +{ + dbus_int32_t v32; + dbus_int64_t v; + + v32 = int32_from_seed (seed); + + v = - (dbus_int32_t) ~ v32; + v |= (((dbus_int64_t)v32) << 32); + + return v; +} +#endif + +static dbus_bool_t +int64_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ +#ifdef DBUS_HAVE_INT64 + /* also used for uint64 */ + dbus_int64_t v; + + v = int64_from_seed (seed); + + return _dbus_type_writer_write_basic (writer, + node->klass->typecode, + &v); +#else + return TRUE; +#endif +} + +static dbus_bool_t +int64_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ +#ifdef DBUS_HAVE_INT64 + /* also used for uint64 */ + dbus_int64_t v; + + check_expected_type (reader, node->klass->typecode); + + _dbus_type_reader_read_basic (reader, + (dbus_int64_t*) &v); + + _dbus_assert (v == int64_from_seed (seed)); + + return TRUE; +#else + return TRUE; +#endif +} + +static dbus_bool_t +int64_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ +#ifdef DBUS_HAVE_INT64 + /* also used for uint64 */ + dbus_int64_t v; + + v = int64_from_seed (seed); + + return _dbus_type_reader_set_basic (reader, + &v, + realign_root); +#else + return TRUE; +#endif +} + +#define MAX_SAMPLE_STRING_LEN 10 +static void +string_from_seed (char *buf, + int len, + int seed) +{ + int i; + unsigned char v; + + _dbus_assert (len < MAX_SAMPLE_STRING_LEN); + + /* vary the length slightly, though we also have multiple string + * value types for this, varying it here tests the set_value code + */ + switch (seed % 3) + { + case 1: + len += 2; + break; + case 2: + len -= 2; + break; + } + if (len < 0) + len = 0; + + v = (unsigned char) ('A' + seed); + + i = 0; + while (i < len) + { + if (v < 'A' || v > 'z') + v = 'A'; + + buf[i] = v; + + v += 1; + ++i; + } + + buf[i] = '\0'; +} + +static dbus_bool_t +string_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + char buf[MAX_SAMPLE_STRING_LEN + 1]=""; + const char *v_string = buf; + + + string_from_seed (buf, node->klass->subclass_detail, + seed); + + return _dbus_type_writer_write_basic (writer, + node->klass->typecode, + &v_string); +} + +static dbus_bool_t +string_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + const char *v; + char buf[MAX_SAMPLE_STRING_LEN + 1]; + v = buf; + + check_expected_type (reader, node->klass->typecode); + + _dbus_type_reader_read_basic (reader, + (const char **) &v); + + string_from_seed (buf, node->klass->subclass_detail, + seed); + + if (strcmp (buf, v) != 0) + { + _dbus_warn ("read string '%s' expected '%s'\n", + v, buf); + _dbus_assert_not_reached ("test failed"); + } + + return TRUE; +} + +static dbus_bool_t +string_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + char buf[MAX_SAMPLE_STRING_LEN + 1]; + const char *v_string = buf; + + string_from_seed (buf, node->klass->subclass_detail, + seed); + +#if RECURSIVE_MARSHAL_WRITE_TRACE + { + const char *old; + _dbus_type_reader_read_basic (reader, &old); + _dbus_verbose ("SETTING new string '%s' len %d in place of '%s' len %d\n", + v_string, strlen (v_string), old, strlen (old)); + } +#endif + + return _dbus_type_reader_set_basic (reader, + &v_string, + realign_root); +} + +#define BOOL_FROM_SEED(seed) ((dbus_bool_t)((seed) % 2)) + +static dbus_bool_t +bool_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + dbus_bool_t v; + + v = BOOL_FROM_SEED (seed); + + return _dbus_type_writer_write_basic (writer, + node->klass->typecode, + &v); +} + +static dbus_bool_t +bool_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + dbus_bool_t v; + + check_expected_type (reader, node->klass->typecode); + + _dbus_type_reader_read_basic (reader, + (unsigned char*) &v); + + _dbus_assert (v == BOOL_FROM_SEED (seed)); + + return TRUE; +} + +static dbus_bool_t +bool_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + dbus_bool_t v; + + v = BOOL_FROM_SEED (seed); + + return _dbus_type_reader_set_basic (reader, + &v, + realign_root); +} + +#define BYTE_FROM_SEED(seed) ((unsigned char) int32_from_seed (seed)) + +static dbus_bool_t +byte_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + unsigned char v; + + v = BYTE_FROM_SEED (seed); + + return _dbus_type_writer_write_basic (writer, + node->klass->typecode, + &v); +} + +static dbus_bool_t +byte_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + unsigned char v; + + check_expected_type (reader, node->klass->typecode); + + _dbus_type_reader_read_basic (reader, + (unsigned char*) &v); + + _dbus_assert (v == BYTE_FROM_SEED (seed)); + + return TRUE; +} + + +static dbus_bool_t +byte_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + unsigned char v; + + v = BYTE_FROM_SEED (seed); + + return _dbus_type_reader_set_basic (reader, + &v, + realign_root); +} + +static double +double_from_seed (int seed) +{ + return SAMPLE_INT32 * (double) seed + 0.3; +} + +static dbus_bool_t +double_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + double v; + + v = double_from_seed (seed); + + return _dbus_type_writer_write_basic (writer, + node->klass->typecode, + &v); +} + +static dbus_bool_t +double_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + double v; + double expected; + + check_expected_type (reader, node->klass->typecode); + + _dbus_type_reader_read_basic (reader, + (double*) &v); + + expected = double_from_seed (seed); + + if (!_DBUS_DOUBLES_BITWISE_EQUAL (v, expected)) + { +#ifdef DBUS_INT64_PRINTF_MODIFIER + _dbus_warn ("Expected double %g got %g\n bits = 0x%" DBUS_INT64_PRINTF_MODIFIER "x vs.\n bits = 0x%" DBUS_INT64_PRINTF_MODIFIER "x)\n", + expected, v, + *(dbus_uint64_t*)(char*)&expected, + *(dbus_uint64_t*)(char*)&v); +#endif + _dbus_assert_not_reached ("test failed"); + } + + return TRUE; +} + +static dbus_bool_t +double_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + double v; + + v = double_from_seed (seed); + + return _dbus_type_reader_set_basic (reader, + &v, + realign_root); +} + +#define MAX_SAMPLE_OBJECT_PATH_LEN 10 +static void +object_path_from_seed (char *buf, + int seed) +{ + int i; + unsigned char v; + int len; + + len = seed % 9; + _dbus_assert (len < MAX_SAMPLE_OBJECT_PATH_LEN); + + v = (unsigned char) ('A' + seed); + + if (len < 2) + { + buf[0] = '/'; + i = 1; + } + else + { + i = 0; + while (i + 1 < len) + { + if (v < 'A' || v > 'z') + v = 'A'; + + buf[i] = '/'; + ++i; + buf[i] = v; + ++i; + + v += 1; + } + } + + buf[i] = '\0'; +} + +static dbus_bool_t +object_path_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + char buf[MAX_SAMPLE_OBJECT_PATH_LEN + 1]; + const char *v_string = buf; + + object_path_from_seed (buf, seed); + + return _dbus_type_writer_write_basic (writer, + node->klass->typecode, + &v_string); +} + +static dbus_bool_t +object_path_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + const char *v; + char buf[MAX_SAMPLE_OBJECT_PATH_LEN + 1]; + + check_expected_type (reader, node->klass->typecode); + + _dbus_type_reader_read_basic (reader, + (const char **) &v); + + object_path_from_seed (buf, seed); + + if (strcmp (buf, v) != 0) + { + _dbus_warn ("read object path '%s' expected '%s'\n", + v, buf); + _dbus_assert_not_reached ("test failed"); + } + + return TRUE; +} + +static dbus_bool_t +object_path_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + char buf[MAX_SAMPLE_OBJECT_PATH_LEN + 1]; + const char *v_string = buf; + + object_path_from_seed (buf, seed); + + return _dbus_type_reader_set_basic (reader, + &v_string, + realign_root); +} + +#define MAX_SAMPLE_SIGNATURE_LEN 10 +static void +signature_from_seed (char *buf, + int seed) +{ + /* try to avoid ascending, descending, or alternating length to help find bugs */ + const char *sample_signatures[] = { + "asax" + "", + "asau(xxxx)", + "x", + "ai", + "a(ii)" + }; + + strcpy (buf, sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)]); +} + +static dbus_bool_t +signature_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + char buf[MAX_SAMPLE_SIGNATURE_LEN + 1]; + const char *v_string = buf; + + signature_from_seed (buf, seed); + + return _dbus_type_writer_write_basic (writer, + node->klass->typecode, + &v_string); +} + +static dbus_bool_t +signature_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + const char *v; + char buf[MAX_SAMPLE_SIGNATURE_LEN + 1]; + + check_expected_type (reader, node->klass->typecode); + + _dbus_type_reader_read_basic (reader, + (const char **) &v); + + signature_from_seed (buf, seed); + + if (strcmp (buf, v) != 0) + { + _dbus_warn ("read signature value '%s' expected '%s'\n", + v, buf); + _dbus_assert_not_reached ("test failed"); + } + + return TRUE; +} + + +static dbus_bool_t +signature_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + char buf[MAX_SAMPLE_SIGNATURE_LEN + 1]; + const char *v_string = buf; + + signature_from_seed (buf, seed); + + return _dbus_type_reader_set_basic (reader, + &v_string, + realign_root); +} + +static dbus_bool_t +struct_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + DataBlockState saved; + DBusTypeWriter sub; + int i; + int n_copies; + + n_copies = node->klass->subclass_detail; + + _dbus_assert (container->children != NULL); + + data_block_save (block, &saved); + + if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT, + NULL, 0, + &sub)) + return FALSE; + + i = 0; + while (i < n_copies) + { + DBusList *link; + + link = _dbus_list_get_first_link (&container->children); + while (link != NULL) + { + TestTypeNode *child = link->data; + DBusList *next = _dbus_list_get_next_link (&container->children, link); + + if (!node_write_value (child, block, &sub, seed + i)) + { + data_block_restore (block, &saved); + return FALSE; + } + + link = next; + } + + ++i; + } + + if (!_dbus_type_writer_unrecurse (writer, &sub)) + { + data_block_restore (block, &saved); + return FALSE; + } + + return TRUE; +} + +static dbus_bool_t +struct_read_or_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + DBusTypeReader sub; + int i; + int n_copies; + + n_copies = node->klass->subclass_detail; + + check_expected_type (reader, DBUS_TYPE_STRUCT); + + _dbus_type_reader_recurse (reader, &sub); + + i = 0; + while (i < n_copies) + { + DBusList *link; + + link = _dbus_list_get_first_link (&container->children); + while (link != NULL) + { + TestTypeNode *child = link->data; + DBusList *next = _dbus_list_get_next_link (&container->children, link); + + if (realign_root == NULL) + { + if (!node_read_value (child, &sub, seed + i)) + return FALSE; + } + else + { + if (!node_set_value (child, &sub, realign_root, seed + i)) + return FALSE; + } + + if (i == (n_copies - 1) && next == NULL) + NEXT_EXPECTING_FALSE (&sub); + else + NEXT_EXPECTING_TRUE (&sub); + + link = next; + } + + ++i; + } + + return TRUE; +} + +static dbus_bool_t +struct_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + return struct_read_or_set_value (node, reader, NULL, seed); +} + +static dbus_bool_t +struct_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + return struct_read_or_set_value (node, reader, realign_root, seed); +} + +static dbus_bool_t +struct_build_signature (TestTypeNode *node, + DBusString *str) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + int i; + int orig_len; + int n_copies; + + n_copies = node->klass->subclass_detail; + + orig_len = _dbus_string_get_length (str); + + if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR)) + goto oom; + + i = 0; + while (i < n_copies) + { + DBusList *link; + + link = _dbus_list_get_first_link (&container->children); + while (link != NULL) + { + TestTypeNode *child = link->data; + DBusList *next = _dbus_list_get_next_link (&container->children, link); + + if (!node_build_signature (child, str)) + goto oom; + + link = next; + } + + ++i; + } + + if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR)) + goto oom; + + return TRUE; + + oom: + _dbus_string_set_length (str, orig_len); + return FALSE; +} + +static dbus_bool_t +array_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + DataBlockState saved; + DBusTypeWriter sub; + DBusString element_signature; + int i; + int n_copies; + int element_type; + TestTypeNode *child; + + n_copies = node->klass->subclass_detail; + + _dbus_assert (container->children != NULL); + + data_block_save (block, &saved); + + if (!_dbus_string_init (&element_signature)) + return FALSE; + + child = _dbus_list_get_first (&container->children); + + if (!node_build_signature (child, + &element_signature)) + goto oom; + + element_type = _dbus_first_type_in_signature (&element_signature, 0); + + if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY, + &element_signature, 0, + &sub)) + goto oom; + + if (arrays_write_fixed_in_blocks && + dbus_type_is_fixed (element_type) && + child->klass->write_multi) + { + if (!node_write_multi (child, block, &sub, seed, n_copies)) + goto oom; + } + else + { + i = 0; + while (i < n_copies) + { + DBusList *link; + + link = _dbus_list_get_first_link (&container->children); + while (link != NULL) + { + TestTypeNode *child = link->data; + DBusList *next = _dbus_list_get_next_link (&container->children, link); + + if (!node_write_value (child, block, &sub, seed + i)) + goto oom; + + link = next; + } + + ++i; + } + } + + if (!_dbus_type_writer_unrecurse (writer, &sub)) + goto oom; + + _dbus_string_free (&element_signature); + return TRUE; + + oom: + data_block_restore (block, &saved); + _dbus_string_free (&element_signature); + return FALSE; +} + +static dbus_bool_t +array_read_or_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + DBusTypeReader sub; + int i; + int n_copies; + TestTypeNode *child; + + n_copies = node->klass->subclass_detail; + + check_expected_type (reader, DBUS_TYPE_ARRAY); + + child = _dbus_list_get_first (&container->children); + + if (n_copies > 0) + { + _dbus_type_reader_recurse (reader, &sub); + + if (realign_root == NULL && arrays_write_fixed_in_blocks && + dbus_type_is_fixed (_dbus_type_reader_get_element_type (reader)) && + child->klass->read_multi) + { + if (!node_read_multi (child, &sub, seed, n_copies)) + return FALSE; + } + else + { + i = 0; + while (i < n_copies) + { + DBusList *link; + + link = _dbus_list_get_first_link (&container->children); + while (link != NULL) + { + TestTypeNode *child = link->data; + DBusList *next = _dbus_list_get_next_link (&container->children, link); + + _dbus_assert (child->klass->typecode == + _dbus_type_reader_get_element_type (reader)); + + if (realign_root == NULL) + { + if (!node_read_value (child, &sub, seed + i)) + return FALSE; + } + else + { + if (!node_set_value (child, &sub, realign_root, seed + i)) + return FALSE; + } + + if (i == (n_copies - 1) && next == NULL) + NEXT_EXPECTING_FALSE (&sub); + else + NEXT_EXPECTING_TRUE (&sub); + + link = next; + } + + ++i; + } + } + } + + return TRUE; +} + +static dbus_bool_t +array_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + return array_read_or_set_value (node, reader, NULL, seed); +} + +static dbus_bool_t +array_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + return array_read_or_set_value (node, reader, realign_root, seed); +} + +static dbus_bool_t +array_build_signature (TestTypeNode *node, + DBusString *str) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + int orig_len; + + orig_len = _dbus_string_get_length (str); + + if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY)) + goto oom; + + if (!node_build_signature (_dbus_list_get_first (&container->children), + str)) + goto oom; + + return TRUE; + + oom: + _dbus_string_set_length (str, orig_len); + return FALSE; +} + + /* 10 is random just to add another seed that we use in the suite */ +#define VARIANT_SEED 10 + +static dbus_bool_t +variant_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + DataBlockState saved; + DBusTypeWriter sub; + DBusString content_signature; + TestTypeNode *child; + + _dbus_assert (container->children != NULL); + _dbus_assert (_dbus_list_length_is_one (&container->children)); + + child = _dbus_list_get_first (&container->children); + + data_block_save (block, &saved); + + if (!_dbus_string_init (&content_signature)) + return FALSE; + + if (!node_build_signature (child, + &content_signature)) + goto oom; + + if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_VARIANT, + &content_signature, 0, + &sub)) + goto oom; + + if (!node_write_value (child, block, &sub, seed + VARIANT_SEED)) + goto oom; + + if (!_dbus_type_writer_unrecurse (writer, &sub)) + goto oom; + + _dbus_string_free (&content_signature); + return TRUE; + + oom: + data_block_restore (block, &saved); + _dbus_string_free (&content_signature); + return FALSE; +} + +static dbus_bool_t +variant_read_or_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + DBusTypeReader sub; + TestTypeNode *child; + + _dbus_assert (container->children != NULL); + _dbus_assert (_dbus_list_length_is_one (&container->children)); + + child = _dbus_list_get_first (&container->children); + + check_expected_type (reader, DBUS_TYPE_VARIANT); + + _dbus_type_reader_recurse (reader, &sub); + + if (realign_root == NULL) + { + if (!node_read_value (child, &sub, seed + VARIANT_SEED)) + return FALSE; + } + else + { + if (!node_set_value (child, &sub, realign_root, seed + VARIANT_SEED)) + return FALSE; + } + + NEXT_EXPECTING_FALSE (&sub); + + return TRUE; +} + +static dbus_bool_t +variant_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + return variant_read_or_set_value (node, reader, NULL, seed); +} + +static dbus_bool_t +variant_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + return variant_read_or_set_value (node, reader, realign_root, seed); +} + +static dbus_bool_t +dict_write_value (TestTypeNode *node, + DataBlock *block, + DBusTypeWriter *writer, + int seed) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + DataBlockState saved; + DBusTypeWriter sub; + DBusString entry_value_signature; + DBusString dict_entry_signature; + int i; + int n_entries; + int entry_value_type; + TestTypeNode *child; + + n_entries = node->klass->subclass_detail; + + _dbus_assert (container->children != NULL); + + data_block_save (block, &saved); + + if (!_dbus_string_init (&entry_value_signature)) + return FALSE; + + if (!_dbus_string_init (&dict_entry_signature)) + { + _dbus_string_free (&entry_value_signature); + return FALSE; + } + + child = _dbus_list_get_first (&container->children); + + if (!node_build_signature (child, + &entry_value_signature)) + goto oom; + + if (!_dbus_string_append (&dict_entry_signature, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_INT32_AS_STRING)) + goto oom; + + if (!_dbus_string_copy (&entry_value_signature, 0, + &dict_entry_signature, + _dbus_string_get_length (&dict_entry_signature))) + goto oom; + + if (!_dbus_string_append_byte (&dict_entry_signature, + DBUS_DICT_ENTRY_END_CHAR)) + goto oom; + + entry_value_type = _dbus_first_type_in_signature (&entry_value_signature, 0); + + if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY, + &dict_entry_signature, 0, + &sub)) + goto oom; + + i = 0; + while (i < n_entries) + { + DBusTypeWriter entry_sub; + dbus_int32_t key; + + if (!_dbus_type_writer_recurse (&sub, DBUS_TYPE_DICT_ENTRY, + NULL, 0, + &entry_sub)) + goto oom; + + key = int32_from_seed (seed + i); + + if (!_dbus_type_writer_write_basic (&entry_sub, + DBUS_TYPE_INT32, + &key)) + goto oom; + + if (!node_write_value (child, block, &entry_sub, seed + i)) + goto oom; + + if (!_dbus_type_writer_unrecurse (&sub, &entry_sub)) + goto oom; + + ++i; + } + + if (!_dbus_type_writer_unrecurse (writer, &sub)) + goto oom; + + _dbus_string_free (&entry_value_signature); + _dbus_string_free (&dict_entry_signature); + return TRUE; + + oom: + data_block_restore (block, &saved); + _dbus_string_free (&entry_value_signature); + _dbus_string_free (&dict_entry_signature); + return FALSE; +} + +static dbus_bool_t +dict_read_or_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + DBusTypeReader sub; + int i; + int n_entries; + TestTypeNode *child; + + n_entries = node->klass->subclass_detail; + + check_expected_type (reader, DBUS_TYPE_ARRAY); + + child = _dbus_list_get_first (&container->children); + + if (n_entries > 0) + { + _dbus_type_reader_recurse (reader, &sub); + + check_expected_type (&sub, DBUS_TYPE_DICT_ENTRY); + + i = 0; + while (i < n_entries) + { + DBusTypeReader entry_sub; + + check_expected_type (&sub, DBUS_TYPE_DICT_ENTRY); + + _dbus_type_reader_recurse (&sub, &entry_sub); + + if (realign_root == NULL) + { + dbus_int32_t v; + + check_expected_type (&entry_sub, DBUS_TYPE_INT32); + + _dbus_type_reader_read_basic (&entry_sub, + (dbus_int32_t*) &v); + + _dbus_assert (v == int32_from_seed (seed + i)); + + NEXT_EXPECTING_TRUE (&entry_sub); + + if (!node_read_value (child, &entry_sub, seed + i)) + return FALSE; + + NEXT_EXPECTING_FALSE (&entry_sub); + } + else + { + dbus_int32_t v; + + v = int32_from_seed (seed + i); + + if (!_dbus_type_reader_set_basic (&entry_sub, + &v, + realign_root)) + return FALSE; + + NEXT_EXPECTING_TRUE (&entry_sub); + + if (!node_set_value (child, &entry_sub, realign_root, seed + i)) + return FALSE; + + NEXT_EXPECTING_FALSE (&entry_sub); + } + + if (i == (n_entries - 1)) + NEXT_EXPECTING_FALSE (&sub); + else + NEXT_EXPECTING_TRUE (&sub); + + ++i; + } + } + + return TRUE; +} + +static dbus_bool_t +dict_read_value (TestTypeNode *node, + DBusTypeReader *reader, + int seed) +{ + return dict_read_or_set_value (node, reader, NULL, seed); +} + +static dbus_bool_t +dict_set_value (TestTypeNode *node, + DBusTypeReader *reader, + DBusTypeReader *realign_root, + int seed) +{ + return dict_read_or_set_value (node, reader, realign_root, seed); +} + +static dbus_bool_t +dict_build_signature (TestTypeNode *node, + DBusString *str) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + int orig_len; + + orig_len = _dbus_string_get_length (str); + + if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY)) + goto oom; + + if (!_dbus_string_append (str, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_INT32_AS_STRING)) + goto oom; + + if (!node_build_signature (_dbus_list_get_first (&container->children), + str)) + goto oom; + + if (!_dbus_string_append_byte (str, DBUS_DICT_ENTRY_END_CHAR)) + goto oom; + + return TRUE; + + oom: + _dbus_string_set_length (str, orig_len); + return FALSE; +} + +static void +container_destroy (TestTypeNode *node) +{ + TestTypeNodeContainer *container = (TestTypeNodeContainer*) node; + DBusList *link; + + link = _dbus_list_get_first_link (&container->children); + while (link != NULL) + { + TestTypeNode *child = link->data; + DBusList *next = _dbus_list_get_next_link (&container->children, link); + + node_destroy (child); + + _dbus_list_free_link (link); + + link = next; + } +} + +#endif /* !DOXYGEN_SHOULD_SKIP_THIS */ + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-marshal-recursive.c b/dbus/dbus-marshal-recursive.c new file mode 100644 index 00000000..ccf0d22b --- /dev/null +++ b/dbus/dbus-marshal-recursive.c @@ -0,0 +1,2739 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-recursive.c Marshalling routines for recursive types + * + * Copyright (C) 2004, 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-marshal-recursive.h" +#include "dbus-marshal-basic.h" +#include "dbus-signature.h" +#include "dbus-internals.h" + +/** + * @addtogroup DBusMarshal + * @{ + */ + +/** turn this on to get deluged in TypeReader verbose spam */ +#define RECURSIVE_MARSHAL_READ_TRACE 0 + +/** turn this on to get deluged in TypeWriter verbose spam */ +#define RECURSIVE_MARSHAL_WRITE_TRACE 0 + +static void +free_fixups (DBusList **fixups) +{ + DBusList *link; + + link = _dbus_list_get_first_link (fixups); + while (link != NULL) + { + DBusList *next; + + next = _dbus_list_get_next_link (fixups, link); + + dbus_free (link->data); + _dbus_list_free_link (link); + + link = next; + } + + *fixups = NULL; +} + +static void +apply_and_free_fixups (DBusList **fixups, + DBusTypeReader *reader) +{ + DBusList *link; + +#if RECURSIVE_MARSHAL_WRITE_TRACE + if (*fixups) + _dbus_verbose (" %d FIXUPS to apply\n", + _dbus_list_get_length (fixups)); +#endif + + link = _dbus_list_get_first_link (fixups); + while (link != NULL) + { + DBusList *next; + + next = _dbus_list_get_next_link (fixups, link); + + if (reader) + { + DBusArrayLenFixup *f; + + f = link->data; + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose (" applying FIXUP to reader %p at pos %d new_len = %d old len %d\n", + reader, f->len_pos_in_reader, f->new_len, + _dbus_marshal_read_uint32 (reader->value_str, + f->len_pos_in_reader, + reader->byte_order, NULL)); +#endif + + _dbus_marshal_set_uint32 ((DBusString*) reader->value_str, + f->len_pos_in_reader, + f->new_len, + reader->byte_order); + } + + dbus_free (link->data); + _dbus_list_free_link (link); + + link = next; + } + + *fixups = NULL; +} + +/** + * Virtual table for a type reader. + */ +struct DBusTypeReaderClass +{ + const char *name; /**< name for debugging */ + int id; /**< index in all_reader_classes */ + dbus_bool_t types_only; /**< only iterates over types, not values */ + void (* recurse) (DBusTypeReader *sub, + DBusTypeReader *parent); /**< recurse with this reader as sub */ + dbus_bool_t (* check_finished) (const DBusTypeReader *reader); /**< check whether reader is at the end */ + void (* next) (DBusTypeReader *reader, + int current_type); /**< go to the next value */ +}; + +static int +element_type_get_alignment (const DBusString *str, + int pos) +{ + return _dbus_type_get_alignment (_dbus_first_type_in_signature (str, pos)); +} + +static void +reader_init (DBusTypeReader *reader, + int byte_order, + const DBusString *type_str, + int type_pos, + const DBusString *value_str, + int value_pos) +{ + reader->byte_order = byte_order; + reader->finished = FALSE; + reader->type_str = type_str; + reader->type_pos = type_pos; + reader->value_str = value_str; + reader->value_pos = value_pos; +} + +static void +base_reader_recurse (DBusTypeReader *sub, + DBusTypeReader *parent) +{ + /* point subreader at the same place as parent */ + reader_init (sub, + parent->byte_order, + parent->type_str, + parent->type_pos, + parent->value_str, + parent->value_pos); +} + +static void +struct_or_dict_entry_types_only_reader_recurse (DBusTypeReader *sub, + DBusTypeReader *parent) +{ + base_reader_recurse (sub, parent); + + _dbus_assert (_dbus_string_get_byte (sub->type_str, + sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR || + _dbus_string_get_byte (sub->type_str, + sub->type_pos) == DBUS_DICT_ENTRY_BEGIN_CHAR); + + sub->type_pos += 1; +} + +static void +struct_or_dict_entry_reader_recurse (DBusTypeReader *sub, + DBusTypeReader *parent) +{ + struct_or_dict_entry_types_only_reader_recurse (sub, parent); + + /* struct and dict entry have 8 byte alignment */ + sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8); +} + +static void +array_types_only_reader_recurse (DBusTypeReader *sub, + DBusTypeReader *parent) +{ + base_reader_recurse (sub, parent); + + /* point type_pos at the array element type */ + sub->type_pos += 1; + + /* Init with values likely to crash things if misused */ + sub->u.array.start_pos = _DBUS_INT_MAX; + sub->array_len_offset = 7; +} + +/** compute position of array length given array_len_offset, which is + the offset back from start_pos to end of the len */ +#define ARRAY_READER_LEN_POS(reader) \ + ((reader)->u.array.start_pos - ((int)(reader)->array_len_offset) - 4) + +static int +array_reader_get_array_len (const DBusTypeReader *reader) +{ + dbus_uint32_t array_len; + int len_pos; + + len_pos = ARRAY_READER_LEN_POS (reader); + + _dbus_assert (_DBUS_ALIGN_VALUE (len_pos, 4) == (unsigned) len_pos); + array_len = _dbus_unpack_uint32 (reader->byte_order, + _dbus_string_get_const_data_len (reader->value_str, len_pos, 4)); + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose (" reader %p len_pos %d array len %u len_offset %d\n", + reader, len_pos, array_len, reader->array_len_offset); +#endif + + _dbus_assert (reader->u.array.start_pos - len_pos - 4 < 8); + + return array_len; +} + +static void +array_reader_recurse (DBusTypeReader *sub, + DBusTypeReader *parent) +{ + int alignment; + int len_pos; + + array_types_only_reader_recurse (sub, parent); + + sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4); + + len_pos = sub->value_pos; + + sub->value_pos += 4; /* for the length */ + + alignment = element_type_get_alignment (sub->type_str, + sub->type_pos); + + sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment); + + sub->u.array.start_pos = sub->value_pos; + _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */ + sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4); + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose (" type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n", + sub, + sub->u.array.start_pos, + sub->array_len_offset, + array_reader_get_array_len (sub), + _dbus_type_to_string (_dbus_first_type_in_signature (sub->type_str, + sub->type_pos))); +#endif +} + +static void +variant_reader_recurse (DBusTypeReader *sub, + DBusTypeReader *parent) +{ + int sig_len; + int contained_alignment; + + base_reader_recurse (sub, parent); + + /* Variant is 1 byte sig length (without nul), signature with nul, + * padding to 8-boundary, then values + */ + + sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos); + + sub->type_str = sub->value_str; + sub->type_pos = sub->value_pos + 1; + + sub->value_pos = sub->type_pos + sig_len + 1; + + contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (sub->type_str, + sub->type_pos)); + + sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment); + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose (" type reader %p variant containing '%s'\n", + sub, + _dbus_string_get_const_data_len (sub->type_str, + sub->type_pos, 0)); +#endif +} + +static dbus_bool_t +array_reader_check_finished (const DBusTypeReader *reader) +{ + int end_pos; + + /* return the array element type if elements remain, and + * TYPE_INVALID otherwise + */ + + end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader); + + _dbus_assert (reader->value_pos <= end_pos); + _dbus_assert (reader->value_pos >= reader->u.array.start_pos); + + return reader->value_pos == end_pos; +} + +static void +skip_one_complete_type (const DBusString *type_str, + int *type_pos) +{ + _dbus_type_signature_next (_dbus_string_get_const_data (type_str), + type_pos); +} + +/** + * Skips to the next "complete" type inside a type signature. + * The signature is read starting at type_pos, and the next + * type position is stored in the same variable. + * + * @param type_str a type signature (must be valid) + * @param type_pos an integer position in the type signature (in and out) + */ +void +_dbus_type_signature_next (const char *type_str, + int *type_pos) +{ + const unsigned char *p; + const unsigned char *start; + + _dbus_assert (type_str != NULL); + _dbus_assert (type_pos != NULL); + + start = type_str; + p = start + *type_pos; + + _dbus_assert (*p != DBUS_STRUCT_END_CHAR); + _dbus_assert (*p != DBUS_DICT_ENTRY_END_CHAR); + + while (*p == DBUS_TYPE_ARRAY) + ++p; + + _dbus_assert (*p != DBUS_STRUCT_END_CHAR); + _dbus_assert (*p != DBUS_DICT_ENTRY_END_CHAR); + + if (*p == DBUS_STRUCT_BEGIN_CHAR) + { + int depth; + + depth = 1; + + while (TRUE) + { + _dbus_assert (*p != DBUS_TYPE_INVALID); + + ++p; + + _dbus_assert (*p != DBUS_TYPE_INVALID); + + if (*p == DBUS_STRUCT_BEGIN_CHAR) + depth += 1; + else if (*p == DBUS_STRUCT_END_CHAR) + { + depth -= 1; + if (depth == 0) + { + ++p; + break; + } + } + } + } + else if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR) + { + int depth; + + depth = 1; + + while (TRUE) + { + _dbus_assert (*p != DBUS_TYPE_INVALID); + + ++p; + + _dbus_assert (*p != DBUS_TYPE_INVALID); + + if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR) + depth += 1; + else if (*p == DBUS_DICT_ENTRY_END_CHAR) + { + depth -= 1; + if (depth == 0) + { + ++p; + break; + } + } + } + } + else + { + ++p; + } + + *type_pos = (int) (p - start); +} + +static int +find_len_of_complete_type (const DBusString *type_str, + int type_pos) +{ + int end; + + end = type_pos; + + skip_one_complete_type (type_str, &end); + + return end - type_pos; +} + +static void +base_reader_next (DBusTypeReader *reader, + int current_type) +{ + switch (current_type) + { + case DBUS_TYPE_DICT_ENTRY: + case DBUS_TYPE_STRUCT: + case DBUS_TYPE_VARIANT: + /* Scan forward over the entire container contents */ + { + DBusTypeReader sub; + + if (reader->klass->types_only && current_type == DBUS_TYPE_VARIANT) + ; + else + { + /* Recurse into the struct or variant */ + _dbus_type_reader_recurse (reader, &sub); + + /* Skip everything in this subreader */ + while (_dbus_type_reader_next (&sub)) + { + /* nothing */; + } + } + if (!reader->klass->types_only) + reader->value_pos = sub.value_pos; + + /* Now we are at the end of this container; for variants, the + * subreader's type_pos is totally inapplicable (it's in the + * value string) but we know that we increment by one past the + * DBUS_TYPE_VARIANT + */ + if (current_type == DBUS_TYPE_VARIANT) + reader->type_pos += 1; + else + reader->type_pos = sub.type_pos; + } + break; + + case DBUS_TYPE_ARRAY: + { + if (!reader->klass->types_only) + _dbus_marshal_skip_array (reader->value_str, + _dbus_first_type_in_signature (reader->type_str, + reader->type_pos + 1), + reader->byte_order, + &reader->value_pos); + + skip_one_complete_type (reader->type_str, &reader->type_pos); + } + break; + + default: + if (!reader->klass->types_only) + _dbus_marshal_skip_basic (reader->value_str, + current_type, reader->byte_order, + &reader->value_pos); + + reader->type_pos += 1; + break; + } +} + +static void +struct_reader_next (DBusTypeReader *reader, + int current_type) +{ + int t; + + base_reader_next (reader, current_type); + + /* for STRUCT containers we return FALSE at the end of the struct, + * for INVALID we return FALSE at the end of the signature. + * In both cases we arrange for get_current_type() to return INVALID + * which is defined to happen iff we're at the end (no more next()) + */ + t = _dbus_string_get_byte (reader->type_str, reader->type_pos); + if (t == DBUS_STRUCT_END_CHAR) + { + reader->type_pos += 1; + reader->finished = TRUE; + } +} + +static void +dict_entry_reader_next (DBusTypeReader *reader, + int current_type) +{ + int t; + + base_reader_next (reader, current_type); + + /* for STRUCT containers we return FALSE at the end of the struct, + * for INVALID we return FALSE at the end of the signature. + * In both cases we arrange for get_current_type() to return INVALID + * which is defined to happen iff we're at the end (no more next()) + */ + t = _dbus_string_get_byte (reader->type_str, reader->type_pos); + if (t == DBUS_DICT_ENTRY_END_CHAR) + { + reader->type_pos += 1; + reader->finished = TRUE; + } +} + +static void +array_types_only_reader_next (DBusTypeReader *reader, + int current_type) +{ + /* We have one "element" to be iterated over + * in each array, which is its element type. + * So the finished flag indicates whether we've + * iterated over it yet or not. + */ + reader->finished = TRUE; +} + +static void +array_reader_next (DBusTypeReader *reader, + int current_type) +{ + /* Skip one array element */ + int end_pos; + + end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader); + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose (" reader %p array next START start_pos = %d end_pos = %d value_pos = %d current_type = %s\n", + reader, + reader->u.array.start_pos, + end_pos, reader->value_pos, + _dbus_type_to_string (current_type)); +#endif + + _dbus_assert (reader->value_pos < end_pos); + _dbus_assert (reader->value_pos >= reader->u.array.start_pos); + + switch (_dbus_first_type_in_signature (reader->type_str, + reader->type_pos)) + { + case DBUS_TYPE_DICT_ENTRY: + case DBUS_TYPE_STRUCT: + case DBUS_TYPE_VARIANT: + { + DBusTypeReader sub; + + /* Recurse into the struct or variant */ + _dbus_type_reader_recurse (reader, &sub); + + /* Skip everything in this element */ + while (_dbus_type_reader_next (&sub)) + { + /* nothing */; + } + + /* Now we are at the end of this element */ + reader->value_pos = sub.value_pos; + } + break; + + case DBUS_TYPE_ARRAY: + { + _dbus_marshal_skip_array (reader->value_str, + _dbus_first_type_in_signature (reader->type_str, + reader->type_pos + 1), + reader->byte_order, + &reader->value_pos); + } + break; + + default: + { + _dbus_marshal_skip_basic (reader->value_str, + current_type, reader->byte_order, + &reader->value_pos); + } + break; + } + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose (" reader %p array next END start_pos = %d end_pos = %d value_pos = %d current_type = %s\n", + reader, + reader->u.array.start_pos, + end_pos, reader->value_pos, + _dbus_type_to_string (current_type)); +#endif + + _dbus_assert (reader->value_pos <= end_pos); + + if (reader->value_pos == end_pos) + { + skip_one_complete_type (reader->type_str, + &reader->type_pos); + } +} + +static const DBusTypeReaderClass body_reader_class = { + "body", 0, + FALSE, + NULL, /* body is always toplevel, so doesn't get recursed into */ + NULL, + base_reader_next +}; + +static const DBusTypeReaderClass body_types_only_reader_class = { + "body types", 1, + TRUE, + NULL, /* body is always toplevel, so doesn't get recursed into */ + NULL, + base_reader_next +}; + +static const DBusTypeReaderClass struct_reader_class = { + "struct", 2, + FALSE, + struct_or_dict_entry_reader_recurse, + NULL, + struct_reader_next +}; + +static const DBusTypeReaderClass struct_types_only_reader_class = { + "struct types", 3, + TRUE, + struct_or_dict_entry_types_only_reader_recurse, + NULL, + struct_reader_next +}; + +static const DBusTypeReaderClass dict_entry_reader_class = { + "dict_entry", 4, + FALSE, + struct_or_dict_entry_reader_recurse, + NULL, + dict_entry_reader_next +}; + +static const DBusTypeReaderClass dict_entry_types_only_reader_class = { + "dict_entry types", 5, + TRUE, + struct_or_dict_entry_types_only_reader_recurse, + NULL, + dict_entry_reader_next +}; + +static const DBusTypeReaderClass array_reader_class = { + "array", 6, + FALSE, + array_reader_recurse, + array_reader_check_finished, + array_reader_next +}; + +static const DBusTypeReaderClass array_types_only_reader_class = { + "array types", 7, + TRUE, + array_types_only_reader_recurse, + NULL, + array_types_only_reader_next +}; + +static const DBusTypeReaderClass variant_reader_class = { + "variant", 8, + FALSE, + variant_reader_recurse, + NULL, + base_reader_next +}; + +#ifndef DBUS_DISABLE_ASSERT +static const DBusTypeReaderClass * const +all_reader_classes[] = { + &body_reader_class, + &body_types_only_reader_class, + &struct_reader_class, + &struct_types_only_reader_class, + &dict_entry_reader_class, + &dict_entry_types_only_reader_class, + &array_reader_class, + &array_types_only_reader_class, + &variant_reader_class +}; +#endif + +/** + * Initializes a type reader. + * + * @param reader the reader + * @param byte_order the byte order of the block to read + * @param type_str the signature of the block to read + * @param type_pos location of signature + * @param value_str the string containing values block + * @param value_pos start of values block + */ +void +_dbus_type_reader_init (DBusTypeReader *reader, + int byte_order, + const DBusString *type_str, + int type_pos, + const DBusString *value_str, + int value_pos) +{ + reader->klass = &body_reader_class; + + reader_init (reader, byte_order, type_str, type_pos, + value_str, value_pos); + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n", + reader, reader->type_pos, reader->value_pos, + _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); +#endif +} + +/** + * Like _dbus_type_reader_init() but the iteration is over the + * signature, not over values. + * + * @param reader the reader + * @param type_str the signature string + * @param type_pos location in the signature string + */ +void +_dbus_type_reader_init_types_only (DBusTypeReader *reader, + const DBusString *type_str, + int type_pos) +{ + reader->klass = &body_types_only_reader_class; + + reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */, + type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */); + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose (" type reader %p init types only type_pos = %d remaining sig '%s'\n", + reader, reader->type_pos, + _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); +#endif +} + +/** + * Gets the type of the value the reader is currently pointing to; + * or for a types-only reader gets the type it's currently pointing to. + * If the reader is at the end of a block or end of a container such + * as an array, returns #DBUS_TYPE_INVALID. + * + * @param reader the reader + */ +int +_dbus_type_reader_get_current_type (const DBusTypeReader *reader) +{ + int t; + + if (reader->finished || + (reader->klass->check_finished && + (* reader->klass->check_finished) (reader))) + t = DBUS_TYPE_INVALID; + else + t = _dbus_first_type_in_signature (reader->type_str, + reader->type_pos); + + _dbus_assert (t != DBUS_STRUCT_END_CHAR); + _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR); + _dbus_assert (t != DBUS_DICT_ENTRY_END_CHAR); + _dbus_assert (t != DBUS_DICT_ENTRY_BEGIN_CHAR); + +#if 0 + _dbus_verbose (" type reader %p current type_pos = %d type = %s\n", + reader, reader->type_pos, + _dbus_type_to_string (t)); +#endif + + return t; +} + +/** + * Gets the type of an element of the array the reader is currently + * pointing to. It's an error to call this if + * _dbus_type_reader_get_current_type() doesn't return #DBUS_TYPE_ARRAY + * for this reader. + * + * @param reader the reader + */ +int +_dbus_type_reader_get_element_type (const DBusTypeReader *reader) +{ + int element_type; + + _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY); + + element_type = _dbus_first_type_in_signature (reader->type_str, + reader->type_pos + 1); + + return element_type; +} + +/** + * Gets the current position in the value block + * @param reader the reader + */ +int +_dbus_type_reader_get_value_pos (const DBusTypeReader *reader) +{ + return reader->value_pos; +} + +/** + * Get the address of the marshaled value in the data being read. The + * address may not be aligned; you have to align it to the type of the + * value you want to read. Most of the demarshal routines do this for + * you. + * + * @param reader the reader + * @param value_location the address of the marshaled value + */ +void +_dbus_type_reader_read_raw (const DBusTypeReader *reader, + const unsigned char **value_location) +{ + _dbus_assert (!reader->klass->types_only); + + *value_location = _dbus_string_get_const_data_len (reader->value_str, + reader->value_pos, + 0); +} + +/** + * Reads a basic-typed value, as with _dbus_marshal_read_basic(). + * + * @param reader the reader + * @param value the address of the value + */ +void +_dbus_type_reader_read_basic (const DBusTypeReader *reader, + void *value) +{ + int t; + + _dbus_assert (!reader->klass->types_only); + + t = _dbus_type_reader_get_current_type (reader); + + _dbus_marshal_read_basic (reader->value_str, + reader->value_pos, + t, value, + reader->byte_order, + NULL); + + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n", + reader, reader->type_pos, reader->value_pos, + _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); +#endif +} + +/** + * Returns the number of bytes in the array. + * + * @param reader the reader to read from + * @returns the number of bytes in the array + */ +int +_dbus_type_reader_get_array_length (const DBusTypeReader *reader) +{ + _dbus_assert (!reader->klass->types_only); + _dbus_assert (reader->klass == &array_reader_class); + + return array_reader_get_array_len (reader); +} + +/** + * Reads a block of fixed-length basic values, from the current point + * in an array to the end of the array. Does not work for arrays of + * string or container types. + * + * This function returns the array in-place; it does not make a copy, + * and it does not swap the bytes. + * + * If you ask for #DBUS_TYPE_DOUBLE you will get a "const double*" back + * and the "value" argument should be a "const double**" and so on. + * + * @param reader the reader to read from + * @param value place to return the array values + * @param n_elements place to return number of array elements + */ +void +_dbus_type_reader_read_fixed_multi (const DBusTypeReader *reader, + void *value, + int *n_elements) +{ + int element_type; + int end_pos; + int remaining_len; + int alignment; + int total_len; + + _dbus_assert (!reader->klass->types_only); + _dbus_assert (reader->klass == &array_reader_class); + + element_type = _dbus_first_type_in_signature (reader->type_str, + reader->type_pos); + + _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */ + _dbus_assert (dbus_type_is_fixed (element_type)); + + alignment = _dbus_type_get_alignment (element_type); + + _dbus_assert (reader->value_pos >= reader->u.array.start_pos); + + total_len = array_reader_get_array_len (reader); + end_pos = reader->u.array.start_pos + total_len; + remaining_len = end_pos - reader->value_pos; + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose ("end_pos %d total_len %d remaining_len %d value_pos %d\n", + end_pos, total_len, remaining_len, reader->value_pos); +#endif + + _dbus_assert (remaining_len <= total_len); + + if (remaining_len == 0) + *(const DBusBasicValue**) value = NULL; + else + *(const DBusBasicValue**) value = + (void*) _dbus_string_get_const_data_len (reader->value_str, + reader->value_pos, + remaining_len); + + *n_elements = remaining_len / alignment; + _dbus_assert ((remaining_len % alignment) == 0); + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose (" type reader %p read fixed array type_pos = %d value_pos = %d remaining sig '%s'\n", + reader, reader->type_pos, reader->value_pos, + _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); +#endif +} + +/** + * Initialize a new reader pointing to the first type and + * corresponding value that's a child of the current container. It's + * an error to call this if the current type is a non-container. + * + * Note that DBusTypeReader traverses values, not types. So if you + * have an empty array of array of int, you can't recurse into it. You + * can only recurse into each element. + * + * @param reader the reader + * @param sub a reader to init pointing to the first child + */ +void +_dbus_type_reader_recurse (DBusTypeReader *reader, + DBusTypeReader *sub) +{ + int t; + + t = _dbus_first_type_in_signature (reader->type_str, reader->type_pos); + + switch (t) + { + case DBUS_TYPE_STRUCT: + if (reader->klass->types_only) + sub->klass = &struct_types_only_reader_class; + else + sub->klass = &struct_reader_class; + break; + case DBUS_TYPE_DICT_ENTRY: + if (reader->klass->types_only) + sub->klass = &dict_entry_types_only_reader_class; + else + sub->klass = &dict_entry_reader_class; + break; + case DBUS_TYPE_ARRAY: + if (reader->klass->types_only) + sub->klass = &array_types_only_reader_class; + else + sub->klass = &array_reader_class; + break; + case DBUS_TYPE_VARIANT: + if (reader->klass->types_only) + _dbus_assert_not_reached ("can't recurse into variant typecode"); + else + sub->klass = &variant_reader_class; + break; + default: + _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t)); +#ifndef DBUS_DISABLE_CHECKS + if (t == DBUS_TYPE_INVALID) + _dbus_warn_check_failed ("You can't recurse into an empty array or off the end of a message body\n"); +#endif /* DBUS_DISABLE_CHECKS */ + + _dbus_assert_not_reached ("don't yet handle recursing into this type"); + } + + _dbus_assert (sub->klass == all_reader_classes[sub->klass->id]); + + (* sub->klass->recurse) (sub, reader); + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n", + sub, sub->type_pos, sub->value_pos, + _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0)); +#endif +} + +/** + * Skip to the next value on this "level". e.g. the next field in a + * struct, the next value in an array. Returns FALSE at the end of the + * current container. + * + * @param reader the reader + * @returns FALSE if nothing more to read at or below this level + */ +dbus_bool_t +_dbus_type_reader_next (DBusTypeReader *reader) +{ + int t; + + t = _dbus_type_reader_get_current_type (reader); + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n", + reader, reader->type_pos, reader->value_pos, + _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0), + _dbus_type_to_string (t)); +#endif + + if (t == DBUS_TYPE_INVALID) + return FALSE; + + (* reader->klass->next) (reader, t); + +#if RECURSIVE_MARSHAL_READ_TRACE + _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n", + reader, reader->type_pos, reader->value_pos, + _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0), + _dbus_type_to_string (_dbus_type_reader_get_current_type (reader))); +#endif + + return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID; +} + +/** + * Check whether there's another value on this "level". e.g. the next + * field in a struct, the next value in an array. Returns FALSE at the + * end of the current container. + * + * You probably don't want to use this; it makes for an awkward for/while + * loop. A nicer one is "while ((current_type = get_current_type()) != INVALID)" + * + * @param reader the reader + * @returns FALSE if nothing more to read at or below this level + */ +dbus_bool_t +_dbus_type_reader_has_next (const DBusTypeReader *reader) +{ + /* Not efficient but works for now. */ + DBusTypeReader copy; + + copy = *reader; + return _dbus_type_reader_next (©); +} + +/** + * Gets the string and range of said string containing the signature + * of the current value. Essentially a more complete version of + * _dbus_type_reader_get_current_type() (returns the full type + * rather than only the outside of the onion). + * + * Note though that the first byte in a struct signature is + * #DBUS_STRUCT_BEGIN_CHAR while the current type will be + * #DBUS_TYPE_STRUCT so it isn't true that the first byte of the + * signature is always the same as the current type. Another + * difference is that this function will still return a signature when + * inside an empty array; say you recurse into empty array of int32, + * the signature is "i" but the current type will always be + * #DBUS_TYPE_INVALID since there are no elements to be currently + * pointing to. + * + * @param reader the reader + * @param str_p place to return the string with the type in it + * @param start_p place to return start of the type + * @param len_p place to return the length of the type + */ +void +_dbus_type_reader_get_signature (const DBusTypeReader *reader, + const DBusString **str_p, + int *start_p, + int *len_p) +{ + *str_p = reader->type_str; + *start_p = reader->type_pos; + *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos); +} + +typedef struct +{ + DBusString replacement; /**< Marshaled value including alignment padding */ + int padding; /**< How much of the replacement block is padding */ +} ReplacementBlock; + +static dbus_bool_t +replacement_block_init (ReplacementBlock *block, + DBusTypeReader *reader) +{ + if (!_dbus_string_init (&block->replacement)) + return FALSE; + + /* % 8 is the padding to have the same align properties in + * our replacement string as we do at the position being replaced + */ + block->padding = reader->value_pos % 8; + + if (!_dbus_string_lengthen (&block->replacement, block->padding)) + goto oom; + + return TRUE; + + oom: + _dbus_string_free (&block->replacement); + return FALSE; +} + +static dbus_bool_t +replacement_block_replace (ReplacementBlock *block, + DBusTypeReader *reader, + const DBusTypeReader *realign_root) +{ + DBusTypeWriter writer; + DBusTypeReader realign_reader; + DBusList *fixups; + int orig_len; + + _dbus_assert (realign_root != NULL); + + orig_len = _dbus_string_get_length (&block->replacement); + + realign_reader = *realign_root; + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("INITIALIZING replacement block writer %p at value_pos %d\n", + &writer, _dbus_string_get_length (&block->replacement)); +#endif + _dbus_type_writer_init_values_only (&writer, + realign_reader.byte_order, + realign_reader.type_str, + realign_reader.type_pos, + &block->replacement, + _dbus_string_get_length (&block->replacement)); + + _dbus_assert (realign_reader.value_pos <= reader->value_pos); + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("COPYING from reader at value_pos %d to writer %p starting after value_pos %d\n", + realign_reader.value_pos, &writer, reader->value_pos); +#endif + fixups = NULL; + if (!_dbus_type_writer_write_reader_partial (&writer, + &realign_reader, + reader, + block->padding, + _dbus_string_get_length (&block->replacement) - block->padding, + &fixups)) + goto oom; + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("REPLACEMENT at padding %d len %d\n", block->padding, + _dbus_string_get_length (&block->replacement) - block->padding); + _dbus_verbose_bytes_of_string (&block->replacement, block->padding, + _dbus_string_get_length (&block->replacement) - block->padding); + _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d realign_reader.value_pos %d\n", + reader->value_pos, reader->value_pos % 8, + realign_reader.value_pos - reader->value_pos, + realign_reader.value_pos); + _dbus_verbose_bytes_of_string (reader->value_str, + reader->value_pos, + realign_reader.value_pos - reader->value_pos); +#endif + + /* Move the replacement into position + * (realign_reader should now be at the end of the block to be replaced) + */ + if (!_dbus_string_replace_len (&block->replacement, block->padding, + _dbus_string_get_length (&block->replacement) - block->padding, + (DBusString*) reader->value_str, + reader->value_pos, + realign_reader.value_pos - reader->value_pos)) + goto oom; + + /* Process our fixups now that we can't have an OOM error */ + apply_and_free_fixups (&fixups, reader); + + return TRUE; + + oom: + _dbus_string_set_length (&block->replacement, orig_len); + free_fixups (&fixups); + return FALSE; +} + +static void +replacement_block_free (ReplacementBlock *block) +{ + _dbus_string_free (&block->replacement); +} + +/* In the variable-length case, we have to fix alignment after we insert. + * The strategy is as follows: + * + * - pad a new string to have the same alignment as the + * start of the current basic value + * - write the new basic value + * - copy from the original reader to the new string, + * which will fix the alignment of types following + * the new value + * - this copy has to start at realign_root, + * but not really write anything until it + * passes the value being set + * - as an optimization, we can stop copying + * when the source and dest values are both + * on an 8-boundary, since we know all following + * padding and alignment will be identical + * - copy the new string back to the original + * string, replacing the relevant part of the + * original string + * - now any arrays in the original string that + * contained the replaced string may have the + * wrong length; so we have to fix that + */ +static dbus_bool_t +reader_set_basic_variable_length (DBusTypeReader *reader, + int current_type, + const void *value, + const DBusTypeReader *realign_root) +{ + dbus_bool_t retval; + ReplacementBlock block; + DBusTypeWriter writer; + + _dbus_assert (realign_root != NULL); + + retval = FALSE; + + if (!replacement_block_init (&block, reader)) + return FALSE; + + /* Write the new basic value */ +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("INITIALIZING writer %p to write basic value at value_pos %d of replacement string\n", + &writer, _dbus_string_get_length (&block.replacement)); +#endif + _dbus_type_writer_init_values_only (&writer, + reader->byte_order, + reader->type_str, + reader->type_pos, + &block.replacement, + _dbus_string_get_length (&block.replacement)); +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("WRITING basic value to writer %p (replacement string)\n", &writer); +#endif + if (!_dbus_type_writer_write_basic (&writer, current_type, value)) + goto out; + + if (!replacement_block_replace (&block, + reader, + realign_root)) + goto out; + + retval = TRUE; + + out: + replacement_block_free (&block); + return retval; +} + +static void +reader_set_basic_fixed_length (DBusTypeReader *reader, + int current_type, + const void *value) +{ + _dbus_marshal_set_basic ((DBusString*) reader->value_str, + reader->value_pos, + current_type, + value, + reader->byte_order, + NULL, NULL); +} + +/** + * Sets a new value for the basic type value pointed to by the reader, + * leaving the reader valid to continue reading. Any other readers + * will be invalidated if you set a variable-length type such as a + * string. + * + * The provided realign_root is the reader to start from when + * realigning the data that follows the newly-set value. The reader + * parameter must point to a value below the realign_root parameter. + * If the type being set is fixed-length, then realign_root may be + * #NULL. Only values reachable from realign_root will be realigned, + * so if your string contains other values you will need to deal with + * those somehow yourself. It is OK if realign_root is the same + * reader as the reader parameter, though if you aren't setting the + * root it may not be such a good idea. + * + * @todo DBusTypeReader currently takes "const" versions of the type + * and value strings, and this function modifies those strings by + * casting away the const, which is of course bad if we want to get + * picky. (To be truly clean you'd have an object which contained the + * type and value strings and set_basic would be a method on that + * object... this would also make DBusTypeReader the same thing as + * DBusTypeMark. But since DBusMessage is effectively that object for + * D-Bus it doesn't seem worth creating some random object.) + * + * @todo optimize this by only rewriting until the old and new values + * are at the same alignment. Frequently this should result in only + * replacing the value that's immediately at hand. + * + * @param reader reader indicating where to set a new value + * @param value address of the value to set + * @param realign_root realign from here + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_type_reader_set_basic (DBusTypeReader *reader, + const void *value, + const DBusTypeReader *realign_root) +{ + int current_type; + + _dbus_assert (!reader->klass->types_only); + _dbus_assert (reader->value_str == realign_root->value_str); + _dbus_assert (reader->value_pos >= realign_root->value_pos); + + current_type = _dbus_type_reader_get_current_type (reader); + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose (" SET BASIC type reader %p type_pos = %d value_pos = %d remaining sig '%s' realign_root = %p with value_pos %d current_type = %s\n", + reader, reader->type_pos, reader->value_pos, + _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0), + realign_root, + realign_root ? realign_root->value_pos : -1, + _dbus_type_to_string (current_type)); + _dbus_verbose_bytes_of_string (realign_root->value_str, realign_root->value_pos, + _dbus_string_get_length (realign_root->value_str) - + realign_root->value_pos); +#endif + + _dbus_assert (dbus_type_is_basic (current_type)); + + if (dbus_type_is_fixed (current_type)) + { + reader_set_basic_fixed_length (reader, current_type, value); + return TRUE; + } + else + { + _dbus_assert (realign_root != NULL); + return reader_set_basic_variable_length (reader, current_type, + value, realign_root); + } +} + +/** + * Recursively deletes any value pointed to by the reader, leaving the + * reader valid to continue reading. Any other readers will be + * invalidated. + * + * The provided realign_root is the reader to start from when + * realigning the data that follows the newly-set value. + * See _dbus_type_reader_set_basic() for more details on the + * realign_root paramter. + * + * @todo for now this does not delete the typecodes associated with + * the value, so this function should only be used for array elements. + * + * @param reader reader indicating where to delete a value + * @param realign_root realign from here + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_type_reader_delete (DBusTypeReader *reader, + const DBusTypeReader *realign_root) +{ + dbus_bool_t retval; + ReplacementBlock block; + + _dbus_assert (realign_root != NULL); + _dbus_assert (reader->klass == &array_reader_class); + + retval = FALSE; + + if (!replacement_block_init (&block, reader)) + return FALSE; + + if (!replacement_block_replace (&block, + reader, + realign_root)) + goto out; + + retval = TRUE; + + out: + replacement_block_free (&block); + return retval; +} + +/** + * Compares two readers, which must be iterating over the same value data. + * Returns #TRUE if the first parameter is further along than the second parameter. + * + * @param lhs left-hand-side (first) parameter + * @param rhs left-hand-side (first) parameter + * @returns whether lhs is greater than rhs + */ +dbus_bool_t +_dbus_type_reader_greater_than (const DBusTypeReader *lhs, + const DBusTypeReader *rhs) +{ + _dbus_assert (lhs->value_str == rhs->value_str); + + return lhs->value_pos > rhs->value_pos; +} + +/* + * + * + * DBusTypeWriter + * + * + * + */ + +/** + * Initialize a write iterator, which is used to write out values in + * serialized D-Bus format. + * + * The type_pos passed in is expected to be inside an already-valid, + * though potentially empty, type signature. This means that the byte + * after type_pos must be either #DBUS_TYPE_INVALID (aka nul) or some + * other valid type. #DBusTypeWriter won't enforce that the signature + * is already valid (you can append the nul byte at the end if you + * like), but just be aware that you need the nul byte eventually and + * #DBusTypeWriter isn't going to write it for you. + * + * @param writer the writer to init + * @param byte_order the byte order to marshal into + * @param type_str the string to write typecodes into + * @param type_pos where to insert typecodes + * @param value_str the string to write values into + * @param value_pos where to insert values + * + */ +void +_dbus_type_writer_init (DBusTypeWriter *writer, + int byte_order, + DBusString *type_str, + int type_pos, + DBusString *value_str, + int value_pos) +{ + writer->byte_order = byte_order; + writer->type_str = type_str; + writer->type_pos = type_pos; + writer->value_str = value_str; + writer->value_pos = value_pos; + writer->container_type = DBUS_TYPE_INVALID; + writer->type_pos_is_expectation = FALSE; + writer->enabled = TRUE; + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("writer %p init remaining sig '%s'\n", writer, + writer->type_str ? + _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : + "unknown"); +#endif +} + +/** + * Initialize a write iterator, with the signature to be provided + * later. + * + * @param writer the writer to init + * @param byte_order the byte order to marshal into + * @param value_str the string to write values into + * @param value_pos where to insert values + * + */ +void +_dbus_type_writer_init_types_delayed (DBusTypeWriter *writer, + int byte_order, + DBusString *value_str, + int value_pos) +{ + _dbus_type_writer_init (writer, byte_order, + NULL, 0, value_str, value_pos); +} + +/** + * Adds type string to the writer, if it had none. + * + * @param writer the writer to init + * @param type_str type string to add + * @param type_pos type position + * + */ +void +_dbus_type_writer_add_types (DBusTypeWriter *writer, + DBusString *type_str, + int type_pos) +{ + if (writer->type_str == NULL) /* keeps us from using this as setter */ + { + writer->type_str = type_str; + writer->type_pos = type_pos; + } +} + +/** + * Removes type string from the writer. + * + * @param writer the writer to remove from + */ +void +_dbus_type_writer_remove_types (DBusTypeWriter *writer) +{ + writer->type_str = NULL; + writer->type_pos = -1; +} + +/** + * Like _dbus_type_writer_init(), except the type string + * passed in should correspond to an existing signature that + * matches what you're going to write out. The writer will + * check what you write vs. this existing signature. + * + * @param writer the writer to init + * @param byte_order the byte order to marshal into + * @param type_str the string with signature + * @param type_pos start of signature + * @param value_str the string to write values into + * @param value_pos where to insert values + * + */ +void +_dbus_type_writer_init_values_only (DBusTypeWriter *writer, + int byte_order, + const DBusString *type_str, + int type_pos, + DBusString *value_str, + int value_pos) +{ + _dbus_type_writer_init (writer, byte_order, + (DBusString*)type_str, type_pos, + value_str, value_pos); + + writer->type_pos_is_expectation = TRUE; +} + +static dbus_bool_t +_dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer, + int type, + const void *value) +{ + if (writer->enabled) + return _dbus_marshal_write_basic (writer->value_str, + writer->value_pos, + type, + value, + writer->byte_order, + &writer->value_pos); + else + return TRUE; +} + +/* If our parent is an array, things are a little bit complicated. + * + * The parent must have a complete element type, such as + * "i" or "aai" or "(ii)" or "a(ii)". There can't be + * unclosed parens, or an "a" with no following type. + * + * To recurse, the only allowed operation is to recurse into the + * first type in the element type. So for "i" you can't recurse, for + * "ai" you can recurse into the array, for "(ii)" you can recurse + * into the struct. + * + * If you recurse into the array for "ai", then you must specify + * "i" for the element type of the array you recurse into. + * + * While inside an array at any level, we need to avoid writing to + * type_str, since the type only appears once for the whole array, + * it does not appear for each array element. + * + * While inside an array type_pos points to the expected next + * typecode, rather than the next place we could write a typecode. + */ +static void +writer_recurse_init_and_check (DBusTypeWriter *writer, + int container_type, + DBusTypeWriter *sub) +{ + _dbus_type_writer_init (sub, + writer->byte_order, + writer->type_str, + writer->type_pos, + writer->value_str, + writer->value_pos); + + sub->container_type = container_type; + + if (writer->type_pos_is_expectation || + (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT)) + sub->type_pos_is_expectation = TRUE; + else + sub->type_pos_is_expectation = FALSE; + + sub->enabled = writer->enabled; + +#ifndef DBUS_DISABLE_CHECKS + if (writer->type_pos_is_expectation && writer->type_str) + { + int expected; + + expected = _dbus_first_type_in_signature (writer->type_str, writer->type_pos); + + if (expected != sub->container_type) + { + if (expected != DBUS_TYPE_INVALID) + _dbus_warn_check_failed ("Writing an element of type %s, but the expected type here is %s\n" + "The overall signature expected here was '%s' and we are on byte %d of that signature.\n", + _dbus_type_to_string (sub->container_type), + _dbus_type_to_string (expected), + _dbus_string_get_const_data (writer->type_str), writer->type_pos); + else + _dbus_warn_check_failed ("Writing an element of type %s, but no value is expected here\n" + "The overall signature expected here was '%s' and we are on byte %d of that signature.\n", + _dbus_type_to_string (sub->container_type), + _dbus_string_get_const_data (writer->type_str), writer->type_pos); + + _dbus_assert_not_reached ("bad array element or variant content written"); + } + } +#endif /* DBUS_DISABLE_CHECKS */ + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose (" type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s' enabled = %d\n", + writer, + _dbus_type_to_string (writer->container_type), + writer->type_pos, writer->value_pos, writer->type_pos_is_expectation, + writer->type_str ? + _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : + "unknown", + writer->enabled); + _dbus_verbose (" type writer %p recurse sub %s type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n", + sub, + _dbus_type_to_string (sub->container_type), + sub->type_pos, sub->value_pos, + sub->type_pos_is_expectation, + sub->enabled); +#endif +} + +static dbus_bool_t +write_or_verify_typecode (DBusTypeWriter *writer, + int typecode) +{ + /* A subwriter inside an array or variant will have type_pos + * pointing to the expected typecode; a writer not inside an array + * or variant has type_pos pointing to the next place to insert a + * typecode. + */ +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose (" type writer %p write_or_verify start type_pos = %d remaining sig '%s' enabled = %d\n", + writer, writer->type_pos, + writer->type_str ? + _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : + "unknown", + writer->enabled); +#endif + + if (writer->type_str == NULL) + return TRUE; + + if (writer->type_pos_is_expectation) + { +#ifndef DBUS_DISABLE_CHECKS + { + int expected; + + expected = _dbus_string_get_byte (writer->type_str, writer->type_pos); + + if (expected != typecode) + { + if (expected != DBUS_TYPE_INVALID) + _dbus_warn_check_failed ("Array or variant type requires that type %s be written, but %s was written.\n" + "The overall signature expected here was '%s' and we are on byte %d of that signature.\n", + _dbus_type_to_string (expected), _dbus_type_to_string (typecode), + _dbus_string_get_const_data (writer->type_str), writer->type_pos); + else + _dbus_warn_check_failed ("Array or variant type wasn't expecting any more values to be written into it, but a value %s was written.\n" + "The overall signature expected here was '%s' and we are on byte %d of that signature.\n", + _dbus_type_to_string (typecode), + _dbus_string_get_const_data (writer->type_str), writer->type_pos); + _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant"); + } + } +#endif /* DBUS_DISABLE_CHECKS */ + + /* if immediately inside an array we'd always be appending an element, + * so the expected type doesn't change; if inside a struct or something + * below an array, we need to move through said struct or something. + */ + if (writer->container_type != DBUS_TYPE_ARRAY) + writer->type_pos += 1; + } + else + { + if (!_dbus_string_insert_byte (writer->type_str, + writer->type_pos, + typecode)) + return FALSE; + + writer->type_pos += 1; + } + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose (" type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n", + writer, writer->type_pos, + _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0)); +#endif + + return TRUE; +} + +static dbus_bool_t +writer_recurse_struct_or_dict_entry (DBusTypeWriter *writer, + int begin_char, + const DBusString *contained_type, + int contained_type_start, + int contained_type_len, + DBusTypeWriter *sub) +{ + /* FIXME right now contained_type is ignored; we could probably + * almost trivially fix the code so if it's present we + * write it out and then set type_pos_is_expectation + */ + + /* Ensure that we'll be able to add alignment padding and the typecode */ + if (writer->enabled) + { + if (!_dbus_string_alloc_space (sub->value_str, 8)) + return FALSE; + } + + if (!write_or_verify_typecode (sub, begin_char)) + _dbus_assert_not_reached ("failed to insert struct typecode after prealloc"); + + if (writer->enabled) + { + if (!_dbus_string_insert_bytes (sub->value_str, + sub->value_pos, + _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos, + '\0')) + _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct"); + sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8); + } + + return TRUE; +} + + +static dbus_bool_t +writer_recurse_array (DBusTypeWriter *writer, + const DBusString *contained_type, + int contained_type_start, + int contained_type_len, + DBusTypeWriter *sub, + dbus_bool_t is_array_append) +{ + dbus_uint32_t value = 0; + int alignment; + int aligned; + +#ifndef DBUS_DISABLE_CHECKS + if (writer->container_type == DBUS_TYPE_ARRAY && + writer->type_str) + { + if (!_dbus_string_equal_substring (contained_type, + contained_type_start, + contained_type_len, + writer->type_str, + writer->u.array.element_type_pos + 1)) + { + _dbus_warn_check_failed ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n", + _dbus_string_get_const_data_len (contained_type, + contained_type_start, + contained_type_len)); + _dbus_assert_not_reached ("incompatible type for child array"); + } + } +#endif /* DBUS_DISABLE_CHECKS */ + + if (writer->enabled && !is_array_append) + { + /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding + * before array values + */ + if (!_dbus_string_alloc_space (sub->value_str, 3 + 4 + 4)) + return FALSE; + } + + if (writer->type_str != NULL) + { + sub->type_pos += 1; /* move to point to the element type, since type_pos + * should be the expected type for further writes + */ + sub->u.array.element_type_pos = sub->type_pos; + } + + if (!writer->type_pos_is_expectation) + { + /* sub is a toplevel/outermost array so we need to write the type data */ + + /* alloc space for array typecode, element signature */ + if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len)) + return FALSE; + + if (!_dbus_string_insert_byte (writer->type_str, + writer->type_pos, + DBUS_TYPE_ARRAY)) + _dbus_assert_not_reached ("failed to insert array typecode after prealloc"); + + if (!_dbus_string_copy_len (contained_type, + contained_type_start, contained_type_len, + sub->type_str, + sub->u.array.element_type_pos)) + _dbus_assert_not_reached ("should not have failed to insert array element typecodes"); + } + + if (writer->type_str != NULL) + { + /* If the parent is an array, we hold type_pos pointing at the array element type; + * otherwise advance it to reflect the array value we just recursed into + */ + if (writer->container_type != DBUS_TYPE_ARRAY) + writer->type_pos += 1 + contained_type_len; + else + _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */ + } + + if (writer->enabled) + { + /* Write (or jump over, if is_array_append) the length */ + sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4); + + if (is_array_append) + { + sub->value_pos += 4; + } + else + { + if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32, + &value)) + _dbus_assert_not_reached ("should not have failed to insert array len"); + } + + _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4); + + /* Write alignment padding for array elements + * Note that we write the padding *even for empty arrays* + * to avoid wonky special cases + */ + alignment = element_type_get_alignment (contained_type, contained_type_start); + + aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment); + if (aligned != sub->value_pos) + { + if (!is_array_append) + { + if (!_dbus_string_insert_bytes (sub->value_str, + sub->value_pos, + aligned - sub->value_pos, + '\0')) + _dbus_assert_not_reached ("should not have failed to insert alignment padding"); + } + + sub->value_pos = aligned; + } + + sub->u.array.start_pos = sub->value_pos; + + if (is_array_append) + { + dbus_uint32_t len; + + _dbus_assert (_DBUS_ALIGN_VALUE (sub->u.array.len_pos, 4) == + (unsigned) sub->u.array.len_pos); + len = _dbus_unpack_uint32 (sub->byte_order, + _dbus_string_get_const_data_len (sub->value_str, + sub->u.array.len_pos, + 4)); + + sub->value_pos += len; + } + } + else + { + /* not enabled, so we won't write the len_pos; set it to -1 to so indicate */ + sub->u.array.len_pos = -1; + sub->u.array.start_pos = sub->value_pos; + } + + _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos); + _dbus_assert (is_array_append || sub->u.array.start_pos == sub->value_pos); + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose (" type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d value_pos = %d\n", sub, + sub->type_str ? + _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0) : + "unknown", + sub->u.array.start_pos, sub->u.array.len_pos, sub->value_pos); +#endif + + return TRUE; +} + +/* Variant value will normally have: + * 1 byte signature length not including nul + * signature typecodes (nul terminated) + * padding to alignment of contained type + * body according to signature + * + * The signature string can only have a single type + * in it but that type may be complex/recursive. + * + * So a typical variant type with the integer 3 will have these + * octets: + * 0x1 'i' '\0' [1 byte padding to alignment boundary] 0x0 0x0 0x0 0x3 + * + * The main world of hurt for writing out a variant is that the type + * string is the same string as the value string. Which means + * inserting to the type string will move the value_pos; and it means + * that inserting to the type string could break type alignment. + */ +static dbus_bool_t +writer_recurse_variant (DBusTypeWriter *writer, + const DBusString *contained_type, + int contained_type_start, + int contained_type_len, + DBusTypeWriter *sub) +{ + int contained_alignment; + + if (writer->enabled) + { + /* Allocate space for the worst case, which is 1 byte sig + * length, nul byte at end of sig, and 7 bytes padding to + * 8-boundary. + */ + if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9)) + return FALSE; + } + + /* write VARIANT typecode to the parent's type string */ + if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT)) + return FALSE; + + /* If not enabled, mark that we have no type_str anymore ... */ + + if (!writer->enabled) + { + sub->type_str = NULL; + sub->type_pos = -1; + + return TRUE; + } + + /* If we're enabled then continue ... */ + + if (!_dbus_string_insert_byte (sub->value_str, + sub->value_pos, + contained_type_len)) + _dbus_assert_not_reached ("should not have failed to insert variant type sig len"); + + sub->value_pos += 1; + + /* Here we switch over to the expected type sig we're about to write */ + sub->type_str = sub->value_str; + sub->type_pos = sub->value_pos; + + if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len, + sub->value_str, sub->value_pos)) + _dbus_assert_not_reached ("should not have failed to insert variant type sig"); + + sub->value_pos += contained_type_len; + + if (!_dbus_string_insert_byte (sub->value_str, + sub->value_pos, + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("should not have failed to insert variant type nul termination"); + + sub->value_pos += 1; + + contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (contained_type, contained_type_start)); + + if (!_dbus_string_insert_bytes (sub->value_str, + sub->value_pos, + _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment) - sub->value_pos, + '\0')) + _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body"); + sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment); + + return TRUE; +} + +static dbus_bool_t +_dbus_type_writer_recurse_contained_len (DBusTypeWriter *writer, + int container_type, + const DBusString *contained_type, + int contained_type_start, + int contained_type_len, + DBusTypeWriter *sub, + dbus_bool_t is_array_append) +{ + writer_recurse_init_and_check (writer, container_type, sub); + + switch (container_type) + { + case DBUS_TYPE_STRUCT: + return writer_recurse_struct_or_dict_entry (writer, + DBUS_STRUCT_BEGIN_CHAR, + contained_type, + contained_type_start, contained_type_len, + sub); + break; + case DBUS_TYPE_DICT_ENTRY: + return writer_recurse_struct_or_dict_entry (writer, + DBUS_DICT_ENTRY_BEGIN_CHAR, + contained_type, + contained_type_start, contained_type_len, + sub); + break; + case DBUS_TYPE_ARRAY: + return writer_recurse_array (writer, + contained_type, contained_type_start, contained_type_len, + sub, is_array_append); + break; + case DBUS_TYPE_VARIANT: + return writer_recurse_variant (writer, + contained_type, contained_type_start, contained_type_len, + sub); + break; + default: + _dbus_assert_not_reached ("tried to recurse into type that doesn't support that"); + return FALSE; + break; + } +} + +/** + * Opens a new container and writes out the initial information for that container. + * + * @param writer the writer + * @param container_type the type of the container to open + * @param contained_type the array element type or variant content type + * @param contained_type_start position to look for the type + * @param sub the new sub-writer to write container contents + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_type_writer_recurse (DBusTypeWriter *writer, + int container_type, + const DBusString *contained_type, + int contained_type_start, + DBusTypeWriter *sub) +{ + int contained_type_len; + + if (contained_type) + contained_type_len = find_len_of_complete_type (contained_type, contained_type_start); + else + contained_type_len = 0; + + return _dbus_type_writer_recurse_contained_len (writer, container_type, + contained_type, + contained_type_start, + contained_type_len, + sub, + FALSE); +} + +/** + * Append to an existing array. Essentially, the writer will read an + * existing length at the write location; jump over that length; and + * write new fields. On unrecurse(), the existing length will be + * updated. + * + * @param writer the writer + * @param contained_type element type + * @param contained_type_start position of element type + * @param sub the subwriter to init + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_type_writer_append_array (DBusTypeWriter *writer, + const DBusString *contained_type, + int contained_type_start, + DBusTypeWriter *sub) +{ + int contained_type_len; + + if (contained_type) + contained_type_len = find_len_of_complete_type (contained_type, contained_type_start); + else + contained_type_len = 0; + + return _dbus_type_writer_recurse_contained_len (writer, DBUS_TYPE_ARRAY, + contained_type, + contained_type_start, + contained_type_len, + sub, + TRUE); +} + +static int +writer_get_array_len (DBusTypeWriter *writer) +{ + _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY); + return writer->value_pos - writer->u.array.start_pos; +} + +/** + * Closes a container created by _dbus_type_writer_recurse() + * and writes any additional information to the values block. + * + * @param writer the writer + * @param sub the sub-writer created by _dbus_type_writer_recurse() + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_type_writer_unrecurse (DBusTypeWriter *writer, + DBusTypeWriter *sub) +{ + /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */ + _dbus_assert (!writer->type_pos_is_expectation || + (writer->type_pos_is_expectation && sub->type_pos_is_expectation)); + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n", + writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation, + _dbus_type_to_string (writer->container_type)); + _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n", + sub, sub->type_pos, sub->value_pos, + sub->type_pos_is_expectation, + _dbus_type_to_string (sub->container_type)); +#endif + + if (sub->container_type == DBUS_TYPE_STRUCT) + { + if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR)) + return FALSE; + } + else if (sub->container_type == DBUS_TYPE_DICT_ENTRY) + { + if (!write_or_verify_typecode (sub, DBUS_DICT_ENTRY_END_CHAR)) + return FALSE; + } + else if (sub->container_type == DBUS_TYPE_ARRAY) + { + if (sub->u.array.len_pos >= 0) /* len_pos == -1 if we weren't enabled when we passed it */ + { + dbus_uint32_t len; + + /* Set the array length */ + len = writer_get_array_len (sub); + _dbus_marshal_set_uint32 (sub->value_str, + sub->u.array.len_pos, + len, + sub->byte_order); +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose (" filled in sub array len to %u at len_pos %d\n", + len, sub->u.array.len_pos); +#endif + } +#if RECURSIVE_MARSHAL_WRITE_TRACE + else + { + _dbus_verbose (" not filling in sub array len because we were disabled when we passed the len\n"); + } +#endif + } + + /* Now get type_pos right for the parent writer. Here are the cases: + * + * Cases !writer->type_pos_is_expectation: + * (in these cases we want to update to the new insertion point) + * + * - if we recursed into a STRUCT then we didn't know in advance + * what the types in the struct would be; so we have to fill in + * that information now. + * writer->type_pos = sub->type_pos + * + * - if we recursed into anything else, we knew the full array + * type, or knew the single typecode marking VARIANT, so + * writer->type_pos is already correct. + * writer->type_pos should remain as-is + * + * - note that the parent is never an ARRAY or VARIANT, if it were + * then type_pos_is_expectation would be TRUE. The parent + * is thus known to be a toplevel or STRUCT. + * + * Cases where writer->type_pos_is_expectation: + * (in these cases we want to update to next expected type to write) + * + * - we recursed from STRUCT into STRUCT and we didn't increment + * type_pos in the parent just to stay consistent with the + * !writer->type_pos_is_expectation case (though we could + * special-case this in recurse_struct instead if we wanted) + * writer->type_pos = sub->type_pos + * + * - we recursed from STRUCT into ARRAY or VARIANT and type_pos + * for parent should have been incremented already + * writer->type_pos should remain as-is + * + * - we recursed from ARRAY into a sub-element, so type_pos in the + * parent is the element type and should remain the element type + * for the benefit of the next child element + * writer->type_pos should remain as-is + * + * - we recursed from VARIANT into its value, so type_pos in the + * parent makes no difference since there's only one value + * and we just finished writing it and won't use type_pos again + * writer->type_pos should remain as-is + * + * + * For all these, DICT_ENTRY is the same as STRUCT + */ + if (writer->type_str != NULL) + { + if ((sub->container_type == DBUS_TYPE_STRUCT || + sub->container_type == DBUS_TYPE_DICT_ENTRY) && + (writer->container_type == DBUS_TYPE_STRUCT || + writer->container_type == DBUS_TYPE_DICT_ENTRY || + writer->container_type == DBUS_TYPE_INVALID)) + { + /* Advance the parent to the next struct field */ + writer->type_pos = sub->type_pos; + } + } + + writer->value_pos = sub->value_pos; + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose (" type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n", + writer, writer->type_pos, writer->value_pos, + writer->type_str ? + _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) : + "unknown"); +#endif + + return TRUE; +} + +/** + * Writes out a basic type. + * + * @param writer the writer + * @param type the type to write + * @param value the address of the value to write + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_type_writer_write_basic (DBusTypeWriter *writer, + int type, + const void *value) +{ + dbus_bool_t retval; + + /* First ensure that our type realloc will succeed */ + if (!writer->type_pos_is_expectation && writer->type_str != NULL) + { + if (!_dbus_string_alloc_space (writer->type_str, 1)) + return FALSE; + } + + retval = FALSE; + + if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value)) + goto out; + + if (!write_or_verify_typecode (writer, type)) + _dbus_assert_not_reached ("failed to write typecode after prealloc"); + + retval = TRUE; + + out: +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose (" type writer %p basic type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n", + writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation, + writer->enabled); +#endif + + return retval; +} + +/** + * Writes a block of fixed-length basic values, i.e. those that are + * both dbus_type_is_fixed() and _dbus_type_is_basic(). The block + * must be written inside an array. + * + * The value parameter should be the address of said array of values, + * so e.g. if it's an array of double, pass in "const double**" + * + * @param writer the writer + * @param element_type type of stuff in the array + * @param value address of the array + * @param n_elements number of elements in the array + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_type_writer_write_fixed_multi (DBusTypeWriter *writer, + int element_type, + const void *value, + int n_elements) +{ + _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY); + _dbus_assert (dbus_type_is_fixed (element_type)); + _dbus_assert (writer->type_pos_is_expectation); + _dbus_assert (n_elements >= 0); + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose (" type writer %p entering fixed multi type_pos = %d value_pos = %d n_elements %d\n", + writer, writer->type_pos, writer->value_pos, n_elements); +#endif + + if (!write_or_verify_typecode (writer, element_type)) + _dbus_assert_not_reached ("OOM should not happen if only verifying typecode"); + + if (writer->enabled) + { + if (!_dbus_marshal_write_fixed_multi (writer->value_str, + writer->value_pos, + element_type, + value, + n_elements, + writer->byte_order, + &writer->value_pos)) + return FALSE; + } + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose (" type writer %p fixed multi written new type_pos = %d new value_pos = %d n_elements %d\n", + writer, writer->type_pos, writer->value_pos, n_elements); +#endif + + return TRUE; +} + +static void +enable_if_after (DBusTypeWriter *writer, + DBusTypeReader *reader, + const DBusTypeReader *start_after) +{ + if (start_after) + { + if (!writer->enabled && _dbus_type_reader_greater_than (reader, start_after)) + { + _dbus_type_writer_set_enabled (writer, TRUE); +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("ENABLING writer %p at %d because reader at value_pos %d is after reader at value_pos %d\n", + writer, writer->value_pos, reader->value_pos, start_after->value_pos); +#endif + } + + _dbus_assert ((!writer->enabled && !_dbus_type_reader_greater_than (reader, start_after)) || + (writer->enabled && _dbus_type_reader_greater_than (reader, start_after))); + } +} + +static dbus_bool_t +append_fixup (DBusList **fixups, + const DBusArrayLenFixup *fixup) +{ + DBusArrayLenFixup *f; + + f = dbus_new (DBusArrayLenFixup, 1); + if (f == NULL) + return FALSE; + + *f = *fixup; + + if (!_dbus_list_append (fixups, f)) + { + dbus_free (f); + return FALSE; + } + + _dbus_assert (f->len_pos_in_reader == fixup->len_pos_in_reader); + _dbus_assert (f->new_len == fixup->new_len); + + return TRUE; +} + +/* This loop is trivial if you ignore all the start_after nonsense, + * so if you're trying to figure it out, start by ignoring that + */ +static dbus_bool_t +writer_write_reader_helper (DBusTypeWriter *writer, + DBusTypeReader *reader, + const DBusTypeReader *start_after, + int start_after_new_pos, + int start_after_new_len, + DBusList **fixups, + dbus_bool_t inside_start_after) +{ + int current_type; + + while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID) + { + if (dbus_type_is_container (current_type)) + { + DBusTypeReader subreader; + DBusTypeWriter subwriter; + const DBusString *sig_str; + int sig_start; + int sig_len; + dbus_bool_t enabled_at_recurse; + dbus_bool_t past_start_after; + int reader_array_len_pos; + int reader_array_start_pos; + dbus_bool_t this_is_start_after; + + /* type_pos is checked since e.g. in a struct the struct + * and its first field have the same value_pos. + * type_str will differ in reader/start_after for variants + * where type_str is inside the value_str + */ + if (!inside_start_after && start_after && + reader->value_pos == start_after->value_pos && + reader->type_str == start_after->type_str && + reader->type_pos == start_after->type_pos) + this_is_start_after = TRUE; + else + this_is_start_after = FALSE; + + _dbus_type_reader_recurse (reader, &subreader); + + if (current_type == DBUS_TYPE_ARRAY) + { + reader_array_len_pos = ARRAY_READER_LEN_POS (&subreader); + reader_array_start_pos = subreader.u.array.start_pos; + } + else + { + /* quiet gcc */ + reader_array_len_pos = -1; + reader_array_start_pos = -1; + } + + _dbus_type_reader_get_signature (&subreader, &sig_str, + &sig_start, &sig_len); + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("about to recurse into %s reader at %d subreader at %d writer at %d start_after reader at %d write target len %d inside_start_after = %d this_is_start_after = %d\n", + _dbus_type_to_string (current_type), + reader->value_pos, + subreader.value_pos, + writer->value_pos, + start_after ? start_after->value_pos : -1, + _dbus_string_get_length (writer->value_str), + inside_start_after, this_is_start_after); +#endif + + if (!inside_start_after && !this_is_start_after) + enable_if_after (writer, &subreader, start_after); + enabled_at_recurse = writer->enabled; + if (!_dbus_type_writer_recurse_contained_len (writer, current_type, + sig_str, sig_start, sig_len, + &subwriter, FALSE)) + goto oom; + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("recursed into subwriter at %d write target len %d\n", + subwriter.value_pos, + _dbus_string_get_length (subwriter.value_str)); +#endif + + if (!writer_write_reader_helper (&subwriter, &subreader, start_after, + start_after_new_pos, start_after_new_len, + fixups, + inside_start_after || + this_is_start_after)) + goto oom; + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("about to unrecurse from %s subreader at %d writer at %d subwriter at %d write target len %d\n", + _dbus_type_to_string (current_type), + subreader.value_pos, + writer->value_pos, + subwriter.value_pos, + _dbus_string_get_length (writer->value_str)); +#endif + + if (!inside_start_after && !this_is_start_after) + enable_if_after (writer, &subreader, start_after); + past_start_after = writer->enabled; + if (!_dbus_type_writer_unrecurse (writer, &subwriter)) + goto oom; + + /* If we weren't enabled when we recursed, we didn't + * write an array len; if we passed start_after + * somewhere inside the array, then we need to generate + * a fixup. + */ + if (start_after != NULL && + !enabled_at_recurse && past_start_after && + current_type == DBUS_TYPE_ARRAY && + fixups != NULL) + { + DBusArrayLenFixup fixup; + int bytes_written_after_start_after; + int bytes_before_start_after; + int old_len; + + /* this subwriter access is moderately unkosher since we + * already unrecursed, but it works as long as unrecurse + * doesn't break us on purpose + */ + bytes_written_after_start_after = writer_get_array_len (&subwriter); + + bytes_before_start_after = + start_after->value_pos - reader_array_start_pos; + + fixup.len_pos_in_reader = reader_array_len_pos; + fixup.new_len = + bytes_before_start_after + + start_after_new_len + + bytes_written_after_start_after; + + _dbus_assert (_DBUS_ALIGN_VALUE (fixup.len_pos_in_reader, 4) == + (unsigned) fixup.len_pos_in_reader); + + old_len = _dbus_unpack_uint32 (reader->byte_order, + _dbus_string_get_const_data_len (reader->value_str, + fixup.len_pos_in_reader, 4)); + + if (old_len != fixup.new_len && !append_fixup (fixups, &fixup)) + goto oom; + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("Generated fixup len_pos_in_reader = %d new_len = %d reader_array_start_pos = %d start_after->value_pos = %d bytes_before_start_after = %d start_after_new_len = %d bytes_written_after_start_after = %d\n", + fixup.len_pos_in_reader, + fixup.new_len, + reader_array_start_pos, + start_after->value_pos, + bytes_before_start_after, + start_after_new_len, + bytes_written_after_start_after); +#endif + } + } + else + { + DBusBasicValue val; + + _dbus_assert (dbus_type_is_basic (current_type)); + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("Reading basic value %s at %d\n", + _dbus_type_to_string (current_type), + reader->value_pos); +#endif + + _dbus_type_reader_read_basic (reader, &val); + +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("Writing basic value %s at %d write target len %d inside_start_after = %d\n", + _dbus_type_to_string (current_type), + writer->value_pos, + _dbus_string_get_length (writer->value_str), + inside_start_after); +#endif + if (!inside_start_after) + enable_if_after (writer, reader, start_after); + if (!_dbus_type_writer_write_basic (writer, current_type, &val)) + goto oom; +#if RECURSIVE_MARSHAL_WRITE_TRACE + _dbus_verbose ("Wrote basic value %s, new value_pos %d write target len %d\n", + _dbus_type_to_string (current_type), + writer->value_pos, + _dbus_string_get_length (writer->value_str)); +#endif + } + + _dbus_type_reader_next (reader); + } + + return TRUE; + + oom: + if (fixups) + apply_and_free_fixups (fixups, NULL); /* NULL for reader to apply to */ + + return FALSE; +} + +/** + * Iterate through all values in the given reader, writing a copy of + * each value to the writer. The reader will be moved forward to its + * end position. + * + * If a reader start_after is provided, it should be a reader for the + * same data as the reader to be written. Only values occurring after + * the value pointed to by start_after will be written to the writer. + * + * If start_after is provided, then the copy of the reader will be + * partial. This means that array lengths will not have been copied. + * The assumption is that you wrote a new version of the value at + * start_after to the writer. You have to pass in the start position + * and length of the new value. (If you are deleting the value + * at start_after, pass in 0 for the length.) + * + * If the fixups parameter is non-#NULL, then any array length that + * was read but not written due to start_after will be provided + * as a #DBusArrayLenFixup. The fixup contains the position of the + * array length in the source data, and the correct array length + * assuming you combine the source data before start_after with + * the written data at start_after and beyond. + * + * @param writer the writer to copy to + * @param reader the reader to copy from + * @param start_after #NULL or a reader showing where to start + * @param start_after_new_pos the position of start_after equivalent in the target data + * @param start_after_new_len the length of start_after equivalent in the target data + * @param fixups list to append #DBusArrayLenFixup if the write was partial + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_type_writer_write_reader_partial (DBusTypeWriter *writer, + DBusTypeReader *reader, + const DBusTypeReader *start_after, + int start_after_new_pos, + int start_after_new_len, + DBusList **fixups) +{ + DBusTypeWriter orig; + int orig_type_len; + int orig_value_len; + int new_bytes; + int orig_enabled; + + orig = *writer; + orig_type_len = _dbus_string_get_length (writer->type_str); + orig_value_len = _dbus_string_get_length (writer->value_str); + orig_enabled = writer->enabled; + + if (start_after) + _dbus_type_writer_set_enabled (writer, FALSE); + + if (!writer_write_reader_helper (writer, reader, start_after, + start_after_new_pos, + start_after_new_len, + fixups, FALSE)) + goto oom; + + _dbus_type_writer_set_enabled (writer, orig_enabled); + return TRUE; + + oom: + if (!writer->type_pos_is_expectation) + { + new_bytes = _dbus_string_get_length (writer->type_str) - orig_type_len; + _dbus_string_delete (writer->type_str, orig.type_pos, new_bytes); + } + new_bytes = _dbus_string_get_length (writer->value_str) - orig_value_len; + _dbus_string_delete (writer->value_str, orig.value_pos, new_bytes); + + *writer = orig; + + return FALSE; +} + +/** + * Iterate through all values in the given reader, writing a copy of + * each value to the writer. The reader will be moved forward to its + * end position. + * + * @param writer the writer to copy to + * @param reader the reader to copy from + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_type_writer_write_reader (DBusTypeWriter *writer, + DBusTypeReader *reader) +{ + return _dbus_type_writer_write_reader_partial (writer, reader, NULL, 0, 0, NULL); +} + +/** + * If disabled, a writer can still be iterated forward and recursed/unrecursed + * but won't write any values. Types will still be written unless the + * writer is a "values only" writer, because the writer needs access to + * a valid signature to be able to iterate. + * + * @param writer the type writer + * @param enabled #TRUE if values should be written + */ +void +_dbus_type_writer_set_enabled (DBusTypeWriter *writer, + dbus_bool_t enabled) +{ + writer->enabled = enabled != FALSE; +} + +/** @} */ /* end of DBusMarshal group */ + +/* tests in dbus-marshal-recursive-util.c */ diff --git a/dbus/dbus-marshal-recursive.h b/dbus/dbus-marshal-recursive.h new file mode 100644 index 00000000..cea35350 --- /dev/null +++ b/dbus/dbus-marshal-recursive.h @@ -0,0 +1,196 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-recursive.h Marshalling routines for recursive types + * + * Copyright (C) 2004, 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_MARSHAL_RECURSIVE_H +#define DBUS_MARSHAL_RECURSIVE_H + +#include +#include +#include + +#ifndef PACKAGE +#error "config.h not included here" +#endif + +typedef struct DBusTypeReader DBusTypeReader; +typedef struct DBusTypeWriter DBusTypeWriter; +typedef struct DBusTypeReaderClass DBusTypeReaderClass; +typedef struct DBusArrayLenFixup DBusArrayLenFixup; + +/** + * The type reader is an iterator for reading values from a block of + * values. + */ +struct DBusTypeReader +{ + dbus_uint32_t byte_order : 8; /**< byte order of the block */ + + dbus_uint32_t finished : 1; /**< marks we're at end iterator for cases + * where we don't have another way to tell + */ + dbus_uint32_t array_len_offset : 3; /**< bytes back from start_pos that len ends */ + const DBusString *type_str; /**< string containing signature of block */ + int type_pos; /**< current position in signature */ + const DBusString *value_str; /**< string containing values of block */ + int value_pos; /**< current position in values */ + + const DBusTypeReaderClass *klass; /**< the vtable for the reader */ + union + { + struct { + int start_pos; /**< for array readers, the start of the array values */ + } array; + } u; /**< class-specific data */ +}; + +/** + * The type writer is an iterator for writing to a block of values. + */ +struct DBusTypeWriter +{ + dbus_uint32_t byte_order : 8; /**< byte order to write values with */ + + dbus_uint32_t container_type : 8; /**< what are we inside? (e.g. struct, variant, array) */ + + dbus_uint32_t type_pos_is_expectation : 1; /**< type_pos can be either an insertion point for or an expected next type */ + + dbus_uint32_t enabled : 1; /**< whether to write values */ + + DBusString *type_str; /**< where to write typecodes (or read type expectations) */ + int type_pos; /**< current pos in type_str */ + DBusString *value_str; /**< where to write values */ + int value_pos; /**< next position to write */ + + union + { + struct { + int start_pos; /**< position of first element in the array */ + int len_pos; /**< position of length of the array */ + int element_type_pos; /**< position of array element type in type_str */ + } array; + } u; /**< class-specific data */ +}; + +/** + * When modifying an existing block of values, array lengths may need + * to be adjusted; those adjustments are described by this struct. + */ +struct DBusArrayLenFixup +{ + int len_pos_in_reader; /**< where the length was in the original block */ + int new_len; /**< the new value of the length in the written-out block */ +}; + +void _dbus_type_reader_init (DBusTypeReader *reader, + int byte_order, + const DBusString *type_str, + int type_pos, + const DBusString *value_str, + int value_pos); +void _dbus_type_reader_init_types_only (DBusTypeReader *reader, + const DBusString *type_str, + int type_pos); +int _dbus_type_reader_get_current_type (const DBusTypeReader *reader); +int _dbus_type_reader_get_element_type (const DBusTypeReader *reader); +int _dbus_type_reader_get_value_pos (const DBusTypeReader *reader); +void _dbus_type_reader_read_basic (const DBusTypeReader *reader, + void *value); +int _dbus_type_reader_get_array_length (const DBusTypeReader *reader); +void _dbus_type_reader_read_fixed_multi (const DBusTypeReader *reader, + void *value, + int *n_elements); +void _dbus_type_reader_read_raw (const DBusTypeReader *reader, + const unsigned char **value_location); +void _dbus_type_reader_recurse (DBusTypeReader *reader, + DBusTypeReader *subreader); +dbus_bool_t _dbus_type_reader_next (DBusTypeReader *reader); +dbus_bool_t _dbus_type_reader_has_next (const DBusTypeReader *reader); +void _dbus_type_reader_get_signature (const DBusTypeReader *reader, + const DBusString **str_p, + int *start_p, + int *len_p); +dbus_bool_t _dbus_type_reader_set_basic (DBusTypeReader *reader, + const void *value, + const DBusTypeReader *realign_root); +dbus_bool_t _dbus_type_reader_delete (DBusTypeReader *reader, + const DBusTypeReader *realign_root); +dbus_bool_t _dbus_type_reader_greater_than (const DBusTypeReader *lhs, + const DBusTypeReader *rhs); + +dbus_bool_t _dbus_type_reader_equal_values (const DBusTypeReader *lhs, + const DBusTypeReader *rhs); + +void _dbus_type_signature_next (const char *signature, + int *type_pos); + +void _dbus_type_writer_init (DBusTypeWriter *writer, + int byte_order, + DBusString *type_str, + int type_pos, + DBusString *value_str, + int value_pos); +void _dbus_type_writer_init_types_delayed (DBusTypeWriter *writer, + int byte_order, + DBusString *value_str, + int value_pos); +void _dbus_type_writer_add_types (DBusTypeWriter *writer, + DBusString *type_str, + int type_pos); +void _dbus_type_writer_remove_types (DBusTypeWriter *writer); +void _dbus_type_writer_init_values_only (DBusTypeWriter *writer, + int byte_order, + const DBusString *type_str, + int type_pos, + DBusString *value_str, + int value_pos); +dbus_bool_t _dbus_type_writer_write_basic (DBusTypeWriter *writer, + int type, + const void *value); +dbus_bool_t _dbus_type_writer_write_fixed_multi (DBusTypeWriter *writer, + int element_type, + const void *value, + int n_elements); +dbus_bool_t _dbus_type_writer_recurse (DBusTypeWriter *writer, + int container_type, + const DBusString *contained_type, + int contained_type_start, + DBusTypeWriter *sub); +dbus_bool_t _dbus_type_writer_unrecurse (DBusTypeWriter *writer, + DBusTypeWriter *sub); +dbus_bool_t _dbus_type_writer_append_array (DBusTypeWriter *writer, + const DBusString *contained_type, + int contained_type_start, + DBusTypeWriter *sub); +dbus_bool_t _dbus_type_writer_write_reader (DBusTypeWriter *writer, + DBusTypeReader *reader); +dbus_bool_t _dbus_type_writer_write_reader_partial (DBusTypeWriter *writer, + DBusTypeReader *reader, + const DBusTypeReader *start_after, + int start_after_new_pos, + int start_after_new_len, + DBusList **fixups); +void _dbus_type_writer_set_enabled (DBusTypeWriter *writer, + dbus_bool_t enabled); + + +#endif /* DBUS_MARSHAL_RECURSIVE_H */ diff --git a/dbus/dbus-marshal-validate-util.c b/dbus/dbus-marshal-validate-util.c new file mode 100644 index 00000000..81135bcf --- /dev/null +++ b/dbus/dbus-marshal-validate-util.c @@ -0,0 +1,588 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-validate-util.c Would be in dbus-marshal-validate.c, but only used by tests/bus + * + * Copyright (C) 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#ifdef DBUS_BUILD_TESTS + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#include "dbus-internals.h" +#include "dbus-marshal-validate.h" +#include "dbus-marshal-recursive.h" + +#include "dbus-test.h" +#include + +typedef struct +{ + const char *data; + DBusValidity expected; +} ValidityTest; + +static void +run_validity_tests (const ValidityTest *tests, + int n_tests, + DBusValidity (* func) (const DBusString*,int,int)) +{ + int i; + + for (i = 0; i < n_tests; i++) + { + DBusString str; + DBusValidity v; + + _dbus_string_init_const (&str, tests[i].data); + + v = (*func) (&str, 0, _dbus_string_get_length (&str)); + + if (v != tests[i].expected) + { + _dbus_warn ("Improper validation result %d for '%s'\n", + v, tests[i].data); + _dbus_assert_not_reached ("test failed"); + } + + ++i; + } +} + +static const ValidityTest signature_tests[] = { + { "", DBUS_VALID }, + { "i", DBUS_VALID }, + { "ai", DBUS_VALID }, + { "(i)", DBUS_VALID }, + { "w", DBUS_INVALID_UNKNOWN_TYPECODE }, + { "a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, + { "aaaaaa", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, + { "ii(ii)a", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, + { "ia", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, + /* DBUS_INVALID_SIGNATURE_TOO_LONG, */ /* too hard to test this way */ + { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION }, + { "((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((ii))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))", + DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION }, + { ")", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED }, + { "i)", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED }, + { "a)", DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED }, + { "(", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED }, + { "(i", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED }, + { "(iiiii", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED }, + { "(ai", DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED }, + { "()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, + { "(())", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, + { "a()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, + { "i()", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, + { "()i", DBUS_INVALID_STRUCT_HAS_NO_FIELDS }, + { "(a)", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, + { "a{ia}", DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE }, + { "a{}", DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS }, + { "a{aii}", DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE }, + /* { "a{i}", DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD }, */ + /* { "{is}", DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY }, */ + /* { "a{isi}", DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS }, */ +}; + +dbus_bool_t +_dbus_marshal_validate_test (void) +{ + DBusString str; + int i; + + const char *valid_paths[] = { + "/", + "/foo/bar", + "/foo", + "/foo/bar/baz" + }; + const char *invalid_paths[] = { + "bar", + "bar/baz", + "/foo/bar/", + "/foo/" + "foo/", + "boo//blah", + "//", + "///", + "foo///blah/", + "Hello World", + "", + " ", + "foo bar" + }; + + const char *valid_interfaces[] = { + "org.freedesktop.Foo", + "Bar.Baz", + "Blah.Blah.Blah.Blah.Blah", + "a.b", + "a.b.c.d.e.f.g", + "a0.b1.c2.d3.e4.f5.g6", + "abc123.foo27" + }; + const char *invalid_interfaces[] = { + ".", + "", + "..", + ".Foo.Bar", + "..Foo.Bar", + "Foo.Bar.", + "Foo.Bar..", + "Foo", + "9foo.bar.baz", + "foo.bar..baz", + "foo.bar...baz", + "foo.bar.b..blah", + ":", + ":0-1", + "10", + ":11.34324", + "0.0.0", + "0..0", + "foo.Bar.%", + "foo.Bar!!", + "!Foo.bar.bz", + "foo.$.blah", + "", + " ", + "foo bar" + }; + + const char *valid_unique_names[] = { + ":0", + ":a", + ":", + ":.a", + ":.1", + ":0.1", + ":000.2222", + ":.blah", + ":abce.freedesktop.blah" + }; + const char *invalid_unique_names[] = { + //":-", + ":!", + //":0-10", + ":blah.", + ":blah.", + ":blah..org", + ":blah.org..", + ":..blah.org", + "", + " ", + "foo bar" + }; + + const char *valid_members[] = { + "Hello", + "Bar", + "foobar", + "_foobar", + "foo89" + }; + + const char *invalid_members[] = { + "9Hello", + "10", + "1", + "foo-bar", + "blah.org", + ".blah", + "blah.", + "Hello.", + "!foo", + "", + " ", + "foo bar" + }; + + const char *valid_signatures[] = { + "", + "sss", + "i", + "b" + }; + + const char *invalid_signatures[] = { + " ", + "not a valid signature", + "123", + ".", + "(", + "a{(ii)i}" /* https://bugs.freedesktop.org/show_bug.cgi?id=17803 */ + }; + + /* Signature with reason */ + + run_validity_tests (signature_tests, _DBUS_N_ELEMENTS (signature_tests), + _dbus_validate_signature_with_reason); + + /* Path validation */ + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (valid_paths)) + { + _dbus_string_init_const (&str, valid_paths[i]); + + if (!_dbus_validate_path (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Path \"%s\" should have been valid\n", valid_paths[i]); + _dbus_assert_not_reached ("invalid path"); + } + + ++i; + } + + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (invalid_paths)) + { + _dbus_string_init_const (&str, invalid_paths[i]); + + if (_dbus_validate_path (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Path \"%s\" should have been invalid\n", invalid_paths[i]); + _dbus_assert_not_reached ("valid path"); + } + + ++i; + } + + /* Interface validation */ + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces)) + { + _dbus_string_init_const (&str, valid_interfaces[i]); + + if (!_dbus_validate_interface (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Interface \"%s\" should have been valid\n", valid_interfaces[i]); + _dbus_assert_not_reached ("invalid interface"); + } + + ++i; + } + + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces)) + { + _dbus_string_init_const (&str, invalid_interfaces[i]); + + if (_dbus_validate_interface (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Interface \"%s\" should have been invalid\n", invalid_interfaces[i]); + _dbus_assert_not_reached ("valid interface"); + } + + ++i; + } + + /* Bus name validation (check that valid interfaces are valid bus names, + * and invalid interfaces are invalid services except if they start with ':') + */ + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces)) + { + _dbus_string_init_const (&str, valid_interfaces[i]); + + if (!_dbus_validate_bus_name (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Bus name \"%s\" should have been valid\n", valid_interfaces[i]); + _dbus_assert_not_reached ("invalid bus name"); + } + + ++i; + } + + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces)) + { + if (invalid_interfaces[i][0] != ':') + { + _dbus_string_init_const (&str, invalid_interfaces[i]); + + if (_dbus_validate_bus_name (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Bus name \"%s\" should have been invalid\n", invalid_interfaces[i]); + _dbus_assert_not_reached ("valid bus name"); + } + } + + ++i; + } + + /* unique name validation */ + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (valid_unique_names)) + { + _dbus_string_init_const (&str, valid_unique_names[i]); + + if (!_dbus_validate_bus_name (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Bus name \"%s\" should have been valid\n", valid_unique_names[i]); + _dbus_assert_not_reached ("invalid unique name"); + } + + ++i; + } + + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (invalid_unique_names)) + { + _dbus_string_init_const (&str, invalid_unique_names[i]); + + if (_dbus_validate_bus_name (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Bus name \"%s\" should have been invalid\n", invalid_unique_names[i]); + _dbus_assert_not_reached ("valid unique name"); + } + + ++i; + } + + + /* Error name validation (currently identical to interfaces) + */ + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces)) + { + _dbus_string_init_const (&str, valid_interfaces[i]); + + if (!_dbus_validate_error_name (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Error name \"%s\" should have been valid\n", valid_interfaces[i]); + _dbus_assert_not_reached ("invalid error name"); + } + + ++i; + } + + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces)) + { + if (invalid_interfaces[i][0] != ':') + { + _dbus_string_init_const (&str, invalid_interfaces[i]); + + if (_dbus_validate_error_name (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Error name \"%s\" should have been invalid\n", invalid_interfaces[i]); + _dbus_assert_not_reached ("valid error name"); + } + } + + ++i; + } + + /* Member validation */ + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (valid_members)) + { + _dbus_string_init_const (&str, valid_members[i]); + + if (!_dbus_validate_member (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Member \"%s\" should have been valid\n", valid_members[i]); + _dbus_assert_not_reached ("invalid member"); + } + + ++i; + } + + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (invalid_members)) + { + _dbus_string_init_const (&str, invalid_members[i]); + + if (_dbus_validate_member (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Member \"%s\" should have been invalid\n", invalid_members[i]); + _dbus_assert_not_reached ("valid member"); + } + + ++i; + } + + /* Signature validation */ + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (valid_signatures)) + { + _dbus_string_init_const (&str, valid_signatures[i]); + + if (!_dbus_validate_signature (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Signature \"%s\" should have been valid\n", valid_signatures[i]); + _dbus_assert_not_reached ("invalid signature"); + } + + ++i; + } + + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (invalid_signatures)) + { + _dbus_string_init_const (&str, invalid_signatures[i]); + + if (_dbus_validate_signature (&str, 0, + _dbus_string_get_length (&str))) + { + _dbus_warn ("Signature \"%s\" should have been invalid\n", invalid_signatures[i]); + _dbus_assert_not_reached ("valid signature"); + } + + ++i; + } + + /* Validate claimed length longer than real length */ + _dbus_string_init_const (&str, "abc.efg"); + if (_dbus_validate_bus_name (&str, 0, 8)) + _dbus_assert_not_reached ("validated too-long string"); + if (_dbus_validate_interface (&str, 0, 8)) + _dbus_assert_not_reached ("validated too-long string"); + if (_dbus_validate_error_name (&str, 0, 8)) + _dbus_assert_not_reached ("validated too-long string"); + + _dbus_string_init_const (&str, "abc"); + if (_dbus_validate_member (&str, 0, 4)) + _dbus_assert_not_reached ("validated too-long string"); + + _dbus_string_init_const (&str, "sss"); + if (_dbus_validate_signature (&str, 0, 4)) + _dbus_assert_not_reached ("validated too-long signature"); + + /* Validate string exceeding max name length */ + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("no memory"); + + while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH) + if (!_dbus_string_append (&str, "abc.def")) + _dbus_assert_not_reached ("no memory"); + + if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str))) + _dbus_assert_not_reached ("validated overmax string"); + if (_dbus_validate_interface (&str, 0, _dbus_string_get_length (&str))) + _dbus_assert_not_reached ("validated overmax string"); + if (_dbus_validate_error_name (&str, 0, _dbus_string_get_length (&str))) + _dbus_assert_not_reached ("validated overmax string"); + + /* overlong member */ + _dbus_string_set_length (&str, 0); + while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH) + if (!_dbus_string_append (&str, "abc")) + _dbus_assert_not_reached ("no memory"); + + if (_dbus_validate_member (&str, 0, _dbus_string_get_length (&str))) + _dbus_assert_not_reached ("validated overmax string"); + + /* overlong unique name */ + _dbus_string_set_length (&str, 0); + _dbus_string_append (&str, ":"); + while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH) + if (!_dbus_string_append (&str, "abc")) + _dbus_assert_not_reached ("no memory"); + + if (_dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str))) + _dbus_assert_not_reached ("validated overmax string"); + + _dbus_string_free (&str); + + /* Body validation; test basic validation of valid bodies for both endian */ + + { + int sequence; + DBusString signature; + DBusString body; + + if (!_dbus_string_init (&signature) || !_dbus_string_init (&body)) + _dbus_assert_not_reached ("oom"); + + sequence = 0; + while (dbus_internal_do_not_use_generate_bodies (sequence, + DBUS_LITTLE_ENDIAN, + &signature, &body)) + { + DBusValidity validity; + + validity = _dbus_validate_body_with_reason (&signature, 0, + DBUS_LITTLE_ENDIAN, + NULL, &body, 0, + _dbus_string_get_length (&body)); + if (validity != DBUS_VALID) + { + _dbus_warn ("invalid code %d expected valid on sequence %d little endian\n", + validity, sequence); + _dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature)); + _dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body)); + _dbus_assert_not_reached ("test failed"); + } + + _dbus_string_set_length (&signature, 0); + _dbus_string_set_length (&body, 0); + ++sequence; + } + + sequence = 0; + while (dbus_internal_do_not_use_generate_bodies (sequence, + DBUS_BIG_ENDIAN, + &signature, &body)) + { + DBusValidity validity; + + validity = _dbus_validate_body_with_reason (&signature, 0, + DBUS_BIG_ENDIAN, + NULL, &body, 0, + _dbus_string_get_length (&body)); + if (validity != DBUS_VALID) + { + _dbus_warn ("invalid code %d expected valid on sequence %d big endian\n", + validity, sequence); + _dbus_verbose_bytes_of_string (&signature, 0, _dbus_string_get_length (&signature)); + _dbus_verbose_bytes_of_string (&body, 0, _dbus_string_get_length (&body)); + _dbus_assert_not_reached ("test failed"); + } + + _dbus_string_set_length (&signature, 0); + _dbus_string_set_length (&body, 0); + ++sequence; + } + + _dbus_string_free (&signature); + _dbus_string_free (&body); + } + + return TRUE; +} + +#endif /* !DOXYGEN_SHOULD_SKIP_THIS */ + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-marshal-validate.c b/dbus/dbus-marshal-validate.c new file mode 100644 index 00000000..61fad4de --- /dev/null +++ b/dbus/dbus-marshal-validate.c @@ -0,0 +1,1204 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-validate.c Validation routines for marshaled data + * + * Copyright (C) 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-marshal-validate.h" +#include "dbus-marshal-recursive.h" +#include "dbus-marshal-basic.h" +#include "dbus-signature.h" +#include "dbus-string.h" + +/** + * @addtogroup DBusMarshal + * + * @{ + */ + +/** + * Verifies that the range of type_str from type_pos to type_end is a + * valid signature. If this function returns #TRUE, it will be safe + * to iterate over the signature with a types-only #DBusTypeReader. + * The range passed in should NOT include the terminating + * nul/DBUS_TYPE_INVALID. + * + * @param type_str the string + * @param type_pos where the typecodes start + * @param len length of typecodes + * @returns #DBUS_VALID if valid, reason why invalid otherwise + */ +DBusValidity +_dbus_validate_signature_with_reason (const DBusString *type_str, + int type_pos, + int len) +{ + const unsigned char *p; + const unsigned char *end; + int last; + int struct_depth; + int array_depth; + int dict_entry_depth; + DBusValidity result; + + int element_count; + DBusList *element_count_stack; + + result = DBUS_VALID; + element_count_stack = NULL; + + if (!_dbus_list_append (&element_count_stack, _DBUS_INT_TO_POINTER (0))) + { + result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; + goto out; + } + + _dbus_assert (type_str != NULL); + _dbus_assert (type_pos < _DBUS_INT32_MAX - len); + _dbus_assert (len >= 0); + _dbus_assert (type_pos >= 0); + + if (len > DBUS_MAXIMUM_SIGNATURE_LENGTH) + { + result = DBUS_INVALID_SIGNATURE_TOO_LONG; + goto out; + } + + p = _dbus_string_get_const_data_len (type_str, type_pos, 0); + + end = _dbus_string_get_const_data_len (type_str, type_pos + len, 0); + struct_depth = 0; + array_depth = 0; + dict_entry_depth = 0; + last = DBUS_TYPE_INVALID; + + while (p != end) + { + switch (*p) + { + case DBUS_TYPE_BYTE: + case DBUS_TYPE_BOOLEAN: + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_SIGNATURE: + case DBUS_TYPE_VARIANT: + break; + + case DBUS_TYPE_ARRAY: + array_depth += 1; + if (array_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH) + { + result = DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION; + goto out; + } + break; + + case DBUS_STRUCT_BEGIN_CHAR: + struct_depth += 1; + + if (struct_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH) + { + result = DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION; + goto out; + } + + if (!_dbus_list_append (&element_count_stack, + _DBUS_INT_TO_POINTER (0))) + { + result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; + goto out; + } + + break; + + case DBUS_STRUCT_END_CHAR: + if (struct_depth == 0) + { + result = DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED; + goto out; + } + + if (last == DBUS_STRUCT_BEGIN_CHAR) + { + result = DBUS_INVALID_STRUCT_HAS_NO_FIELDS; + goto out; + } + + _dbus_list_pop_last (&element_count_stack); + + struct_depth -= 1; + break; + + case DBUS_DICT_ENTRY_BEGIN_CHAR: + if (last != DBUS_TYPE_ARRAY) + { + result = DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY; + goto out; + } + + dict_entry_depth += 1; + + if (dict_entry_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH) + { + result = DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION; + goto out; + } + + if (!_dbus_list_append (&element_count_stack, + _DBUS_INT_TO_POINTER (0))) + { + result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; + goto out; + } + + break; + + case DBUS_DICT_ENTRY_END_CHAR: + if (dict_entry_depth == 0) + { + result = DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED; + goto out; + } + + dict_entry_depth -= 1; + + element_count = + _DBUS_POINTER_TO_INT (_dbus_list_pop_last (&element_count_stack)); + + if (element_count != 2) + { + if (element_count == 0) + result = DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS; + else if (element_count == 1) + result = DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD; + else + result = DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS; + + goto out; + } + break; + + case DBUS_TYPE_STRUCT: /* doesn't appear in signatures */ + case DBUS_TYPE_DICT_ENTRY: /* ditto */ + default: + result = DBUS_INVALID_UNKNOWN_TYPECODE; + goto out; + } + + if (*p != DBUS_TYPE_ARRAY && + *p != DBUS_DICT_ENTRY_BEGIN_CHAR && + *p != DBUS_STRUCT_BEGIN_CHAR) + { + element_count = + _DBUS_POINTER_TO_INT (_dbus_list_pop_last (&element_count_stack)); + + ++element_count; + + if (!_dbus_list_append (&element_count_stack, + _DBUS_INT_TO_POINTER (element_count))) + { + result = DBUS_VALIDITY_UNKNOWN_OOM_ERROR; + goto out; + } + } + + if (array_depth > 0) + { + if (*p == DBUS_TYPE_ARRAY && p != end) + { + const char *p1; + p1 = p + 1; + if (*p1 == DBUS_STRUCT_END_CHAR || + *p1 == DBUS_DICT_ENTRY_END_CHAR) + { + result = DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE; + goto out; + } + } + else + { + array_depth = 0; + } + } + + if (last == DBUS_DICT_ENTRY_BEGIN_CHAR) + { + if (!(_dbus_type_is_valid (*p) && dbus_type_is_basic (*p))) + { + result = DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE; + goto out; + } + } + + last = *p; + ++p; + } + + + if (array_depth > 0) + { + result = DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE; + goto out; + } + + if (struct_depth > 0) + { + result = DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED; + goto out; + } + + if (dict_entry_depth > 0) + { + result = DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED; + goto out; + } + + _dbus_assert (last != DBUS_TYPE_ARRAY); + _dbus_assert (last != DBUS_STRUCT_BEGIN_CHAR); + _dbus_assert (last != DBUS_DICT_ENTRY_BEGIN_CHAR); + + result = DBUS_VALID; + +out: + _dbus_list_clear (&element_count_stack); + return result; +} + +static DBusValidity +validate_body_helper (DBusTypeReader *reader, + int byte_order, + dbus_bool_t walk_reader_to_end, + const unsigned char *p, + const unsigned char *end, + const unsigned char **new_p) +{ + int current_type; + + while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID) + { + const unsigned char *a; + int alignment; + +#if 0 + _dbus_verbose (" validating value of type %s type reader %p type_pos %d p %p end %p %d remain\n", + _dbus_type_to_string (current_type), reader, reader->type_pos, p, end, + (int) (end - p)); +#endif + + /* Guarantee that p has one byte to look at */ + if (p == end) + return DBUS_INVALID_NOT_ENOUGH_DATA; + + switch (current_type) + { + case DBUS_TYPE_BYTE: + ++p; + break; + + case DBUS_TYPE_BOOLEAN: + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + alignment = _dbus_type_get_alignment (current_type); + a = _DBUS_ALIGN_ADDRESS (p, alignment); + if (a >= end) + return DBUS_INVALID_NOT_ENOUGH_DATA; + while (p != a) + { + if (*p != '\0') + return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; + ++p; + } + + if (current_type == DBUS_TYPE_BOOLEAN) + { + dbus_uint32_t v = _dbus_unpack_uint32 (byte_order, + p); + if (!(v == 0 || v == 1)) + return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE; + } + + p += alignment; + break; + + case DBUS_TYPE_ARRAY: + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + { + dbus_uint32_t claimed_len; + + a = _DBUS_ALIGN_ADDRESS (p, 4); + if (a + 4 > end) + return DBUS_INVALID_NOT_ENOUGH_DATA; + while (p != a) + { + if (*p != '\0') + return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; + ++p; + } + + claimed_len = _dbus_unpack_uint32 (byte_order, p); + p += 4; + + /* p may now be == end */ + _dbus_assert (p <= end); + + if (current_type == DBUS_TYPE_ARRAY) + { + int array_elem_type = _dbus_type_reader_get_element_type (reader); + + if (!_dbus_type_is_valid (array_elem_type)) + { + return DBUS_INVALID_UNKNOWN_TYPECODE; + } + + alignment = _dbus_type_get_alignment (array_elem_type); + + a = _DBUS_ALIGN_ADDRESS (p, alignment); + + /* a may now be == end */ + if (a > end) + return DBUS_INVALID_NOT_ENOUGH_DATA; + + while (p != a) + { + if (*p != '\0') + return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; + ++p; + } + } + + if (claimed_len > (unsigned long) (end - p)) + return DBUS_INVALID_LENGTH_OUT_OF_BOUNDS; + + if (current_type == DBUS_TYPE_OBJECT_PATH) + { + DBusString str; + _dbus_string_init_const_len (&str, p, claimed_len); + if (!_dbus_validate_path (&str, 0, + _dbus_string_get_length (&str))) + return DBUS_INVALID_BAD_PATH; + + p += claimed_len; + } + else if (current_type == DBUS_TYPE_STRING) + { + DBusString str; + _dbus_string_init_const_len (&str, p, claimed_len); + if (!_dbus_string_validate_utf8 (&str, 0, + _dbus_string_get_length (&str))) + return DBUS_INVALID_BAD_UTF8_IN_STRING; + + p += claimed_len; + } + else if (current_type == DBUS_TYPE_ARRAY && claimed_len > 0) + { + DBusTypeReader sub; + DBusValidity validity; + const unsigned char *array_end; + int array_elem_type; + + if (claimed_len > DBUS_MAXIMUM_ARRAY_LENGTH) + return DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM; + + /* Remember that the reader is types only, so we can't + * use it to iterate over elements. It stays the same + * for all elements. + */ + _dbus_type_reader_recurse (reader, &sub); + + array_end = p + claimed_len; + + array_elem_type = _dbus_type_reader_get_element_type (reader); + + /* avoid recursive call to validate_body_helper if this is an array + * of fixed-size elements + */ + if (dbus_type_is_fixed (array_elem_type)) + { + /* bools need to be handled differently, because they can + * have an invalid value + */ + if (array_elem_type == DBUS_TYPE_BOOLEAN) + { + dbus_uint32_t v; + alignment = _dbus_type_get_alignment (array_elem_type); + + while (p < array_end) + { + v = _dbus_unpack_uint32 (byte_order, p); + + if (!(v == 0 || v == 1)) + return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE; + + p += alignment; + } + } + + else + { + p = array_end; + } + } + + else + { + while (p < array_end) + { + validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p); + if (validity != DBUS_VALID) + return validity; + } + } + + if (p != array_end) + return DBUS_INVALID_ARRAY_LENGTH_INCORRECT; + } + + /* check nul termination */ + if (current_type != DBUS_TYPE_ARRAY) + { + if (p == end) + return DBUS_INVALID_NOT_ENOUGH_DATA; + + if (*p != '\0') + return DBUS_INVALID_STRING_MISSING_NUL; + ++p; + } + } + break; + + case DBUS_TYPE_SIGNATURE: + { + dbus_uint32_t claimed_len; + DBusString str; + DBusValidity validity; + + claimed_len = *p; + ++p; + + /* 1 is for nul termination */ + if (claimed_len + 1 > (unsigned long) (end - p)) + return DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS; + + _dbus_string_init_const_len (&str, p, claimed_len); + validity = + _dbus_validate_signature_with_reason (&str, 0, + _dbus_string_get_length (&str)); + + if (validity != DBUS_VALID) + return validity; + + p += claimed_len; + + _dbus_assert (p < end); + if (*p != DBUS_TYPE_INVALID) + return DBUS_INVALID_SIGNATURE_MISSING_NUL; + + ++p; + + _dbus_verbose ("p = %p end = %p claimed_len %u\n", p, end, claimed_len); + } + break; + + case DBUS_TYPE_VARIANT: + { + /* 1 byte sig len, sig typecodes, align to + * contained-type-boundary, values. + */ + + /* In addition to normal signature validation, we need to be sure + * the signature contains only a single (possibly container) type. + */ + dbus_uint32_t claimed_len; + DBusString sig; + DBusTypeReader sub; + DBusValidity validity; + int contained_alignment; + int contained_type; + DBusValidity reason; + + claimed_len = *p; + ++p; + + /* + 1 for nul */ + if (claimed_len + 1 > (unsigned long) (end - p)) + return DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS; + + _dbus_string_init_const_len (&sig, p, claimed_len); + reason = _dbus_validate_signature_with_reason (&sig, 0, + _dbus_string_get_length (&sig)); + if (!(reason == DBUS_VALID)) + { + if (reason == DBUS_VALIDITY_UNKNOWN_OOM_ERROR) + return reason; + else + return DBUS_INVALID_VARIANT_SIGNATURE_BAD; + } + + p += claimed_len; + + if (*p != DBUS_TYPE_INVALID) + return DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL; + ++p; + + contained_type = _dbus_first_type_in_signature (&sig, 0); + if (contained_type == DBUS_TYPE_INVALID) + return DBUS_INVALID_VARIANT_SIGNATURE_EMPTY; + + contained_alignment = _dbus_type_get_alignment (contained_type); + + a = _DBUS_ALIGN_ADDRESS (p, contained_alignment); + if (a > end) + return DBUS_INVALID_NOT_ENOUGH_DATA; + while (p != a) + { + if (*p != '\0') + return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; + ++p; + } + + _dbus_type_reader_init_types_only (&sub, &sig, 0); + + _dbus_assert (_dbus_type_reader_get_current_type (&sub) != DBUS_TYPE_INVALID); + + validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p); + if (validity != DBUS_VALID) + return validity; + + if (_dbus_type_reader_next (&sub)) + return DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES; + + _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_INVALID); + } + break; + + case DBUS_TYPE_DICT_ENTRY: + case DBUS_TYPE_STRUCT: + { + DBusTypeReader sub; + DBusValidity validity; + + a = _DBUS_ALIGN_ADDRESS (p, 8); + if (a > end) + return DBUS_INVALID_NOT_ENOUGH_DATA; + while (p != a) + { + if (*p != '\0') + return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL; + ++p; + } + + _dbus_type_reader_recurse (reader, &sub); + + validity = validate_body_helper (&sub, byte_order, TRUE, p, end, &p); + if (validity != DBUS_VALID) + return validity; + } + break; + + default: + _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature"); + break; + } + +#if 0 + _dbus_verbose (" validated value of type %s type reader %p type_pos %d p %p end %p %d remain\n", + _dbus_type_to_string (current_type), reader, reader->type_pos, p, end, + (int) (end - p)); +#endif + + if (p > end) + { + _dbus_verbose ("not enough data!!! p = %p end = %p end-p = %d\n", + p, end, (int) (end - p)); + return DBUS_INVALID_NOT_ENOUGH_DATA; + } + + if (walk_reader_to_end) + _dbus_type_reader_next (reader); + else + break; + } + + if (new_p) + *new_p = p; + + return DBUS_VALID; +} + +/** + * Verifies that the range of value_str from value_pos to value_end is + * a legitimate value of type expected_signature. If this function + * returns #TRUE, it will be safe to iterate over the values with + * #DBusTypeReader. The signature is assumed to be already valid. + * + * If bytes_remaining is not #NULL, then leftover bytes will be stored + * there and #DBUS_VALID returned. If it is #NULL, then + * #DBUS_INVALID_TOO_MUCH_DATA will be returned if bytes are left + * over. + * + * @param expected_signature the expected types in the value_str + * @param expected_signature_start where in expected_signature is the signature + * @param byte_order the byte order + * @param bytes_remaining place to store leftover bytes + * @param value_str the string containing the body + * @param value_pos where the values start + * @param len length of values after value_pos + * @returns #DBUS_VALID if valid, reason why invalid otherwise + */ +DBusValidity +_dbus_validate_body_with_reason (const DBusString *expected_signature, + int expected_signature_start, + int byte_order, + int *bytes_remaining, + const DBusString *value_str, + int value_pos, + int len) +{ + DBusTypeReader reader; + const unsigned char *p; + const unsigned char *end; + DBusValidity validity; + + _dbus_assert (len >= 0); + _dbus_assert (value_pos >= 0); + _dbus_assert (value_pos <= _dbus_string_get_length (value_str) - len); + + _dbus_verbose ("validating body from pos %d len %d sig '%s'\n", + value_pos, len, _dbus_string_get_const_data_len (expected_signature, + expected_signature_start, + 0)); + + _dbus_type_reader_init_types_only (&reader, + expected_signature, expected_signature_start); + + p = _dbus_string_get_const_data_len (value_str, value_pos, len); + end = p + len; + + validity = validate_body_helper (&reader, byte_order, TRUE, p, end, &p); + if (validity != DBUS_VALID) + return validity; + + if (bytes_remaining) + { + *bytes_remaining = end - p; + return DBUS_VALID; + } + else if (p < end) + return DBUS_INVALID_TOO_MUCH_DATA; + else + { + _dbus_assert (p == end); + return DBUS_VALID; + } +} + +/** + * Determine wether the given character is valid as the first character + * in a name. + */ +#define VALID_INITIAL_NAME_CHARACTER(c) \ + ( ((c) >= 'A' && (c) <= 'Z') || \ + ((c) >= 'a' && (c) <= 'z') || \ + ((c) == '_') ) + +/** + * Determine wether the given character is valid as a second or later + * character in a name + */ +#define VALID_NAME_CHARACTER(c) \ + ( ((c) >= '0' && (c) <= '9') || \ + ((c) >= 'A' && (c) <= 'Z') || \ + ((c) >= 'a' && (c) <= 'z') || \ + ((c) == '_') ) + +/** + * Checks that the given range of the string is a valid object path + * name in the D-Bus protocol. Part of the validation ensures that + * the object path contains only ASCII. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @todo change spec to disallow more things, such as spaces in the + * path name + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_validate_path (const DBusString *str, + int start, + int len) +{ + const unsigned char *s; + const unsigned char *end; + const unsigned char *last_slash; + + _dbus_assert (start >= 0); + _dbus_assert (len >= 0); + _dbus_assert (start <= _dbus_string_get_length (str)); + + if (len > _dbus_string_get_length (str) - start) + return FALSE; + + if (len == 0) + return FALSE; + + s = _dbus_string_get_const_data (str) + start; + end = s + len; + + if (*s != '/') + return FALSE; + last_slash = s; + ++s; + + while (s != end) + { + if (*s == '/') + { + if ((s - last_slash) < 2) + return FALSE; /* no empty path components allowed */ + + last_slash = s; + } + else + { + if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s))) + return FALSE; + } + + ++s; + } + + if ((end - last_slash) < 2 && + len > 1) + return FALSE; /* trailing slash not allowed unless the string is "/" */ + + return TRUE; +} + +const char * +_dbus_validity_to_error_message (DBusValidity validity) +{ + switch (validity) + { + case DBUS_VALIDITY_UNKNOWN_OOM_ERROR: return "Out of memory"; + case DBUS_INVALID_FOR_UNKNOWN_REASON: return "Unknown reason"; + case DBUS_VALID_BUT_INCOMPLETE: return "Valid but incomplete"; + case DBUS_VALIDITY_UNKNOWN: return "Validity unknown"; + case DBUS_VALID: return "Valid"; + case DBUS_INVALID_UNKNOWN_TYPECODE: return "Unknown typecode"; + case DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE: return "Missing array element type"; + case DBUS_INVALID_SIGNATURE_TOO_LONG: return "Signature is too long"; + case DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION: return "Exceeded maximum array recursion"; + case DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION: return "Exceeded maximum struct recursion"; + case DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED: return "Struct ended but not started"; + case DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED: return "Struct started but not ended"; + case DBUS_INVALID_STRUCT_HAS_NO_FIELDS: return "Struct has no fields"; + case DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL: return "Alignment padding not null"; + case DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE: return "Boolean is not zero or one"; + case DBUS_INVALID_NOT_ENOUGH_DATA: return "Not enough data"; + case DBUS_INVALID_TOO_MUCH_DATA: return "Too much data"; + case DBUS_INVALID_BAD_BYTE_ORDER: return "Bad byte order"; + case DBUS_INVALID_BAD_PROTOCOL_VERSION: return "Bad protocol version"; + case DBUS_INVALID_BAD_MESSAGE_TYPE: return "Bad message type"; + case DBUS_INVALID_BAD_SERIAL: return "Bad serial"; + case DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH: return "Insane fields array length"; + case DBUS_INVALID_INSANE_BODY_LENGTH: return "Insane body length"; + case DBUS_INVALID_MESSAGE_TOO_LONG: return "Message too long"; + case DBUS_INVALID_HEADER_FIELD_CODE: return "Header field code"; + case DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE: return "Header field has wrong type"; + case DBUS_INVALID_USES_LOCAL_INTERFACE: return "Uses local interface"; + case DBUS_INVALID_USES_LOCAL_PATH: return "Uses local path"; + case DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE: return "Header field appears twice"; + case DBUS_INVALID_BAD_DESTINATION: return "Bad destination"; + case DBUS_INVALID_BAD_INTERFACE: return "Bad interface"; + case DBUS_INVALID_BAD_MEMBER: return "Bad member"; + case DBUS_INVALID_BAD_ERROR_NAME: return "Bad error name"; + case DBUS_INVALID_BAD_SENDER: return "Bad sender"; + case DBUS_INVALID_MISSING_PATH: return "Missing path"; + case DBUS_INVALID_MISSING_INTERFACE: return "Missing interface"; + case DBUS_INVALID_MISSING_MEMBER: return "Missing member"; + case DBUS_INVALID_MISSING_ERROR_NAME: return "Missing error name"; + case DBUS_INVALID_MISSING_REPLY_SERIAL: return "Missing reply serial"; + case DBUS_INVALID_LENGTH_OUT_OF_BOUNDS: return "Length out of bounds"; + case DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM: return "Array length exceeds maximum"; + case DBUS_INVALID_BAD_PATH: return "Bad path"; + case DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS: return "Signature length out of bounds"; + case DBUS_INVALID_BAD_UTF8_IN_STRING: return "Bad utf8 in string"; + case DBUS_INVALID_ARRAY_LENGTH_INCORRECT: return "Array length incorrect"; + case DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS: return "Variant signature length out of bounds"; + case DBUS_INVALID_VARIANT_SIGNATURE_BAD: return "Variant signature bad"; + case DBUS_INVALID_VARIANT_SIGNATURE_EMPTY: return "Variant signature empty"; + case DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES: return "Variant signature specifies multiple values"; + case DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL: return "Variant signature missing nul"; + case DBUS_INVALID_STRING_MISSING_NUL: return "String missing nul"; + case DBUS_INVALID_SIGNATURE_MISSING_NUL: return "Signature missing nul"; + case DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION: return "Exceeded maximum dict entry recursion"; + case DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED: return "Dict entry ended but not started"; + case DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED: return "Dict entry started but not ended"; + case DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS: return "Dict entry has no fields"; + case DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD: return "Dict entry has only one field"; + case DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS: return "Dict entry has too many fields"; + case DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY: return "Dict entry not inside array"; + case DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE: return "Dict key must be basic type"; + + default: + return "Invalid"; + } +} + +/** + * Checks that the given range of the string is a valid interface name + * in the D-Bus protocol. This includes a length restriction and an + * ASCII subset, see the specification. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_validate_interface (const DBusString *str, + int start, + int len) +{ + const unsigned char *s; + const unsigned char *end; + const unsigned char *iface; + const unsigned char *last_dot; + + _dbus_assert (start >= 0); + _dbus_assert (len >= 0); + _dbus_assert (start <= _dbus_string_get_length (str)); + + if (len > _dbus_string_get_length (str) - start) + return FALSE; + + if (len > DBUS_MAXIMUM_NAME_LENGTH) + return FALSE; + + if (len == 0) + return FALSE; + + last_dot = NULL; + iface = _dbus_string_get_const_data (str) + start; + end = iface + len; + s = iface; + + /* check special cases of first char so it doesn't have to be done + * in the loop. Note we know len > 0 + */ + if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */ + return FALSE; + else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s))) + return FALSE; + else + ++s; + + while (s != end) + { + if (*s == '.') + { + if (_DBUS_UNLIKELY ((s + 1) == end)) + return FALSE; + else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*(s + 1)))) + return FALSE; + last_dot = s; + ++s; /* we just validated the next char, so skip two */ + } + else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s))) + { + return FALSE; + } + + ++s; + } + + if (_DBUS_UNLIKELY (last_dot == NULL)) + return FALSE; + + return TRUE; +} + +/** + * Checks that the given range of the string is a valid member name + * in the D-Bus protocol. This includes a length restriction, etc., + * see the specification. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_validate_member (const DBusString *str, + int start, + int len) +{ + const unsigned char *s; + const unsigned char *end; + const unsigned char *member; + + _dbus_assert (start >= 0); + _dbus_assert (len >= 0); + _dbus_assert (start <= _dbus_string_get_length (str)); + + if (len > _dbus_string_get_length (str) - start) + return FALSE; + + if (len > DBUS_MAXIMUM_NAME_LENGTH) + return FALSE; + + if (len == 0) + return FALSE; + + member = _dbus_string_get_const_data (str) + start; + end = member + len; + s = member; + + /* check special cases of first char so it doesn't have to be done + * in the loop. Note we know len > 0 + */ + + if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s))) + return FALSE; + else + ++s; + + while (s != end) + { + if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s))) + { + return FALSE; + } + + ++s; + } + + return TRUE; +} + +/** + * Checks that the given range of the string is a valid error name + * in the D-Bus protocol. This includes a length restriction, etc., + * see the specification. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_validate_error_name (const DBusString *str, + int start, + int len) +{ + /* Same restrictions as interface name at the moment */ + return _dbus_validate_interface (str, start, len); +} + +/** + * Determine wether the given character is valid as the first character + * in a bus name. + */ +#define VALID_INITIAL_BUS_NAME_CHARACTER(c) \ + ( ((c) >= 'A' && (c) <= 'Z') || \ + ((c) >= 'a' && (c) <= 'z') || \ + ((c) == '_') || ((c) == '-')) + +/** + * Determine wether the given character is valid as a second or later + * character in a bus name + */ +#define VALID_BUS_NAME_CHARACTER(c) \ + ( ((c) >= '0' && (c) <= '9') || \ + ((c) >= 'A' && (c) <= 'Z') || \ + ((c) >= 'a' && (c) <= 'z') || \ + ((c) == '_') || ((c) == '-')) + +/** + * Checks that the given range of the string is a valid bus name in + * the D-Bus protocol. This includes a length restriction, etc., see + * the specification. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid name + */ +dbus_bool_t +_dbus_validate_bus_name (const DBusString *str, + int start, + int len) +{ + const unsigned char *s; + const unsigned char *end; + const unsigned char *iface; + const unsigned char *last_dot; + + _dbus_assert (start >= 0); + _dbus_assert (len >= 0); + _dbus_assert (start <= _dbus_string_get_length (str)); + + if (len > _dbus_string_get_length (str) - start) + return FALSE; + + if (len > DBUS_MAXIMUM_NAME_LENGTH) + return FALSE; + + if (len == 0) + return FALSE; + + last_dot = NULL; + iface = _dbus_string_get_const_data (str) + start; + end = iface + len; + s = iface; + + /* check special cases of first char so it doesn't have to be done + * in the loop. Note we know len > 0 + */ + if (*s == ':') + { + /* unique name */ + ++s; + while (s != end) + { + if (*s == '.') + { + if (_DBUS_UNLIKELY ((s + 1) == end)) + return FALSE; + if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*(s + 1)))) + return FALSE; + ++s; /* we just validated the next char, so skip two */ + } + else if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*s))) + { + return FALSE; + } + + ++s; + } + + return TRUE; + } + else if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */ + return FALSE; + else if (_DBUS_UNLIKELY (!VALID_INITIAL_BUS_NAME_CHARACTER (*s))) + return FALSE; + else + ++s; + + while (s != end) + { + if (*s == '.') + { + if (_DBUS_UNLIKELY ((s + 1) == end)) + return FALSE; + else if (_DBUS_UNLIKELY (!VALID_INITIAL_BUS_NAME_CHARACTER (*(s + 1)))) + return FALSE; + last_dot = s; + ++s; /* we just validated the next char, so skip two */ + } + else if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*s))) + { + return FALSE; + } + + ++s; + } + + if (_DBUS_UNLIKELY (last_dot == NULL)) + return FALSE; + + return TRUE; +} + +/** + * Checks that the given range of the string is a valid message type + * signature in the D-Bus protocol. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is a valid signature + */ +dbus_bool_t +_dbus_validate_signature (const DBusString *str, + int start, + int len) +{ + _dbus_assert (start >= 0); + _dbus_assert (start <= _dbus_string_get_length (str)); + _dbus_assert (len >= 0); + + if (len > _dbus_string_get_length (str) - start) + return FALSE; + + return _dbus_validate_signature_with_reason (str, start, len) == DBUS_VALID; +} + +/** define _dbus_check_is_valid_path() */ +DEFINE_DBUS_NAME_CHECK(path) +/** define _dbus_check_is_valid_interface() */ +DEFINE_DBUS_NAME_CHECK(interface) +/** define _dbus_check_is_valid_member() */ +DEFINE_DBUS_NAME_CHECK(member) +/** define _dbus_check_is_valid_error_name() */ +DEFINE_DBUS_NAME_CHECK(error_name) +/** define _dbus_check_is_valid_bus_name() */ +DEFINE_DBUS_NAME_CHECK(bus_name) +/** define _dbus_check_is_valid_signature() */ +DEFINE_DBUS_NAME_CHECK(signature) + +/** @} */ + +/* tests in dbus-marshal-validate-util.c */ diff --git a/dbus/dbus-marshal-validate.h b/dbus/dbus-marshal-validate.h new file mode 100644 index 00000000..a7d904b2 --- /dev/null +++ b/dbus/dbus-marshal-validate.h @@ -0,0 +1,203 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-marshal-validate.h Validation routines for marshaled data + * + * Copyright (C) 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_MARSHAL_VALIDATE_H +#define DBUS_MARSHAL_VALIDATE_H + +#include + +#ifndef PACKAGE +#error "config.h not included here" +#endif + +/** + * @addtogroup DBusMarshal + * + * @{ + */ + +/** + * This is used rather than a bool for high visibility + */ +typedef enum +{ + DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY, + DBUS_VALIDATION_MODE_DATA_IS_UNTRUSTED +} DBusValidationMode; + +/** + * This is primarily used in unit testing, so we can verify that each + * invalid message is invalid for the expected reasons. Thus we really + * want a distinct enum value for every codepath leaving the validator + * functions. Enum values are specified manually for ease of debugging + * (so you can see the enum value given a printf) + */ +typedef enum +{ +#define _DBUS_NEGATIVE_VALIDITY_COUNT 4 + DBUS_VALIDITY_UNKNOWN_OOM_ERROR = -4, /**< can't determine validity due to OOM */ + DBUS_INVALID_FOR_UNKNOWN_REASON = -3, + DBUS_VALID_BUT_INCOMPLETE = -2, + DBUS_VALIDITY_UNKNOWN = -1, + DBUS_VALID = 0, /**< the data is valid */ + DBUS_INVALID_UNKNOWN_TYPECODE = 1, + DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE = 2, + DBUS_INVALID_SIGNATURE_TOO_LONG = 3, /* this one is impossible right now since + * you can't put a too-long value in a byte + */ + DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION = 4, + DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION = 5, + DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED = 6, + DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED = 7, + DBUS_INVALID_STRUCT_HAS_NO_FIELDS = 8, + DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL = 9, + DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE = 10, + DBUS_INVALID_NOT_ENOUGH_DATA = 11, + DBUS_INVALID_TOO_MUCH_DATA = 12, /**< trailing junk makes it invalid */ + DBUS_INVALID_BAD_BYTE_ORDER = 13, + DBUS_INVALID_BAD_PROTOCOL_VERSION = 14, + DBUS_INVALID_BAD_MESSAGE_TYPE = 15, + DBUS_INVALID_BAD_SERIAL = 16, + DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH = 17, + DBUS_INVALID_INSANE_BODY_LENGTH = 18, + DBUS_INVALID_MESSAGE_TOO_LONG = 19, + DBUS_INVALID_HEADER_FIELD_CODE = 20, + DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE = 21, + DBUS_INVALID_USES_LOCAL_INTERFACE = 22, + DBUS_INVALID_USES_LOCAL_PATH = 23, + DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE = 24, + DBUS_INVALID_BAD_DESTINATION = 25, + DBUS_INVALID_BAD_INTERFACE = 26, + DBUS_INVALID_BAD_MEMBER = 27, + DBUS_INVALID_BAD_ERROR_NAME = 28, + DBUS_INVALID_BAD_SENDER = 29, + DBUS_INVALID_MISSING_PATH = 30, + DBUS_INVALID_MISSING_INTERFACE = 31, + DBUS_INVALID_MISSING_MEMBER = 32, + DBUS_INVALID_MISSING_ERROR_NAME = 33, + DBUS_INVALID_MISSING_REPLY_SERIAL = 34, + DBUS_INVALID_LENGTH_OUT_OF_BOUNDS = 35, + DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM = 36, + DBUS_INVALID_BAD_PATH = 37, + DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS = 38, + DBUS_INVALID_BAD_UTF8_IN_STRING = 39, + DBUS_INVALID_ARRAY_LENGTH_INCORRECT = 40, + DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS = 41, + DBUS_INVALID_VARIANT_SIGNATURE_BAD = 42, + DBUS_INVALID_VARIANT_SIGNATURE_EMPTY = 43, + DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES = 44, + DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL = 45, + DBUS_INVALID_STRING_MISSING_NUL = 46, + DBUS_INVALID_SIGNATURE_MISSING_NUL = 47, + DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION = 48, + DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED = 49, + DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED = 50, + DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS = 51, + DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD = 52, + DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS = 53, + DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY = 54, + DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE = 55, + DBUS_VALIDITY_LAST +} DBusValidity; + +DBusValidity _dbus_validate_signature_with_reason (const DBusString *type_str, + int type_pos, + int len); +DBusValidity _dbus_validate_body_with_reason (const DBusString *expected_signature, + int expected_signature_start, + int byte_order, + int *bytes_remaining, + const DBusString *value_str, + int value_pos, + int len); + +const char *_dbus_validity_to_error_message (DBusValidity validity); + +dbus_bool_t _dbus_validate_path (const DBusString *str, + int start, + int len); +dbus_bool_t _dbus_validate_interface (const DBusString *str, + int start, + int len); +dbus_bool_t _dbus_validate_member (const DBusString *str, + int start, + int len); +dbus_bool_t _dbus_validate_error_name (const DBusString *str, + int start, + int len); +dbus_bool_t _dbus_validate_bus_name (const DBusString *str, + int start, + int len); +dbus_bool_t _dbus_validate_signature (const DBusString *str, + int start, + int len); + +#ifdef DBUS_DISABLE_CHECKS + +/* Be sure they don't exist, since we don't want to use them outside of checks + * and so we want the compile failure. + */ +#define DECLARE_DBUS_NAME_CHECK(what) +#define DEFINE_DBUS_NAME_CHECK(what) + +#else /* !DBUS_DISABLE_CHECKS */ + +/** A name check is used in _dbus_return_if_fail(), it's not suitable + * for validating untrusted data. use _dbus_validate_whatever for that. + */ +#define DECLARE_DBUS_NAME_CHECK(what) \ +dbus_bool_t _dbus_check_is_valid_##what (const char *name) + +/** Define a name check to be used in _dbus_return_if_fail() statements. + */ +#define DEFINE_DBUS_NAME_CHECK(what) \ +dbus_bool_t \ +_dbus_check_is_valid_##what (const char *name) \ +{ \ + DBusString str; \ + \ + if (name == NULL) \ + return FALSE; \ + \ + _dbus_string_init_const (&str, name); \ + return _dbus_validate_##what (&str, 0, \ + _dbus_string_get_length (&str)); \ +} +#endif /* !DBUS_DISABLE_CHECKS */ + +/** defines _dbus_check_is_valid_path() */ +DECLARE_DBUS_NAME_CHECK(path); +/** defines _dbus_check_is_valid_interface() */ +DECLARE_DBUS_NAME_CHECK(interface); +/** defines _dbus_check_is_valid_member() */ +DECLARE_DBUS_NAME_CHECK(member); +/** defines _dbus_check_is_valid_error_name() */ +DECLARE_DBUS_NAME_CHECK(error_name); +/** defines _dbus_check_is_valid_bus_name() */ +DECLARE_DBUS_NAME_CHECK(bus_name); +/** defines _dbus_check_is_valid_signature() */ +DECLARE_DBUS_NAME_CHECK(signature); + +/** @} */ + +#endif /* DBUS_MARSHAL_VALIDATE_H */ diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c new file mode 100644 index 00000000..5e93c047 --- /dev/null +++ b/dbus/dbus-memory.c @@ -0,0 +1,842 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-memory.c D-Bus memory handling + * + * Copyright (C) 2002, 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-memory.h" +#include "dbus-internals.h" +#include "dbus-sysdeps.h" +#include "dbus-list.h" +#include + +/** + * @defgroup DBusMemory Memory Allocation + * @ingroup DBus + * @brief dbus_malloc(), dbus_free(), etc. + * + * Functions and macros related to allocating and releasing + * blocks of memory. + * + */ + +/** + * @defgroup DBusMemoryInternals Memory allocation implementation details + * @ingroup DBusInternals + * @brief internals of dbus_malloc() etc. + * + * Implementation details related to allocating and releasing blocks + * of memory. + */ + +/** + * @addtogroup DBusMemory + * + * @{ + */ + +/** + * @def dbus_new + * + * Safe macro for using dbus_malloc(). Accepts the type + * to allocate and the number of type instances to + * allocate as arguments, and returns a memory block + * cast to the desired type, instead of as a void*. + * + * @param type type name to allocate + * @param count number of instances in the allocated array + * @returns the new memory block or #NULL on failure + */ + +/** + * @def dbus_new0 + * + * Safe macro for using dbus_malloc0(). Accepts the type + * to allocate and the number of type instances to + * allocate as arguments, and returns a memory block + * cast to the desired type, instead of as a void*. + * The allocated array is initialized to all-bits-zero. + * + * @param type type name to allocate + * @param count number of instances in the allocated array + * @returns the new memory block or #NULL on failure + */ + +/** + * @typedef DBusFreeFunction + * + * The type of a function which frees a block of memory. + * + * @param memory the memory to free + */ + +/** @} */ /* end of public API docs */ + +/** + * @addtogroup DBusMemoryInternals + * + * @{ + */ + +#ifdef DBUS_BUILD_TESTS +static dbus_bool_t debug_initialized = FALSE; +static int fail_nth = -1; +static size_t fail_size = 0; +static int fail_alloc_counter = _DBUS_INT_MAX; +static int n_failures_per_failure = 1; +static int n_failures_this_failure = 0; +static dbus_bool_t guards = FALSE; +static dbus_bool_t disable_mem_pools = FALSE; +static dbus_bool_t backtrace_on_fail_alloc = FALSE; +static DBusAtomic n_blocks_outstanding = {0}; + +/** value stored in guard padding for debugging buffer overrun */ +#define GUARD_VALUE 0xdeadbeef +/** size of the information about the block stored in guard mode */ +#define GUARD_INFO_SIZE 8 +/** size of the GUARD_VALUE-filled padding after the header info */ +#define GUARD_START_PAD 16 +/** size of the GUARD_VALUE-filled padding at the end of the block */ +#define GUARD_END_PAD 16 +/** size of stuff at start of block */ +#define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE) +/** total extra size over the requested allocation for guard stuff */ +#define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD) + +static void +_dbus_initialize_malloc_debug (void) +{ + if (!debug_initialized) + { + debug_initialized = TRUE; + + if (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH") != NULL) + { + fail_nth = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH")); + fail_alloc_counter = fail_nth; + _dbus_verbose ("Will fail malloc every %d times\n", fail_nth); + } + + if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL) + { + fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN")); + _dbus_verbose ("Will fail mallocs over %ld bytes\n", + (long) fail_size); + } + + if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL) + { + guards = TRUE; + _dbus_verbose ("Will use malloc guards\n"); + } + + if (_dbus_getenv ("DBUS_DISABLE_MEM_POOLS") != NULL) + { + disable_mem_pools = TRUE; + _dbus_verbose ("Will disable memory pools\n"); + } + + if (_dbus_getenv ("DBUS_MALLOC_BACKTRACES") != NULL) + { + backtrace_on_fail_alloc = TRUE; + _dbus_verbose ("Will backtrace on failing a malloc\n"); + } + } +} + +/** + * Whether to turn off mem pools, useful for leak checking. + * + * @returns #TRUE if mempools should not be used. + */ +dbus_bool_t +_dbus_disable_mem_pools (void) +{ + _dbus_initialize_malloc_debug (); + return disable_mem_pools; +} + +/** + * Sets the number of allocations until we simulate a failed + * allocation. If set to 0, the next allocation to run + * fails; if set to 1, one succeeds then the next fails; etc. + * Set to _DBUS_INT_MAX to not fail anything. + * + * @param until_next_fail number of successful allocs before one fails + */ +void +_dbus_set_fail_alloc_counter (int until_next_fail) +{ + _dbus_initialize_malloc_debug (); + + fail_alloc_counter = until_next_fail; + +#if 0 + _dbus_verbose ("Set fail alloc counter = %d\n", fail_alloc_counter); +#endif +} + +/** + * Gets the number of successful allocs until we'll simulate + * a failed alloc. + * + * @returns current counter value + */ +int +_dbus_get_fail_alloc_counter (void) +{ + _dbus_initialize_malloc_debug (); + + return fail_alloc_counter; +} + +/** + * Sets how many mallocs to fail when the fail alloc counter reaches + * 0. + * + * @param failures_per_failure number to fail + */ +void +_dbus_set_fail_alloc_failures (int failures_per_failure) +{ + n_failures_per_failure = failures_per_failure; +} + +/** + * Gets the number of failures we'll have when the fail malloc + * counter reaches 0. + * + * @returns number of failures planned + */ +int +_dbus_get_fail_alloc_failures (void) +{ + return n_failures_per_failure; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Called when about to alloc some memory; if + * it returns #TRUE, then the allocation should + * fail. If it returns #FALSE, then the allocation + * should not fail. + * + * @returns #TRUE if this alloc should fail + */ +dbus_bool_t +_dbus_decrement_fail_alloc_counter (void) +{ + _dbus_initialize_malloc_debug (); + + if (fail_alloc_counter <= 0) + { + if (backtrace_on_fail_alloc) + _dbus_print_backtrace (); + + _dbus_verbose ("failure %d\n", n_failures_this_failure); + + n_failures_this_failure += 1; + if (n_failures_this_failure >= n_failures_per_failure) + { + if (fail_nth >= 0) + fail_alloc_counter = fail_nth; + else + fail_alloc_counter = _DBUS_INT_MAX; + + n_failures_this_failure = 0; + + _dbus_verbose ("reset fail alloc counter to %d\n", fail_alloc_counter); + } + + return TRUE; + } + else + { + fail_alloc_counter -= 1; + return FALSE; + } +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Get the number of outstanding malloc()'d blocks. + * + * @returns number of blocks + */ +int +_dbus_get_malloc_blocks_outstanding (void) +{ + return n_blocks_outstanding.value; +} + +/** + * Where the block came from. + */ +typedef enum +{ + SOURCE_UNKNOWN, + SOURCE_MALLOC, + SOURCE_REALLOC, + SOURCE_MALLOC_ZERO, + SOURCE_REALLOC_NULL +} BlockSource; + +static const char* +source_string (BlockSource source) +{ + switch (source) + { + case SOURCE_UNKNOWN: + return "unknown"; + case SOURCE_MALLOC: + return "malloc"; + case SOURCE_REALLOC: + return "realloc"; + case SOURCE_MALLOC_ZERO: + return "malloc0"; + case SOURCE_REALLOC_NULL: + return "realloc(NULL)"; + } + _dbus_assert_not_reached ("Invalid malloc block source ID"); + return "invalid!"; +} + +static void +check_guards (void *free_block, + dbus_bool_t overwrite) +{ + if (free_block != NULL) + { + unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET; + size_t requested_bytes = *(dbus_uint32_t*)block; + BlockSource source = *(dbus_uint32_t*)(block + 4); + unsigned int i; + dbus_bool_t failed; + + failed = FALSE; + +#if 0 + _dbus_verbose ("Checking %d bytes request from source %s\n", + requested_bytes, source_string (source)); +#endif + + i = GUARD_INFO_SIZE; + while (i < GUARD_START_OFFSET) + { + dbus_uint32_t value = *(dbus_uint32_t*) &block[i]; + if (value != GUARD_VALUE) + { + _dbus_warn ("Block of %lu bytes from %s had start guard value 0x%ux at %d expected 0x%x\n", + (long) requested_bytes, source_string (source), + value, i, GUARD_VALUE); + failed = TRUE; + } + + i += 4; + } + + i = GUARD_START_OFFSET + requested_bytes; + while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD)) + { + dbus_uint32_t value = *(dbus_uint32_t*) &block[i]; + if (value != GUARD_VALUE) + { + _dbus_warn ("Block of %lu bytes from %s had end guard value 0x%ux at %d expected 0x%x\n", + (long) requested_bytes, source_string (source), + value, i, GUARD_VALUE); + failed = TRUE; + } + + i += 4; + } + + /* set memory to anything but nul bytes */ + if (overwrite) + memset (free_block, 'g', requested_bytes); + + if (failed) + _dbus_assert_not_reached ("guard value corruption"); + } +} + +static void* +set_guards (void *real_block, + size_t requested_bytes, + BlockSource source) +{ + unsigned char *block = real_block; + unsigned int i; + + if (block == NULL) + return NULL; + + _dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE); + + *((dbus_uint32_t*)block) = requested_bytes; + *((dbus_uint32_t*)(block + 4)) = source; + + i = GUARD_INFO_SIZE; + while (i < GUARD_START_OFFSET) + { + (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE; + + i += 4; + } + + i = GUARD_START_OFFSET + requested_bytes; + while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD)) + { + (*(dbus_uint32_t*) &block[i]) = GUARD_VALUE; + + i += 4; + } + + check_guards (block + GUARD_START_OFFSET, FALSE); + + return block + GUARD_START_OFFSET; +} + +#endif + +/** @} */ /* End of internals docs */ + + +/** + * @addtogroup DBusMemory + * + * @{ + */ + +/** + * Allocates the given number of bytes, as with standard + * malloc(). Guaranteed to return #NULL if bytes is zero + * on all platforms. Returns #NULL if the allocation fails. + * The memory must be released with dbus_free(). + * + * dbus_malloc() memory is NOT safe to free with regular free() from + * the C library. Free it with dbus_free() only. + * + * @param bytes number of bytes to allocate + * @return allocated memory, or #NULL if the allocation fails. + */ +void* +dbus_malloc (size_t bytes) +{ +#ifdef DBUS_BUILD_TESTS + _dbus_initialize_malloc_debug (); + + if (_dbus_decrement_fail_alloc_counter ()) + { + _dbus_verbose (" FAILING malloc of %ld bytes\n", (long) bytes); + return NULL; + } +#endif + + if (bytes == 0) /* some system mallocs handle this, some don't */ + return NULL; +#ifdef DBUS_BUILD_TESTS + else if (fail_size != 0 && bytes > fail_size) + return NULL; + else if (guards) + { + void *block; + + block = malloc (bytes + GUARD_EXTRA_SIZE); + if (block) + _dbus_atomic_inc (&n_blocks_outstanding); + + return set_guards (block, bytes, SOURCE_MALLOC); + } +#endif + else + { + void *mem; + mem = malloc (bytes); +#ifdef DBUS_BUILD_TESTS + if (mem) + _dbus_atomic_inc (&n_blocks_outstanding); +#endif + return mem; + } +} + +/** + * Allocates the given number of bytes, as with standard malloc(), but + * all bytes are initialized to zero as with calloc(). Guaranteed to + * return #NULL if bytes is zero on all platforms. Returns #NULL if the + * allocation fails. The memory must be released with dbus_free(). + * + * dbus_malloc0() memory is NOT safe to free with regular free() from + * the C library. Free it with dbus_free() only. + * + * @param bytes number of bytes to allocate + * @return allocated memory, or #NULL if the allocation fails. + */ +void* +dbus_malloc0 (size_t bytes) +{ +#ifdef DBUS_BUILD_TESTS + _dbus_initialize_malloc_debug (); + + if (_dbus_decrement_fail_alloc_counter ()) + { + _dbus_verbose (" FAILING malloc0 of %ld bytes\n", (long) bytes); + + return NULL; + } +#endif + + if (bytes == 0) + return NULL; +#ifdef DBUS_BUILD_TESTS + else if (fail_size != 0 && bytes > fail_size) + return NULL; + else if (guards) + { + void *block; + + block = calloc (bytes + GUARD_EXTRA_SIZE, 1); + if (block) + _dbus_atomic_inc (&n_blocks_outstanding); + return set_guards (block, bytes, SOURCE_MALLOC_ZERO); + } +#endif + else + { + void *mem; + mem = calloc (bytes, 1); +#ifdef DBUS_BUILD_TESTS + if (mem) + _dbus_atomic_inc (&n_blocks_outstanding); +#endif + return mem; + } +} + +/** + * Resizes a block of memory previously allocated by dbus_malloc() or + * dbus_malloc0(). Guaranteed to free the memory and return #NULL if bytes + * is zero on all platforms. Returns #NULL if the resize fails. + * If the resize fails, the memory is not freed. + * + * @param memory block to be resized + * @param bytes new size of the memory block + * @return allocated memory, or #NULL if the resize fails. + */ +void* +dbus_realloc (void *memory, + size_t bytes) +{ +#ifdef DBUS_BUILD_TESTS + _dbus_initialize_malloc_debug (); + + if (_dbus_decrement_fail_alloc_counter ()) + { + _dbus_verbose (" FAILING realloc of %ld bytes\n", (long) bytes); + + return NULL; + } +#endif + + if (bytes == 0) /* guarantee this is safe */ + { + dbus_free (memory); + return NULL; + } +#ifdef DBUS_BUILD_TESTS + else if (fail_size != 0 && bytes > fail_size) + return NULL; + else if (guards) + { + if (memory) + { + size_t old_bytes; + void *block; + + check_guards (memory, FALSE); + + block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET, + bytes + GUARD_EXTRA_SIZE); + + old_bytes = *(dbus_uint32_t*)block; + if (block && bytes >= old_bytes) + /* old guards shouldn't have moved */ + check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE); + + return set_guards (block, bytes, SOURCE_REALLOC); + } + else + { + void *block; + + block = malloc (bytes + GUARD_EXTRA_SIZE); + + if (block) + _dbus_atomic_inc (&n_blocks_outstanding); + + return set_guards (block, bytes, SOURCE_REALLOC_NULL); + } + } +#endif + else + { + void *mem; + mem = realloc (memory, bytes); +#ifdef DBUS_BUILD_TESTS + if (memory == NULL && mem != NULL) + _dbus_atomic_inc (&n_blocks_outstanding); +#endif + return mem; + } +} + +/** + * Frees a block of memory previously allocated by dbus_malloc() or + * dbus_malloc0(). If passed #NULL, does nothing. + * + * @param memory block to be freed + */ +void +dbus_free (void *memory) +{ +#ifdef DBUS_BUILD_TESTS + if (guards) + { + check_guards (memory, TRUE); + if (memory) + { + _dbus_atomic_dec (&n_blocks_outstanding); + + _dbus_assert (n_blocks_outstanding.value >= 0); + + free (((unsigned char*)memory) - GUARD_START_OFFSET); + } + + return; + } +#endif + + if (memory) /* we guarantee it's safe to free (NULL) */ + { +#ifdef DBUS_BUILD_TESTS + _dbus_atomic_dec (&n_blocks_outstanding); + + _dbus_assert (n_blocks_outstanding.value >= 0); +#endif + + free (memory); + } +} + +/** + * Frees a #NULL-terminated array of strings. + * If passed #NULL, does nothing. + * + * @param str_array the array to be freed + */ +void +dbus_free_string_array (char **str_array) +{ + if (str_array) + { + int i; + + i = 0; + while (str_array[i]) + { + dbus_free (str_array[i]); + i++; + } + + dbus_free (str_array); + } +} + +/** @} */ /* End of public API docs block */ + + +/** + * @addtogroup DBusMemoryInternals + * + * @{ + */ + +/** + * _dbus_current_generation is used to track each + * time that dbus_shutdown() is called, so we can + * reinit things after it's been called. It is simply + * incremented each time we shut down. + */ +int _dbus_current_generation = 1; + +/** + * Represents a function to be called on shutdown. + */ +typedef struct ShutdownClosure ShutdownClosure; + +/** + * This struct represents a function to be called on shutdown. + */ +struct ShutdownClosure +{ + ShutdownClosure *next; /**< Next ShutdownClosure */ + DBusShutdownFunction func; /**< Function to call */ + void *data; /**< Data for function */ +}; + +_DBUS_DEFINE_GLOBAL_LOCK (shutdown_funcs); +static ShutdownClosure *registered_globals = NULL; + +/** + * Register a cleanup function to be called exactly once + * the next time dbus_shutdown() is called. + * + * @param func the function + * @param data data to pass to the function + * @returns #FALSE on not enough memory + */ +dbus_bool_t +_dbus_register_shutdown_func (DBusShutdownFunction func, + void *data) +{ + ShutdownClosure *c; + + c = dbus_new (ShutdownClosure, 1); + + if (c == NULL) + return FALSE; + + c->func = func; + c->data = data; + + _DBUS_LOCK (shutdown_funcs); + + c->next = registered_globals; + registered_globals = c; + + _DBUS_UNLOCK (shutdown_funcs); + + return TRUE; +} + +/** @} */ /* End of private API docs block */ + + +/** + * @addtogroup DBusMemory + * + * @{ + */ + +/** + * Frees all memory allocated internally by libdbus and + * reverses the effects of dbus_threads_init(). libdbus keeps internal + * global variables, for example caches and thread locks, and it + * can be useful to free these internal data structures. + * + * dbus_shutdown() does NOT free memory that was returned + * to the application. It only returns libdbus-internal + * data structures. + * + * You MUST free all memory and release all reference counts + * returned to you by libdbus prior to calling dbus_shutdown(). + * + * You can't continue to use any D-Bus objects, such as connections, + * that were allocated prior to dbus_shutdown(). You can, however, + * start over; call dbus_threads_init() again, create new connections, + * and so forth. + * + * WARNING: dbus_shutdown() is NOT thread safe, it must be called + * while NO other threads are using D-Bus. (Remember, you have to free + * all D-Bus objects and memory before you call dbus_shutdown(), so no + * thread can be using libdbus.) + * + * The purpose of dbus_shutdown() is to allow applications to get + * clean output from memory leak checkers. dbus_shutdown() may also be + * useful if you want to dlopen() libdbus instead of linking to it, + * and want to be able to unload the library again. + * + * There is absolutely no requirement to call dbus_shutdown() - in fact, + * most applications won't bother and should not feel guilty. + * + * You have to know that nobody is using libdbus in your application's + * process before you can call dbus_shutdown(). One implication of this + * is that calling dbus_shutdown() from a library is almost certainly + * wrong, since you don't know what the rest of the app is up to. + * + */ +void +dbus_shutdown (void) +{ + while (registered_globals != NULL) + { + ShutdownClosure *c; + + c = registered_globals; + registered_globals = c->next; + + (* c->func) (c->data); + + dbus_free (c); + } + + _dbus_current_generation += 1; +} + +/** @} */ /** End of public API docs block */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" + +/** + * @ingroup DBusMemoryInternals + * Unit test for DBusMemory + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_memory_test (void) +{ + dbus_bool_t old_guards; + void *p; + size_t size; + + old_guards = guards; + guards = TRUE; + p = dbus_malloc (4); + if (p == NULL) + _dbus_assert_not_reached ("no memory"); + for (size = 4; size < 256; size += 4) + { + p = dbus_realloc (p, size); + if (p == NULL) + _dbus_assert_not_reached ("no memory"); + } + for (size = 256; size != 0; size -= 4) + { + p = dbus_realloc (p, size); + if (p == NULL) + _dbus_assert_not_reached ("no memory"); + } + dbus_free (p); + guards = old_guards; + return TRUE; +} + +#endif diff --git a/dbus/dbus-memory.h b/dbus/dbus-memory.h new file mode 100644 index 00000000..d0e92d1a --- /dev/null +++ b/dbus/dbus-memory.h @@ -0,0 +1,59 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-memory.h D-Bus memory handling + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_MEMORY_H +#define DBUS_MEMORY_H + +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusMemory + * @{ + */ + +void* dbus_malloc (size_t bytes); +void* dbus_malloc0 (size_t bytes); +void* dbus_realloc (void *memory, + size_t bytes); +void dbus_free (void *memory); + +#define dbus_new(type, count) ((type*)dbus_malloc (sizeof (type) * (count))); +#define dbus_new0(type, count) ((type*)dbus_malloc0 (sizeof (type) * (count))); + +void dbus_free_string_array (char **str_array); + +typedef void (* DBusFreeFunction) (void *memory); + +void dbus_shutdown (void); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_MEMORY_H */ diff --git a/dbus/dbus-mempool.c b/dbus/dbus-mempool.c new file mode 100644 index 00000000..2a41cb16 --- /dev/null +++ b/dbus/dbus-mempool.c @@ -0,0 +1,577 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-mempool.h Memory pools + * + * Copyright (C) 2002, 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-mempool.h" +#include "dbus-internals.h" + +/** + * @defgroup DBusMemPool memory pools + * @ingroup DBusInternals + * @brief DBusMemPool object + * + * Types and functions related to DBusMemPool. A memory pool is used + * to decrease memory fragmentation/overhead and increase speed for + * blocks of small uniformly-sized objects. The main point is to avoid + * the overhead of a malloc block for each small object, speed is + * secondary. + */ + +/** + * @defgroup DBusMemPoolInternals Memory pool implementation details + * @ingroup DBusInternals + * @brief DBusMemPool implementation details + * + * The guts of DBusMemPool. + * + * @{ + */ + +/** + * typedef so DBusFreedElement struct can refer to itself. + */ +typedef struct DBusFreedElement DBusFreedElement; + +/** + * struct representing an element on the free list. + * We just cast freed elements to this so we can + * make a list out of them. + */ +struct DBusFreedElement +{ + DBusFreedElement *next; /**< next element of the free list */ +}; + +/** + * The dummy size of the variable-length "elements" + * field in DBusMemBlock + */ +#define ELEMENT_PADDING 4 + +/** + * Typedef for DBusMemBlock so the struct can recursively + * point to itself. + */ +typedef struct DBusMemBlock DBusMemBlock; + +/** + * DBusMemBlock object represents a single malloc()-returned + * block that gets chunked up into objects in the memory pool. + */ +struct DBusMemBlock +{ + DBusMemBlock *next; /**< next block in the list, which is already used up; + * only saved so we can free all the blocks + * when we free the mem pool. + */ + + /* this is a long so that "elements" is aligned */ + long used_so_far; /**< bytes of this block already allocated as elements. */ + + unsigned char elements[ELEMENT_PADDING]; /**< the block data, actually allocated to required size */ +}; + +/** + * Internals fields of DBusMemPool + */ +struct DBusMemPool +{ + int element_size; /**< size of a single object in the pool */ + int block_size; /**< size of most recently allocated block */ + unsigned int zero_elements : 1; /**< whether to zero-init allocated elements */ + + DBusFreedElement *free_elements; /**< a free list of elements to recycle */ + DBusMemBlock *blocks; /**< blocks of memory from malloc() */ + int allocated_elements; /**< Count of outstanding allocated elements */ +}; + +/** @} */ + +/** + * @addtogroup DBusMemPool + * + * @{ + */ + +/** + * @typedef DBusMemPool + * + * Opaque object representing a memory pool. Memory pools allow + * avoiding per-malloc-block memory overhead when allocating a lot of + * small objects that are all the same size. They are slightly + * faster than calling malloc() also. + */ + +/** + * Creates a new memory pool, or returns #NULL on failure. Objects in + * the pool must be at least sizeof(void*) bytes each, due to the way + * memory pools work. To avoid creating 64 bit problems, this means at + * least 8 bytes on all platforms, unless you are 4 bytes on 32-bit + * and 8 bytes on 64-bit. + * + * @param element_size size of an element allocated from the pool. + * @param zero_elements whether to zero-initialize elements + * @returns the new pool or #NULL + */ +DBusMemPool* +_dbus_mem_pool_new (int element_size, + dbus_bool_t zero_elements) +{ + DBusMemPool *pool; + + pool = dbus_new0 (DBusMemPool, 1); + if (pool == NULL) + return NULL; + + /* Make the element size at least 8 bytes. */ + if (element_size < 8) + element_size = 8; + + /* these assertions are equivalent but the first is more clear + * to programmers that see it fail. + */ + _dbus_assert (element_size >= (int) sizeof (void*)); + _dbus_assert (element_size >= (int) sizeof (DBusFreedElement)); + + /* align the element size to a pointer boundary so we won't get bus + * errors under other architectures. + */ + pool->element_size = _DBUS_ALIGN_VALUE (element_size, sizeof (void *)); + + pool->zero_elements = zero_elements != FALSE; + + pool->allocated_elements = 0; + + /* pick a size for the first block; it increases + * for each block we need to allocate. This is + * actually half the initial block size + * since _dbus_mem_pool_alloc() unconditionally + * doubles it prior to creating a new block. */ + pool->block_size = pool->element_size * 8; + + _dbus_assert ((pool->block_size % + pool->element_size) == 0); + + return pool; +} + +/** + * Frees a memory pool (and all elements allocated from it). + * + * @param pool the memory pool. + */ +void +_dbus_mem_pool_free (DBusMemPool *pool) +{ + DBusMemBlock *block; + + block = pool->blocks; + while (block != NULL) + { + DBusMemBlock *next = block->next; + + dbus_free (block); + + block = next; + } + + dbus_free (pool); +} + +/** + * Allocates an object from the memory pool. + * The object must be freed with _dbus_mem_pool_dealloc(). + * + * @param pool the memory pool + * @returns the allocated object or #NULL if no memory. + */ +void* +_dbus_mem_pool_alloc (DBusMemPool *pool) +{ +#ifdef DBUS_BUILD_TESTS + if (_dbus_disable_mem_pools ()) + { + DBusMemBlock *block; + int alloc_size; + + /* This is obviously really silly, but it's + * debug-mode-only code that is compiled out + * when tests are disabled (_dbus_disable_mem_pools() + * is a constant expression FALSE so this block + * should vanish) + */ + + alloc_size = sizeof (DBusMemBlock) - ELEMENT_PADDING + + pool->element_size; + + if (pool->zero_elements) + block = dbus_malloc0 (alloc_size); + else + block = dbus_malloc (alloc_size); + + if (block != NULL) + { + block->next = pool->blocks; + pool->blocks = block; + pool->allocated_elements += 1; + + return (void*) &block->elements[0]; + } + else + return NULL; + } + else +#endif + { + if (_dbus_decrement_fail_alloc_counter ()) + { + _dbus_verbose (" FAILING mempool alloc\n"); + return NULL; + } + else if (pool->free_elements) + { + DBusFreedElement *element = pool->free_elements; + + pool->free_elements = pool->free_elements->next; + + if (pool->zero_elements) + memset (element, '\0', pool->element_size); + + pool->allocated_elements += 1; + + return element; + } + else + { + void *element; + + if (pool->blocks == NULL || + pool->blocks->used_so_far == pool->block_size) + { + /* Need a new block */ + DBusMemBlock *block; + int alloc_size; +#ifdef DBUS_BUILD_TESTS + int saved_counter; +#endif + + if (pool->block_size <= _DBUS_INT_MAX / 4) /* avoid overflow */ + { + /* use a larger block size for our next block */ + pool->block_size *= 2; + _dbus_assert ((pool->block_size % + pool->element_size) == 0); + } + + alloc_size = sizeof (DBusMemBlock) - ELEMENT_PADDING + pool->block_size; + +#ifdef DBUS_BUILD_TESTS + /* We save/restore the counter, so that memory pools won't + * cause a given function to have different number of + * allocations on different invocations. i.e. when testing + * we want consistent alloc patterns. So we skip our + * malloc here for purposes of failed alloc simulation. + */ + saved_counter = _dbus_get_fail_alloc_counter (); + _dbus_set_fail_alloc_counter (_DBUS_INT_MAX); +#endif + + if (pool->zero_elements) + block = dbus_malloc0 (alloc_size); + else + block = dbus_malloc (alloc_size); + +#ifdef DBUS_BUILD_TESTS + _dbus_set_fail_alloc_counter (saved_counter); + _dbus_assert (saved_counter == _dbus_get_fail_alloc_counter ()); +#endif + + if (block == NULL) + return NULL; + + block->used_so_far = 0; + block->next = pool->blocks; + pool->blocks = block; + } + + element = &pool->blocks->elements[pool->blocks->used_so_far]; + + pool->blocks->used_so_far += pool->element_size; + + pool->allocated_elements += 1; + + return element; + } + } +} + +/** + * Deallocates an object previously created with + * _dbus_mem_pool_alloc(). The previous object + * must have come from this same pool. + * @param pool the memory pool + * @param element the element earlier allocated. + * @returns #TRUE if there are no remaining allocated elements + */ +dbus_bool_t +_dbus_mem_pool_dealloc (DBusMemPool *pool, + void *element) +{ +#ifdef DBUS_BUILD_TESTS + if (_dbus_disable_mem_pools ()) + { + DBusMemBlock *block; + DBusMemBlock *prev; + + /* mmm, fast. ;-) debug-only code, so doesn't matter. */ + + prev = NULL; + block = pool->blocks; + + while (block != NULL) + { + if (block->elements == (unsigned char*) element) + { + if (prev) + prev->next = block->next; + else + pool->blocks = block->next; + + dbus_free (block); + + _dbus_assert (pool->allocated_elements > 0); + pool->allocated_elements -= 1; + + if (pool->allocated_elements == 0) + _dbus_assert (pool->blocks == NULL); + + return pool->blocks == NULL; + } + prev = block; + block = block->next; + } + + _dbus_assert_not_reached ("freed nonexistent block"); + return FALSE; + } + else +#endif + { + DBusFreedElement *freed; + + freed = element; + freed->next = pool->free_elements; + pool->free_elements = freed; + + _dbus_assert (pool->allocated_elements > 0); + pool->allocated_elements -= 1; + + return pool->allocated_elements == 0; + } +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include +#include + +static void +time_for_size (int size) +{ + int i; + int j; + clock_t start; + clock_t end; +#define FREE_ARRAY_SIZE 512 +#define N_ITERATIONS FREE_ARRAY_SIZE * 512 + void *to_free[FREE_ARRAY_SIZE]; + DBusMemPool *pool; + + _dbus_verbose ("Timings for size %d\n", size); + + _dbus_verbose (" malloc\n"); + + start = clock (); + + i = 0; + j = 0; + while (i < N_ITERATIONS) + { + to_free[j] = dbus_malloc (size); + _dbus_assert (to_free[j] != NULL); /* in a real app of course this is wrong */ + + ++j; + + if (j == FREE_ARRAY_SIZE) + { + j = 0; + while (j < FREE_ARRAY_SIZE) + { + dbus_free (to_free[j]); + ++j; + } + + j = 0; + } + + ++i; + } + + end = clock (); + + _dbus_verbose (" created/destroyed %d elements in %g seconds\n", + N_ITERATIONS, (end - start) / (double) CLOCKS_PER_SEC); + + + + _dbus_verbose (" mempools\n"); + + start = clock (); + + pool = _dbus_mem_pool_new (size, FALSE); + + i = 0; + j = 0; + while (i < N_ITERATIONS) + { + to_free[j] = _dbus_mem_pool_alloc (pool); + _dbus_assert (to_free[j] != NULL); /* in a real app of course this is wrong */ + + ++j; + + if (j == FREE_ARRAY_SIZE) + { + j = 0; + while (j < FREE_ARRAY_SIZE) + { + _dbus_mem_pool_dealloc (pool, to_free[j]); + ++j; + } + + j = 0; + } + + ++i; + } + + _dbus_mem_pool_free (pool); + + end = clock (); + + _dbus_verbose (" created/destroyed %d elements in %g seconds\n", + N_ITERATIONS, (end - start) / (double) CLOCKS_PER_SEC); + + _dbus_verbose (" zeroed malloc\n"); + + start = clock (); + + i = 0; + j = 0; + while (i < N_ITERATIONS) + { + to_free[j] = dbus_malloc0 (size); + _dbus_assert (to_free[j] != NULL); /* in a real app of course this is wrong */ + + ++j; + + if (j == FREE_ARRAY_SIZE) + { + j = 0; + while (j < FREE_ARRAY_SIZE) + { + dbus_free (to_free[j]); + ++j; + } + + j = 0; + } + + ++i; + } + + end = clock (); + + _dbus_verbose (" created/destroyed %d elements in %g seconds\n", + N_ITERATIONS, (end - start) / (double) CLOCKS_PER_SEC); + + _dbus_verbose (" zeroed mempools\n"); + + start = clock (); + + pool = _dbus_mem_pool_new (size, TRUE); + + i = 0; + j = 0; + while (i < N_ITERATIONS) + { + to_free[j] = _dbus_mem_pool_alloc (pool); + _dbus_assert (to_free[j] != NULL); /* in a real app of course this is wrong */ + + ++j; + + if (j == FREE_ARRAY_SIZE) + { + j = 0; + while (j < FREE_ARRAY_SIZE) + { + _dbus_mem_pool_dealloc (pool, to_free[j]); + ++j; + } + + j = 0; + } + + ++i; + } + + _dbus_mem_pool_free (pool); + + end = clock (); + + _dbus_verbose (" created/destroyed %d elements in %g seconds\n", + N_ITERATIONS, (end - start) / (double) CLOCKS_PER_SEC); +} + +/** + * @ingroup DBusMemPoolInternals + * Unit test for DBusMemPool + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_mem_pool_test (void) +{ + int i; + int element_sizes[] = { 4, 8, 16, 50, 124 }; + + i = 0; + while (i < _DBUS_N_ELEMENTS (element_sizes)) + { + time_for_size (element_sizes[i]); + ++i; + } + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-mempool.h b/dbus/dbus-mempool.h new file mode 100644 index 00000000..afe52472 --- /dev/null +++ b/dbus/dbus-mempool.h @@ -0,0 +1,44 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-mempool.h Memory pools + * + * Copyright (C) 2002 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_MEMPOOL_H +#define DBUS_MEMPOOL_H + +#include +#include +#include + +DBUS_BEGIN_DECLS + +typedef struct DBusMemPool DBusMemPool; + +DBusMemPool* _dbus_mem_pool_new (int element_size, + dbus_bool_t zero_elements); +void _dbus_mem_pool_free (DBusMemPool *pool); +void* _dbus_mem_pool_alloc (DBusMemPool *pool); +dbus_bool_t _dbus_mem_pool_dealloc (DBusMemPool *pool, + void *element); + +DBUS_END_DECLS + +#endif /* DBUS_MEMPOOL_H */ diff --git a/dbus/dbus-message-factory.c b/dbus/dbus-message-factory.c new file mode 100644 index 00000000..7bc539b5 --- /dev/null +++ b/dbus/dbus-message-factory.c @@ -0,0 +1,1228 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-message-factory.c Generator of valid and invalid message data for test suite + * + * Copyright (C) 2005 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#ifdef DBUS_BUILD_TESTS +#include "dbus-message-factory.h" +#include "dbus-message-private.h" +#include "dbus-test.h" +#include + +typedef enum + { + CHANGE_TYPE_ADJUST, + CHANGE_TYPE_ABSOLUTE + } ChangeType; + +#define BYTE_ORDER_OFFSET 0 +#define TYPE_OFFSET 1 +#define BODY_LENGTH_OFFSET 4 +#define FIELDS_ARRAY_LENGTH_OFFSET 12 + +static void +iter_recurse (DBusMessageDataIter *iter) +{ + iter->depth += 1; + _dbus_assert (iter->depth < _DBUS_MESSAGE_DATA_MAX_NESTING); + _dbus_assert (iter->sequence_nos[iter->depth] >= 0); +} + +static int +iter_get_sequence (DBusMessageDataIter *iter) +{ + _dbus_assert (iter->sequence_nos[iter->depth] >= 0); + return iter->sequence_nos[iter->depth]; +} + +static void +iter_set_sequence (DBusMessageDataIter *iter, + int sequence) +{ + _dbus_assert (sequence >= 0); + iter->sequence_nos[iter->depth] = sequence; +} + +static void +iter_unrecurse (DBusMessageDataIter *iter) +{ + iter->depth -= 1; + _dbus_assert (iter->depth >= 0); +} + +static void +iter_next (DBusMessageDataIter *iter) +{ + iter->sequence_nos[iter->depth] += 1; +} + +static dbus_bool_t +iter_first_in_series (DBusMessageDataIter *iter) +{ + int i; + + i = iter->depth; + while (i < _DBUS_MESSAGE_DATA_MAX_NESTING) + { + if (iter->sequence_nos[i] != 0) + return FALSE; + ++i; + } + return TRUE; +} + +typedef dbus_bool_t (* DBusInnerGeneratorFunc) (DBusMessageDataIter *iter, + DBusMessage **message_p); +typedef dbus_bool_t (* DBusMessageGeneratorFunc) (DBusMessageDataIter *iter, + DBusString *data, + DBusValidity *expected_validity); + +static void +set_reply_serial (DBusMessage *message) +{ + if (message == NULL) + _dbus_assert_not_reached ("oom"); + if (!dbus_message_set_reply_serial (message, 100)) + _dbus_assert_not_reached ("oom"); +} + +static dbus_bool_t +generate_trivial_inner (DBusMessageDataIter *iter, + DBusMessage **message_p) +{ + DBusMessage *message; + + switch (iter_get_sequence (iter)) + { + case 0: + message = dbus_message_new_method_call ("org.freedesktop.TextEditor", + "/foo/bar", + "org.freedesktop.DocumentFactory", + "Create"); + break; + case 1: + message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN); + set_reply_serial (message); + break; + case 2: + message = dbus_message_new_signal ("/foo/bar", + "org.freedesktop.DocumentFactory", + "Created"); + break; + case 3: + message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); + + if (!dbus_message_set_error_name (message, + "org.freedesktop.TestErrorName")) + _dbus_assert_not_reached ("oom"); + + { + DBusMessageIter iter; + const char *v_STRING = "This is an error"; + + dbus_message_iter_init_append (message, &iter); + if (!dbus_message_iter_append_basic (&iter, + DBUS_TYPE_STRING, + &v_STRING)) + _dbus_assert_not_reached ("oom"); + } + + set_reply_serial (message); + break; + default: + return FALSE; + } + + if (message == NULL) + _dbus_assert_not_reached ("oom"); + + *message_p = message; + + return TRUE; +} + +static dbus_bool_t +generate_many_bodies_inner (DBusMessageDataIter *iter, + DBusMessage **message_p) +{ + DBusMessage *message; + DBusString signature; + DBusString body; + + /* Keeping this small makes things go faster */ + message = dbus_message_new_method_call ("o.z.F", + "/", + "o.z.B", + "Nah"); + if (message == NULL) + _dbus_assert_not_reached ("oom"); + + set_reply_serial (message); + + if (!_dbus_string_init (&signature) || !_dbus_string_init (&body)) + _dbus_assert_not_reached ("oom"); + + if (dbus_internal_do_not_use_generate_bodies (iter_get_sequence (iter), + message->byte_order, + &signature, &body)) + { + const char *v_SIGNATURE; + + v_SIGNATURE = _dbus_string_get_const_data (&signature); + if (!_dbus_header_set_field_basic (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + DBUS_TYPE_SIGNATURE, + &v_SIGNATURE)) + _dbus_assert_not_reached ("oom"); + + if (!_dbus_string_move (&body, 0, &message->body, 0)) + _dbus_assert_not_reached ("oom"); + + _dbus_marshal_set_uint32 (&message->header.data, BODY_LENGTH_OFFSET, + _dbus_string_get_length (&message->body), + message->byte_order); + + *message_p = message; + } + else + { + dbus_message_unref (message); + *message_p = NULL; + } + + _dbus_string_free (&signature); + _dbus_string_free (&body); + + return *message_p != NULL; +} + +static void +generate_from_message (DBusString *data, + DBusValidity *expected_validity, + DBusMessage *message) +{ + dbus_message_set_serial (message, 1); + dbus_message_lock (message); + + *expected_validity = DBUS_VALID; + + /* move for efficiency, since we'll nuke the message anyway */ + if (!_dbus_string_move (&message->header.data, 0, + data, 0)) + _dbus_assert_not_reached ("oom"); + + if (!_dbus_string_copy (&message->body, 0, + data, _dbus_string_get_length (data))) + _dbus_assert_not_reached ("oom"); +} + +static dbus_bool_t +generate_outer (DBusMessageDataIter *iter, + DBusString *data, + DBusValidity *expected_validity, + DBusInnerGeneratorFunc func) +{ + DBusMessage *message; + + message = NULL; + if (!(*func)(iter, &message)) + return FALSE; + + iter_next (iter); + + _dbus_assert (message != NULL); + + generate_from_message (data, expected_validity, message); + + dbus_message_unref (message); + + return TRUE; +} + +static dbus_bool_t +generate_trivial (DBusMessageDataIter *iter, + DBusString *data, + DBusValidity *expected_validity) +{ + return generate_outer (iter, data, expected_validity, + generate_trivial_inner); +} + +static dbus_bool_t +generate_many_bodies (DBusMessageDataIter *iter, + DBusString *data, + DBusValidity *expected_validity) +{ + return generate_outer (iter, data, expected_validity, + generate_many_bodies_inner); +} + +static DBusMessage* +simple_method_call (void) +{ + DBusMessage *message; + /* Keeping this small makes stuff go faster */ + message = dbus_message_new_method_call ("o.b.Q", + "/f/b", + "o.b.Z", + "Fro"); + if (message == NULL) + _dbus_assert_not_reached ("oom"); + return message; +} + +static DBusMessage* +simple_signal (void) +{ + DBusMessage *message; + message = dbus_message_new_signal ("/f/b", + "o.b.Z", + "Fro"); + if (message == NULL) + _dbus_assert_not_reached ("oom"); + return message; +} + +static DBusMessage* +simple_method_return (void) +{ + DBusMessage *message; + message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN); + if (message == NULL) + _dbus_assert_not_reached ("oom"); + + set_reply_serial (message); + + return message; +} + +static DBusMessage* +simple_error (void) +{ + DBusMessage *message; + message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); + if (message == NULL) + _dbus_assert_not_reached ("oom"); + + if (!dbus_message_set_error_name (message, "foo.bar")) + _dbus_assert_not_reached ("oom"); + + set_reply_serial (message); + + return message; +} + +static dbus_bool_t +generate_special (DBusMessageDataIter *iter, + DBusString *data, + DBusValidity *expected_validity) +{ + int item_seq; + DBusMessage *message; + int pos; + dbus_int32_t v_INT32; + + _dbus_assert (_dbus_string_get_length (data) == 0); + + message = NULL; + pos = -1; + v_INT32 = 42; + item_seq = iter_get_sequence (iter); + + if (item_seq == 0) + { + message = simple_method_call (); + if (!dbus_message_append_args (message, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("oom"); + + _dbus_header_get_field_raw (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + NULL, &pos); + generate_from_message (data, expected_validity, message); + + /* set an invalid typecode */ + _dbus_string_set_byte (data, pos + 1, '$'); + + *expected_validity = DBUS_INVALID_UNKNOWN_TYPECODE; + } + else if (item_seq == 1) + { + char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH+2]; + const char *v_STRING; + int i; + + message = simple_method_call (); + if (!dbus_message_append_args (message, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("oom"); + + i = 0; + while (i < (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1)) + { + long_sig[i] = DBUS_TYPE_ARRAY; + ++i; + } + long_sig[i] = DBUS_TYPE_INVALID; + + v_STRING = long_sig; + if (!_dbus_header_set_field_basic (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + DBUS_TYPE_SIGNATURE, + &v_STRING)) + _dbus_assert_not_reached ("oom"); + + _dbus_header_get_field_raw (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + NULL, &pos); + generate_from_message (data, expected_validity, message); + + *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION; + } + else if (item_seq == 2) + { + char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2+4]; + const char *v_STRING; + int i; + + message = simple_method_call (); + if (!dbus_message_append_args (message, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("oom"); + + i = 0; + while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1)) + { + long_sig[i] = DBUS_STRUCT_BEGIN_CHAR; + ++i; + } + + long_sig[i] = DBUS_TYPE_INT32; + ++i; + + while (i < (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2 + 3)) + { + long_sig[i] = DBUS_STRUCT_END_CHAR; + ++i; + } + long_sig[i] = DBUS_TYPE_INVALID; + + v_STRING = long_sig; + if (!_dbus_header_set_field_basic (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + DBUS_TYPE_SIGNATURE, + &v_STRING)) + _dbus_assert_not_reached ("oom"); + + _dbus_header_get_field_raw (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + NULL, &pos); + generate_from_message (data, expected_validity, message); + + *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION; + } + else if (item_seq == 3) + { + message = simple_method_call (); + if (!dbus_message_append_args (message, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("oom"); + + _dbus_header_get_field_raw (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + NULL, &pos); + generate_from_message (data, expected_validity, message); + + _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR); + + *expected_validity = DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED; + } + else if (item_seq == 4) + { + message = simple_method_call (); + if (!dbus_message_append_args (message, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("oom"); + + _dbus_header_get_field_raw (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + NULL, &pos); + generate_from_message (data, expected_validity, message); + + _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_END_CHAR); + + *expected_validity = DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED; + } + else if (item_seq == 5) + { + message = simple_method_call (); + if (!dbus_message_append_args (message, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("oom"); + + _dbus_header_get_field_raw (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + NULL, &pos); + generate_from_message (data, expected_validity, message); + + _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR); + _dbus_string_set_byte (data, pos + 2, DBUS_STRUCT_END_CHAR); + + *expected_validity = DBUS_INVALID_STRUCT_HAS_NO_FIELDS; + } + else if (item_seq == 6) + { + message = simple_method_call (); + generate_from_message (data, expected_validity, message); + + _dbus_string_set_byte (data, TYPE_OFFSET, DBUS_MESSAGE_TYPE_INVALID); + + *expected_validity = DBUS_INVALID_BAD_MESSAGE_TYPE; + } + else if (item_seq == 7) + { + /* Messages of unknown type are considered valid */ + message = simple_method_call (); + generate_from_message (data, expected_validity, message); + + _dbus_string_set_byte (data, TYPE_OFFSET, 100); + + *expected_validity = DBUS_VALID; + } + else if (item_seq == 8) + { + message = simple_method_call (); + generate_from_message (data, expected_validity, message); + + _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET, + DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4, + message->byte_order); + _dbus_marshal_set_uint32 (data, FIELDS_ARRAY_LENGTH_OFFSET, + DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4, + message->byte_order); + *expected_validity = DBUS_INVALID_MESSAGE_TOO_LONG; + } + else if (item_seq == 9) + { + const char *v_STRING = "not a valid bus name"; + message = simple_method_call (); + + if (!_dbus_header_set_field_basic (&message->header, + DBUS_HEADER_FIELD_SENDER, + DBUS_TYPE_STRING, &v_STRING)) + _dbus_assert_not_reached ("oom"); + + generate_from_message (data, expected_validity, message); + + *expected_validity = DBUS_INVALID_BAD_SENDER; + } + else if (item_seq == 10) + { + message = simple_method_call (); + + if (!dbus_message_set_interface (message, DBUS_INTERFACE_LOCAL)) + _dbus_assert_not_reached ("oom"); + + generate_from_message (data, expected_validity, message); + + *expected_validity = DBUS_INVALID_USES_LOCAL_INTERFACE; + } + else if (item_seq == 11) + { + message = simple_method_call (); + + if (!dbus_message_set_path (message, DBUS_PATH_LOCAL)) + _dbus_assert_not_reached ("oom"); + + generate_from_message (data, expected_validity, message); + + *expected_validity = DBUS_INVALID_USES_LOCAL_PATH; + } + else if (item_seq == 12) + { + /* Method calls don't have to have interface */ + message = simple_method_call (); + + if (!dbus_message_set_interface (message, NULL)) + _dbus_assert_not_reached ("oom"); + + generate_from_message (data, expected_validity, message); + + *expected_validity = DBUS_VALID; + } + else if (item_seq == 13) + { + /* Signals require an interface */ + message = simple_signal (); + + if (!dbus_message_set_interface (message, NULL)) + _dbus_assert_not_reached ("oom"); + + generate_from_message (data, expected_validity, message); + + *expected_validity = DBUS_INVALID_MISSING_INTERFACE; + } + else if (item_seq == 14) + { + message = simple_method_return (); + + if (!_dbus_header_delete_field (&message->header, DBUS_HEADER_FIELD_REPLY_SERIAL)) + _dbus_assert_not_reached ("oom"); + + generate_from_message (data, expected_validity, message); + + *expected_validity = DBUS_INVALID_MISSING_REPLY_SERIAL; + } + else if (item_seq == 15) + { + message = simple_error (); + + if (!dbus_message_set_error_name (message, NULL)) + _dbus_assert_not_reached ("oom"); + + generate_from_message (data, expected_validity, message); + + *expected_validity = DBUS_INVALID_MISSING_ERROR_NAME; + } + else if (item_seq == 16) + { + char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*4+10]; + const char *v_STRING; + int i; + int n_begins; + + message = simple_method_call (); + if (!dbus_message_append_args (message, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("oom"); + + i = 0; + while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*3 + 3)) + { + long_sig[i] = DBUS_TYPE_ARRAY; + ++i; + long_sig[i] = DBUS_DICT_ENTRY_BEGIN_CHAR; + ++i; + long_sig[i] = DBUS_TYPE_INT32; + ++i; + } + n_begins = i / 3; + + long_sig[i] = DBUS_TYPE_INT32; + ++i; + + while (n_begins > 0) + { + long_sig[i] = DBUS_DICT_ENTRY_END_CHAR; + ++i; + n_begins -= 1; + } + long_sig[i] = DBUS_TYPE_INVALID; + + v_STRING = long_sig; + if (!_dbus_header_set_field_basic (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + DBUS_TYPE_SIGNATURE, + &v_STRING)) + _dbus_assert_not_reached ("oom"); + + _dbus_header_get_field_raw (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + NULL, &pos); + generate_from_message (data, expected_validity, message); + + *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION; + } + else if (item_seq == 17) + { + message = simple_method_call (); + if (!dbus_message_append_args (message, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("oom"); + + _dbus_header_get_field_raw (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + NULL, &pos); + generate_from_message (data, expected_validity, message); + + _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY); + _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR); + + *expected_validity = DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED; + } + else if (item_seq == 18) + { + message = simple_method_call (); + if (!dbus_message_append_args (message, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("oom"); + + _dbus_header_get_field_raw (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + NULL, &pos); + generate_from_message (data, expected_validity, message); + + _dbus_string_set_byte (data, pos + 1, DBUS_DICT_ENTRY_END_CHAR); + + *expected_validity = DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED; + } + else if (item_seq == 19) + { + message = simple_method_call (); + if (!dbus_message_append_args (message, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_INVALID)) + _dbus_assert_not_reached ("oom"); + + _dbus_header_get_field_raw (&message->header, + DBUS_HEADER_FIELD_SIGNATURE, + NULL, &pos); + generate_from_message (data, expected_validity, message); + + _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY); + _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR); + _dbus_string_set_byte (data, pos + 3, DBUS_DICT_ENTRY_END_CHAR); + + *expected_validity = DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS; + } + else + { + return FALSE; + } + + if (message) + dbus_message_unref (message); + + iter_next (iter); + return TRUE; +} + +static dbus_bool_t +generate_wrong_length (DBusMessageDataIter *iter, + DBusString *data, + DBusValidity *expected_validity) +{ + int lengths[] = { -42, -17, -16, -15, -9, -8, -7, -6, -5, -4, -3, -2, -1, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 30 }; + int adjust; + int len_seq; + + restart: + len_seq = iter_get_sequence (iter); + if (len_seq == _DBUS_N_ELEMENTS (lengths)) + return FALSE; + + _dbus_assert (len_seq < _DBUS_N_ELEMENTS (lengths)); + + iter_recurse (iter); + if (!generate_many_bodies (iter, data, expected_validity)) + { + iter_set_sequence (iter, 0); /* reset to first body */ + iter_unrecurse (iter); + iter_next (iter); /* next length adjustment */ + goto restart; + } + iter_unrecurse (iter); + + adjust = lengths[len_seq]; + + if (adjust < 0) + { + if ((_dbus_string_get_length (data) + adjust) < DBUS_MINIMUM_HEADER_SIZE) + _dbus_string_set_length (data, DBUS_MINIMUM_HEADER_SIZE); + else + _dbus_string_shorten (data, - adjust); + *expected_validity = DBUS_INVALID_FOR_UNKNOWN_REASON; + } + else + { + if (!_dbus_string_lengthen (data, adjust)) + _dbus_assert_not_reached ("oom"); + *expected_validity = DBUS_INVALID_TOO_MUCH_DATA; + } + + /* Fixup lengths */ + { + int old_body_len; + int new_body_len; + int byte_order; + + _dbus_assert (_dbus_string_get_length (data) >= DBUS_MINIMUM_HEADER_SIZE); + + byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET); + old_body_len = _dbus_marshal_read_uint32 (data, + BODY_LENGTH_OFFSET, + byte_order, + NULL); + _dbus_assert (old_body_len < _dbus_string_get_length (data)); + new_body_len = old_body_len + adjust; + if (new_body_len < 0) + { + new_body_len = 0; + /* we just munged the header, and aren't sure how */ + *expected_validity = DBUS_VALIDITY_UNKNOWN; + } + + _dbus_verbose ("changing body len from %u to %u by adjust %d\n", + old_body_len, new_body_len, adjust); + + _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET, + new_body_len, + byte_order); + } + + return TRUE; +} + +static dbus_bool_t +generate_byte_changed (DBusMessageDataIter *iter, + DBusString *data, + DBusValidity *expected_validity) +{ + int byte_seq; + int v_BYTE; + + /* This is a little convoluted to make the bodies the + * outer loop and each byte of each body the inner + * loop + */ + + restart: + if (!generate_many_bodies (iter, data, expected_validity)) + return FALSE; + + iter_recurse (iter); + byte_seq = iter_get_sequence (iter); + iter_next (iter); + iter_unrecurse (iter); + + if (byte_seq == _dbus_string_get_length (data)) + { + _dbus_string_set_length (data, 0); + /* reset byte count */ + iter_recurse (iter); + iter_set_sequence (iter, 0); + iter_unrecurse (iter); + goto restart; + } + else + { + /* Undo the "next" in generate_many_bodies */ + iter_set_sequence (iter, iter_get_sequence (iter) - 1); + } + + _dbus_assert (byte_seq < _dbus_string_get_length (data)); + v_BYTE = _dbus_string_get_byte (data, byte_seq); + v_BYTE += byte_seq; /* arbitrary but deterministic change to the byte */ + _dbus_string_set_byte (data, byte_seq, v_BYTE); + *expected_validity = DBUS_VALIDITY_UNKNOWN; + + return TRUE; +} + +static dbus_bool_t +find_next_typecode (DBusMessageDataIter *iter, + DBusString *data, + DBusValidity *expected_validity) +{ + int body_seq; + int byte_seq; + int base_depth; + + base_depth = iter->depth; + + restart: + _dbus_assert (iter->depth == (base_depth + 0)); + _dbus_string_set_length (data, 0); + + body_seq = iter_get_sequence (iter); + + if (!generate_many_bodies (iter, data, expected_validity)) + return FALSE; + /* Undo the "next" in generate_many_bodies */ + iter_set_sequence (iter, body_seq); + + iter_recurse (iter); + while (TRUE) + { + _dbus_assert (iter->depth == (base_depth + 1)); + + byte_seq = iter_get_sequence (iter); + + _dbus_assert (byte_seq <= _dbus_string_get_length (data)); + + if (byte_seq == _dbus_string_get_length (data)) + { + /* reset byte count */ + iter_set_sequence (iter, 0); + iter_unrecurse (iter); + _dbus_assert (iter->depth == (base_depth + 0)); + iter_next (iter); /* go to the next body */ + goto restart; + } + + _dbus_assert (byte_seq < _dbus_string_get_length (data)); + + if (_dbus_type_is_valid (_dbus_string_get_byte (data, byte_seq))) + break; + else + iter_next (iter); + } + + _dbus_assert (byte_seq == iter_get_sequence (iter)); + _dbus_assert (byte_seq < _dbus_string_get_length (data)); + + iter_unrecurse (iter); + + _dbus_assert (iter->depth == (base_depth + 0)); + + return TRUE; +} + +static const int typecodes[] = { + DBUS_TYPE_INVALID, + DBUS_TYPE_BYTE, + DBUS_TYPE_BOOLEAN, + DBUS_TYPE_INT16, + DBUS_TYPE_UINT16, + DBUS_TYPE_INT32, + DBUS_TYPE_UINT32, + DBUS_TYPE_INT64, + DBUS_TYPE_UINT64, + DBUS_TYPE_DOUBLE, + DBUS_TYPE_STRING, + DBUS_TYPE_OBJECT_PATH, + DBUS_TYPE_SIGNATURE, + DBUS_TYPE_ARRAY, + DBUS_TYPE_VARIANT, + DBUS_STRUCT_BEGIN_CHAR, + DBUS_STRUCT_END_CHAR, + DBUS_DICT_ENTRY_BEGIN_CHAR, + DBUS_DICT_ENTRY_END_CHAR, + 255 /* random invalid typecode */ +}; + +static dbus_bool_t +generate_typecode_changed (DBusMessageDataIter *iter, + DBusString *data, + DBusValidity *expected_validity) +{ + int byte_seq; + int typecode_seq; + int base_depth; + + base_depth = iter->depth; + + restart: + _dbus_assert (iter->depth == (base_depth + 0)); + _dbus_string_set_length (data, 0); + + if (!find_next_typecode (iter, data, expected_validity)) + return FALSE; + + iter_recurse (iter); + byte_seq = iter_get_sequence (iter); + + _dbus_assert (byte_seq < _dbus_string_get_length (data)); + + iter_recurse (iter); + typecode_seq = iter_get_sequence (iter); + iter_next (iter); + + _dbus_assert (typecode_seq <= _DBUS_N_ELEMENTS (typecodes)); + + if (typecode_seq == _DBUS_N_ELEMENTS (typecodes)) + { + _dbus_assert (iter->depth == (base_depth + 2)); + iter_set_sequence (iter, 0); /* reset typecode sequence */ + iter_unrecurse (iter); + _dbus_assert (iter->depth == (base_depth + 1)); + iter_next (iter); /* go to the next byte_seq */ + iter_unrecurse (iter); + _dbus_assert (iter->depth == (base_depth + 0)); + goto restart; + } + + _dbus_assert (iter->depth == (base_depth + 2)); + iter_unrecurse (iter); + _dbus_assert (iter->depth == (base_depth + 1)); + iter_unrecurse (iter); + _dbus_assert (iter->depth == (base_depth + 0)); + +#if 0 + printf ("Changing byte %d in message %d to %c\n", + byte_seq, iter_get_sequence (iter), typecodes[typecode_seq]); +#endif + + _dbus_string_set_byte (data, byte_seq, typecodes[typecode_seq]); + *expected_validity = DBUS_VALIDITY_UNKNOWN; + return TRUE; +} + +typedef struct +{ + ChangeType type; + dbus_uint32_t value; /* cast to signed for adjusts */ +} UIntChange; + +static const UIntChange uint32_changes[] = { + { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -1 }, + { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -2 }, + { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -3 }, + { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 1 }, + { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 2 }, + { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 3 }, + { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX }, + { CHANGE_TYPE_ABSOLUTE, 0 }, + { CHANGE_TYPE_ABSOLUTE, 1 }, + { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 1 }, + { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 5 } +}; + +static dbus_bool_t +generate_uint32_changed (DBusMessageDataIter *iter, + DBusString *data, + DBusValidity *expected_validity) +{ + int body_seq; + int byte_seq; + int change_seq; + dbus_uint32_t v_UINT32; + int byte_order; + const UIntChange *change; + int base_depth; + + /* Outer loop is each body, next loop is each change, + * inner loop is each change location + */ + + base_depth = iter->depth; + + next_body: + _dbus_assert (iter->depth == (base_depth + 0)); + _dbus_string_set_length (data, 0); + body_seq = iter_get_sequence (iter); + + if (!generate_many_bodies (iter, data, expected_validity)) + return FALSE; + + _dbus_assert (iter->depth == (base_depth + 0)); + + iter_set_sequence (iter, body_seq); /* undo the "next" from generate_many_bodies */ + iter_recurse (iter); + next_change: + _dbus_assert (iter->depth == (base_depth + 1)); + change_seq = iter_get_sequence (iter); + + if (change_seq == _DBUS_N_ELEMENTS (uint32_changes)) + { + /* Reset change count */ + iter_set_sequence (iter, 0); + iter_unrecurse (iter); + iter_next (iter); + goto next_body; + } + + _dbus_assert (iter->depth == (base_depth + 1)); + + iter_recurse (iter); + _dbus_assert (iter->depth == (base_depth + 2)); + byte_seq = iter_get_sequence (iter); + /* skip 4 bytes at a time */ + iter_next (iter); + iter_next (iter); + iter_next (iter); + iter_next (iter); + iter_unrecurse (iter); + + _dbus_assert (_DBUS_ALIGN_VALUE (byte_seq, 4) == (unsigned) byte_seq); + if (byte_seq >= (_dbus_string_get_length (data) - 4)) + { + /* reset byte count */ + _dbus_assert (iter->depth == (base_depth + 1)); + iter_recurse (iter); + _dbus_assert (iter->depth == (base_depth + 2)); + iter_set_sequence (iter, 0); + iter_unrecurse (iter); + _dbus_assert (iter->depth == (base_depth + 1)); + iter_next (iter); + goto next_change; + } + + _dbus_assert (byte_seq <= (_dbus_string_get_length (data) - 4)); + + byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET); + + v_UINT32 = _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL); + + change = &uint32_changes[change_seq]; + + if (change->type == CHANGE_TYPE_ADJUST) + { + v_UINT32 += (int) change->value; + } + else + { + v_UINT32 = change->value; + } + +#if 0 + printf ("body %d change %d pos %d ", + body_seq, change_seq, byte_seq); + + if (change->type == CHANGE_TYPE_ADJUST) + printf ("adjust by %d", (int) change->value); + else + printf ("set to %u", change->value); + + printf (" \t%u -> %u\n", + _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL), + v_UINT32); +#endif + + _dbus_marshal_set_uint32 (data, byte_seq, v_UINT32, byte_order); + *expected_validity = DBUS_VALIDITY_UNKNOWN; + + _dbus_assert (iter->depth == (base_depth + 1)); + iter_unrecurse (iter); + _dbus_assert (iter->depth == (base_depth + 0)); + + return TRUE; +} + +typedef struct +{ + const char *name; + DBusMessageGeneratorFunc func; +} DBusMessageGenerator; + +static const DBusMessageGenerator generators[] = { + { "trivial example of each message type", generate_trivial }, + { "assorted arguments", generate_many_bodies }, + { "assorted special cases", generate_special }, + { "each uint32 modified", generate_uint32_changed }, + { "wrong body lengths", generate_wrong_length }, + { "each byte modified", generate_byte_changed }, +#if 0 + /* This is really expensive and doesn't add too much coverage */ + { "change each typecode", generate_typecode_changed } +#endif +}; + +void +_dbus_message_data_free (DBusMessageData *data) +{ + _dbus_string_free (&data->data); +} + +void +_dbus_message_data_iter_init (DBusMessageDataIter *iter) +{ + int i; + + iter->depth = 0; + i = 0; + while (i < _DBUS_MESSAGE_DATA_MAX_NESTING) + { + iter->sequence_nos[i] = 0; + ++i; + } + iter->count = 0; +} + +dbus_bool_t +_dbus_message_data_iter_get_and_next (DBusMessageDataIter *iter, + DBusMessageData *data) +{ + DBusMessageGeneratorFunc func; + int generator; + + restart: + generator = iter_get_sequence (iter); + + if (generator == _DBUS_N_ELEMENTS (generators)) + return FALSE; + + iter_recurse (iter); + + if (iter_first_in_series (iter)) + { + printf (" testing message loading: %s ", generators[generator].name); + fflush (stdout); + } + + func = generators[generator].func; + + if (!_dbus_string_init (&data->data)) + _dbus_assert_not_reached ("oom"); + + if ((*func)(iter, &data->data, &data->expected_validity)) + ; + else + { + iter_set_sequence (iter, 0); + iter_unrecurse (iter); + iter_next (iter); /* next generator */ + _dbus_string_free (&data->data); + printf ("%d test loads cumulative\n", iter->count); + goto restart; + } + iter_unrecurse (iter); + + iter->count += 1; + return TRUE; +} + +#endif /* !DOXYGEN_SHOULD_SKIP_THIS */ + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-message-factory.h b/dbus/dbus-message-factory.h new file mode 100644 index 00000000..b0747504 --- /dev/null +++ b/dbus/dbus-message-factory.h @@ -0,0 +1,61 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-message-factory.h Generator of valid and invalid message data for test suite + * + * Copyright (C) 2005 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_MESSAGE_FACTORY_H +#define DBUS_MESSAGE_FACTORY_H + +#ifdef DBUS_BUILD_TESTS + +#include +#include +#include + +DBUS_BEGIN_DECLS + +typedef struct +{ + DBusValidity expected_validity; + + DBusString data; + +} DBusMessageData; + +#define _DBUS_MESSAGE_DATA_MAX_NESTING 10 +typedef struct +{ + int sequence_nos[_DBUS_MESSAGE_DATA_MAX_NESTING]; + int depth; + int count; +} DBusMessageDataIter; + +void _dbus_message_data_free (DBusMessageData *data); +void _dbus_message_data_iter_init (DBusMessageDataIter *iter); +dbus_bool_t _dbus_message_data_iter_get_and_next (DBusMessageDataIter *iter, + DBusMessageData *data); + + +DBUS_END_DECLS + +#endif /* DBUS_BUILD_TESTS */ + +#endif /* DBUS_MESSAGE_FACTORY_H */ diff --git a/dbus/dbus-message-internal.h b/dbus/dbus-message-internal.h new file mode 100644 index 00000000..0134f8db --- /dev/null +++ b/dbus/dbus-message-internal.h @@ -0,0 +1,74 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-message-internal.h DBusMessage object internal interfaces + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_MESSAGE_INTERNAL_H +#define DBUS_MESSAGE_INTERNAL_H + +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +typedef struct DBusMessageLoader DBusMessageLoader; + +void _dbus_message_get_network_data (DBusMessage *message, + const DBusString **header, + const DBusString **body); + +void _dbus_message_lock (DBusMessage *message); +void _dbus_message_unlock (DBusMessage *message); +dbus_bool_t _dbus_message_add_size_counter (DBusMessage *message, + DBusCounter *counter); +void _dbus_message_add_size_counter_link (DBusMessage *message, + DBusList *link); +void _dbus_message_remove_size_counter (DBusMessage *message, + DBusCounter *counter, + DBusList **link_return); + +DBusMessageLoader* _dbus_message_loader_new (void); +DBusMessageLoader* _dbus_message_loader_ref (DBusMessageLoader *loader); +void _dbus_message_loader_unref (DBusMessageLoader *loader); + +void _dbus_message_loader_get_buffer (DBusMessageLoader *loader, + DBusString **buffer); +void _dbus_message_loader_return_buffer (DBusMessageLoader *loader, + DBusString *buffer, + int bytes_read); +dbus_bool_t _dbus_message_loader_queue_messages (DBusMessageLoader *loader); +DBusMessage* _dbus_message_loader_peek_message (DBusMessageLoader *loader); +DBusMessage* _dbus_message_loader_pop_message (DBusMessageLoader *loader); +DBusList* _dbus_message_loader_pop_message_link (DBusMessageLoader *loader); +void _dbus_message_loader_putback_message_link (DBusMessageLoader *loader, + DBusList *link); + +dbus_bool_t _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader); +DBusValidity _dbus_message_loader_get_corruption_reason (DBusMessageLoader *loader); + +void _dbus_message_loader_set_max_message_size (DBusMessageLoader *loader, + long size); +long _dbus_message_loader_get_max_message_size (DBusMessageLoader *loader); + +DBUS_END_DECLS + +#endif /* DBUS_MESSAGE_INTERNAL_H */ diff --git a/dbus/dbus-message-private.h b/dbus/dbus-message-private.h new file mode 100644 index 00000000..c8b2ba63 --- /dev/null +++ b/dbus/dbus-message-private.h @@ -0,0 +1,125 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-message-private.h header shared between dbus-message.c and dbus-message-util.c + * + * Copyright (C) 2005 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_MESSAGE_PRIVATE_H +#define DBUS_MESSAGE_PRIVATE_H + +#include +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusMessageInternals + * @{ + */ + +/** + * @typedef DBusMessageLoader + * + * The DBusMessageLoader object encapsulates the process of converting + * a byte stream into a series of DBusMessage. It buffers the incoming + * bytes as efficiently as possible, and generates a queue of + * messages. DBusMessageLoader is typically used as part of a + * DBusTransport implementation. The DBusTransport then hands off + * the loaded messages to a DBusConnection, making the messages + * visible to the application. + * + * @todo write tests for break-loader that a) randomly delete header + * fields and b) set string fields to zero-length and other funky + * values. + * + */ + +/** + * Implementation details of DBusMessageLoader. + * All members are private. + */ +struct DBusMessageLoader +{ + int refcount; /**< Reference count. */ + + DBusString data; /**< Buffered data */ + + DBusList *messages; /**< Complete messages. */ + + long max_message_size; /**< Maximum size of a message */ + + unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */ + + unsigned int corrupted : 1; /**< We got broken data, and are no longer working */ + + DBusValidity corruption_reason; /**< why we were corrupted */ +}; + + +/** How many bits are in the changed_stamp used to validate iterators */ +#define CHANGED_STAMP_BITS 21 + +/** + * @brief Internals of DBusMessage + * + * Object representing a message received from or to be sent to + * another application. This is an opaque object, all members + * are private. + */ +struct DBusMessage +{ + DBusAtomic refcount; /**< Reference count */ + + DBusHeader header; /**< Header network data and associated cache */ + + DBusString body; /**< Body network data. */ + + char byte_order; /**< Message byte order. */ + + unsigned int locked : 1; /**< Message being sent, no modifications allowed. */ + +#ifndef DBUS_DISABLE_CHECKS + unsigned int in_cache : 1; /**< Has been "freed" since it's in the cache (this is a debug feature) */ +#endif + + DBusList *size_counters; /**< 0-N DBusCounter used to track message size. */ + long size_counter_delta; /**< Size we incremented the size counters by. */ + + dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; /**< Incremented when iterators are invalidated. */ + + DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ + +#ifndef DBUS_DISABLE_CHECKS + int generation; /**< _dbus_current_generation when message was created */ +#endif +}; + +dbus_bool_t _dbus_message_iter_get_args_valist (DBusMessageIter *iter, + DBusError *error, + int first_arg_type, + va_list var_args); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_MESSAGE_H */ diff --git a/dbus/dbus-message-util.c b/dbus/dbus-message-util.c new file mode 100644 index 00000000..84471a50 --- /dev/null +++ b/dbus/dbus-message-util.c @@ -0,0 +1,1349 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-message-util.c Would be in dbus-message.c, but only used by bus/tests + * + * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. + * Copyright (C) 2002, 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-test.h" +#include "dbus-message-private.h" +#include "dbus-marshal-recursive.h" +#include "dbus-string.h" + +/** + * @addtogroup DBusMessage + * @{ + */ + +#ifdef DBUS_BUILD_TESTS +/** + * Reads arguments from a message iterator given a variable argument + * list. Only arguments of basic type and arrays of fixed-length + * basic type may be read with this function. See + * dbus_message_get_args() for more details. + * + * @param iter the message iterator + * @param error error to be filled in on failure + * @param first_arg_type the first argument type + * @param ... location for first argument value, then list of type-location pairs + * @returns #FALSE if the error was set + */ +static dbus_bool_t +dbus_message_iter_get_args (DBusMessageIter *iter, + DBusError *error, + int first_arg_type, + ...) +{ + dbus_bool_t retval; + va_list var_args; + + _dbus_return_val_if_fail (iter != NULL, FALSE); + _dbus_return_val_if_error_is_set (error, FALSE); + + va_start (var_args, first_arg_type); + retval = _dbus_message_iter_get_args_valist (iter, error, first_arg_type, var_args); + va_end (var_args); + + return retval; +} +#endif /* DBUS_BUILD_TESTS */ + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include "dbus-message-factory.h" +#include +#include + +static int validities_seen[DBUS_VALIDITY_LAST + _DBUS_NEGATIVE_VALIDITY_COUNT]; + +static void +reset_validities_seen (void) +{ + int i; + i = 0; + while (i < _DBUS_N_ELEMENTS (validities_seen)) + { + validities_seen[i] = 0; + ++i; + } +} + +static void +record_validity_seen (DBusValidity validity) +{ + validities_seen[validity + _DBUS_NEGATIVE_VALIDITY_COUNT] += 1; +} + +static void +print_validities_seen (dbus_bool_t not_seen) +{ + int i; + i = 0; + while (i < _DBUS_N_ELEMENTS (validities_seen)) + { + if ((i - _DBUS_NEGATIVE_VALIDITY_COUNT) == DBUS_VALIDITY_UNKNOWN || + (i - _DBUS_NEGATIVE_VALIDITY_COUNT) == DBUS_INVALID_FOR_UNKNOWN_REASON) + ; + else if ((not_seen && validities_seen[i] == 0) || + (!not_seen && validities_seen[i] > 0)) + printf ("validity %3d seen %d times\n", + i - _DBUS_NEGATIVE_VALIDITY_COUNT, + validities_seen[i]); + ++i; + } +} + +static void +check_memleaks (void) +{ + dbus_shutdown (); + + if (_dbus_get_malloc_blocks_outstanding () != 0) + { + _dbus_warn ("%d dbus_malloc blocks were not freed in %s\n", + _dbus_get_malloc_blocks_outstanding (), __FILE__); + _dbus_assert_not_reached ("memleaks"); + } +} + +static dbus_bool_t +check_have_valid_message (DBusMessageLoader *loader) +{ + DBusMessage *message; + dbus_bool_t retval; + + message = NULL; + retval = FALSE; + + if (_dbus_message_loader_get_is_corrupted (loader)) + { + _dbus_warn ("loader corrupted on message that was expected to be valid; invalid reason %d\n", + loader->corruption_reason); + goto failed; + } + + message = _dbus_message_loader_pop_message (loader); + if (message == NULL) + { + _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n"); + goto failed; + } + + if (_dbus_string_get_length (&loader->data) > 0) + { + _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n"); + goto failed; + } + +#if 0 + /* FIXME */ + /* Verify that we're able to properly deal with the message. + * For example, this would detect improper handling of messages + * in nonstandard byte order. + */ + if (!check_message_handling (message)) + goto failed; +#endif + + record_validity_seen (DBUS_VALID); + + retval = TRUE; + + failed: + if (message) + dbus_message_unref (message); + + return retval; +} + +static dbus_bool_t +check_invalid_message (DBusMessageLoader *loader, + DBusValidity expected_validity) +{ + dbus_bool_t retval; + + retval = FALSE; + + if (!_dbus_message_loader_get_is_corrupted (loader)) + { + _dbus_warn ("loader not corrupted on message that was expected to be invalid\n"); + goto failed; + } + + record_validity_seen (loader->corruption_reason); + + if (expected_validity != DBUS_INVALID_FOR_UNKNOWN_REASON && + loader->corruption_reason != expected_validity) + { + _dbus_warn ("expected message to be corrupted for reason %d and was corrupted for %d instead\n", + expected_validity, loader->corruption_reason); + goto failed; + } + + retval = TRUE; + + failed: + return retval; +} + +static dbus_bool_t +check_incomplete_message (DBusMessageLoader *loader) +{ + DBusMessage *message; + dbus_bool_t retval; + + message = NULL; + retval = FALSE; + + if (_dbus_message_loader_get_is_corrupted (loader)) + { + _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete), corruption reason %d\n", + loader->corruption_reason); + goto failed; + } + + message = _dbus_message_loader_pop_message (loader); + if (message != NULL) + { + _dbus_warn ("loaded message that was expected to be incomplete\n"); + goto failed; + } + + record_validity_seen (DBUS_VALID_BUT_INCOMPLETE); + retval = TRUE; + + failed: + if (message) + dbus_message_unref (message); + return retval; +} + +static dbus_bool_t +check_loader_results (DBusMessageLoader *loader, + DBusValidity expected_validity) +{ + if (!_dbus_message_loader_queue_messages (loader)) + _dbus_assert_not_reached ("no memory to queue messages"); + + if (expected_validity == DBUS_VALID) + return check_have_valid_message (loader); + else if (expected_validity == DBUS_VALID_BUT_INCOMPLETE) + return check_incomplete_message (loader); + else if (expected_validity == DBUS_VALIDITY_UNKNOWN) + { + /* here we just know we didn't segfault and that was the + * only test. Also, we record that we got coverage + * for the validity reason. + */ + if (_dbus_message_loader_get_is_corrupted (loader)) + record_validity_seen (loader->corruption_reason); + + return TRUE; + } + else + return check_invalid_message (loader, expected_validity); +} + +/** + * Loads the message in the given message file. + * + * @param filename filename to load + * @param data string to load message into + * @returns #TRUE if the message was loaded + */ +dbus_bool_t +dbus_internal_do_not_use_load_message_file (const DBusString *filename, + DBusString *data) +{ + dbus_bool_t retval; + DBusError error = DBUS_ERROR_INIT; + + retval = FALSE; + + _dbus_verbose ("Loading raw %s\n", _dbus_string_get_const_data (filename)); + if (!_dbus_file_get_contents (data, filename, &error)) + { + _dbus_warn ("Could not load message file %s: %s\n", + _dbus_string_get_const_data (filename), + error.message); + dbus_error_free (&error); + goto failed; + } + + retval = TRUE; + + failed: + + return retval; +} + +/** + * Tries loading the message in the given message file + * and verifies that DBusMessageLoader can handle it. + * + * @param filename filename to load + * @param expected_validity what the message has to be like to return #TRUE + * @returns #TRUE if the message has the expected validity + */ +dbus_bool_t +dbus_internal_do_not_use_try_message_file (const DBusString *filename, + DBusValidity expected_validity) +{ + DBusString data; + dbus_bool_t retval; + + retval = FALSE; + + if (!_dbus_string_init (&data)) + _dbus_assert_not_reached ("could not allocate string\n"); + + if (!dbus_internal_do_not_use_load_message_file (filename, &data)) + goto failed; + + retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity); + + failed: + + if (!retval) + { + if (_dbus_string_get_length (&data) > 0) + _dbus_verbose_bytes_of_string (&data, 0, + _dbus_string_get_length (&data)); + + _dbus_warn ("Failed message loader test on %s\n", + _dbus_string_get_const_data (filename)); + } + + _dbus_string_free (&data); + + return retval; +} + +/** + * Tries loading the given message data. + * + * + * @param data the message data + * @param expected_validity what the message has to be like to return #TRUE + * @returns #TRUE if the message has the expected validity + */ +dbus_bool_t +dbus_internal_do_not_use_try_message_data (const DBusString *data, + DBusValidity expected_validity) +{ + DBusMessageLoader *loader; + dbus_bool_t retval; + int len; + int i; + + loader = NULL; + retval = FALSE; + + /* Write the data one byte at a time */ + + loader = _dbus_message_loader_new (); + + /* check some trivial loader functions */ + _dbus_message_loader_ref (loader); + _dbus_message_loader_unref (loader); + _dbus_message_loader_get_max_message_size (loader); + + len = _dbus_string_get_length (data); + for (i = 0; i < len; i++) + { + DBusString *buffer; + + _dbus_message_loader_get_buffer (loader, &buffer); + _dbus_string_append_byte (buffer, + _dbus_string_get_byte (data, i)); + _dbus_message_loader_return_buffer (loader, buffer, 1); + } + + if (!check_loader_results (loader, expected_validity)) + goto failed; + + _dbus_message_loader_unref (loader); + loader = NULL; + + /* Write the data all at once */ + + loader = _dbus_message_loader_new (); + + { + DBusString *buffer; + + _dbus_message_loader_get_buffer (loader, &buffer); + _dbus_string_copy (data, 0, buffer, + _dbus_string_get_length (buffer)); + _dbus_message_loader_return_buffer (loader, buffer, 1); + } + + if (!check_loader_results (loader, expected_validity)) + goto failed; + + _dbus_message_loader_unref (loader); + loader = NULL; + + /* Write the data 2 bytes at a time */ + + loader = _dbus_message_loader_new (); + + len = _dbus_string_get_length (data); + for (i = 0; i < len; i += 2) + { + DBusString *buffer; + + _dbus_message_loader_get_buffer (loader, &buffer); + _dbus_string_append_byte (buffer, + _dbus_string_get_byte (data, i)); + if ((i+1) < len) + _dbus_string_append_byte (buffer, + _dbus_string_get_byte (data, i+1)); + _dbus_message_loader_return_buffer (loader, buffer, 1); + } + + if (!check_loader_results (loader, expected_validity)) + goto failed; + + _dbus_message_loader_unref (loader); + loader = NULL; + + retval = TRUE; + + failed: + + if (loader) + _dbus_message_loader_unref (loader); + + return retval; +} + +static dbus_bool_t +process_test_subdir (const DBusString *test_base_dir, + const char *subdir, + DBusValidity expected_validity, + DBusForeachMessageFileFunc function, + void *user_data) +{ + DBusString test_directory; + DBusString filename; + DBusDirIter *dir; + dbus_bool_t retval; + DBusError error = DBUS_ERROR_INIT; + + retval = FALSE; + dir = NULL; + + if (!_dbus_string_init (&test_directory)) + _dbus_assert_not_reached ("didn't allocate test_directory\n"); + + _dbus_string_init_const (&filename, subdir); + + if (!_dbus_string_copy (test_base_dir, 0, + &test_directory, 0)) + _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory"); + + if (!_dbus_concat_dir_and_file (&test_directory, &filename)) + _dbus_assert_not_reached ("couldn't allocate full path"); + + _dbus_string_free (&filename); + if (!_dbus_string_init (&filename)) + _dbus_assert_not_reached ("didn't allocate filename string\n"); + + dir = _dbus_directory_open (&test_directory, &error); + if (dir == NULL) + { + _dbus_warn ("Could not open %s: %s\n", + _dbus_string_get_const_data (&test_directory), + error.message); + dbus_error_free (&error); + goto failed; + } + + printf ("Testing %s:\n", subdir); + + next: + while (_dbus_directory_get_next_file (dir, &filename, &error)) + { + DBusString full_path; + + if (!_dbus_string_init (&full_path)) + _dbus_assert_not_reached ("couldn't init string"); + + if (!_dbus_string_copy (&test_directory, 0, &full_path, 0)) + _dbus_assert_not_reached ("couldn't copy dir to full_path"); + + if (!_dbus_concat_dir_and_file (&full_path, &filename)) + _dbus_assert_not_reached ("couldn't concat file to dir"); + + if (_dbus_string_ends_with_c_str (&filename, ".message-raw")) + ; + else + { + if (_dbus_string_ends_with_c_str (&filename, ".message")) + { + _dbus_warn ("Could not load %s, message builder language no longer supported\n", + _dbus_string_get_const_data (&filename)); + } + + _dbus_verbose ("Skipping non-.message file %s\n", + _dbus_string_get_const_data (&filename)); + _dbus_string_free (&full_path); + goto next; + } + + printf (" %s\n", + _dbus_string_get_const_data (&filename)); + + if (! (*function) (&full_path, + expected_validity, user_data)) + { + _dbus_string_free (&full_path); + goto failed; + } + else + _dbus_string_free (&full_path); + } + + if (dbus_error_is_set (&error)) + { + _dbus_warn ("Could not get next file in %s: %s\n", + _dbus_string_get_const_data (&test_directory), + error.message); + dbus_error_free (&error); + goto failed; + } + + retval = TRUE; + + failed: + + if (dir) + _dbus_directory_close (dir); + _dbus_string_free (&test_directory); + _dbus_string_free (&filename); + + return retval; +} + +/** + * Runs the given function on every message file in the test suite. + * The function should return #FALSE on test failure or fatal error. + * + * @param test_data_dir root dir of the test suite data files (top_srcdir/test/data) + * @param func the function to run + * @param user_data data for function + * @returns #FALSE if there's a failure + */ +dbus_bool_t +dbus_internal_do_not_use_foreach_message_file (const char *test_data_dir, + DBusForeachMessageFileFunc func, + void *user_data) +{ + DBusString test_directory; + dbus_bool_t retval; + + retval = FALSE; + + _dbus_string_init_const (&test_directory, test_data_dir); + + if (!process_test_subdir (&test_directory, "valid-messages", + DBUS_VALID, func, user_data)) + goto failed; + + check_memleaks (); + + if (!process_test_subdir (&test_directory, "invalid-messages", + DBUS_INVALID_FOR_UNKNOWN_REASON, func, user_data)) + goto failed; + + check_memleaks (); + + if (!process_test_subdir (&test_directory, "incomplete-messages", + DBUS_VALID_BUT_INCOMPLETE, func, user_data)) + goto failed; + + check_memleaks (); + + retval = TRUE; + + failed: + + _dbus_string_free (&test_directory); + + return retval; +} + +#if 0 +#define GET_AND_CHECK(iter, typename, literal) \ + do { \ + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_##typename) \ + _dbus_assert_not_reached ("got wrong argument type from message iter"); \ + dbus_message_iter_get_basic (&iter, &v_##typename); \ + if (v_##typename != literal) \ + _dbus_assert_not_reached ("got wrong value from message iter"); \ + } while (0) + +#define GET_AND_CHECK_STRCMP(iter, typename, literal) \ + do { \ + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_##typename) \ + _dbus_assert_not_reached ("got wrong argument type from message iter"); \ + dbus_message_iter_get_basic (&iter, &v_##typename); \ + if (strcmp (v_##typename, literal) != 0) \ + _dbus_assert_not_reached ("got wrong value from message iter"); \ + } while (0) + +#define GET_AND_CHECK_AND_NEXT(iter, typename, literal) \ + do { \ + GET_AND_CHECK(iter, typename, literal); \ + if (!dbus_message_iter_next (&iter)) \ + _dbus_assert_not_reached ("failed to move iter to next"); \ + } while (0) + +#define GET_AND_CHECK_STRCMP_AND_NEXT(iter, typename, literal) \ + do { \ + GET_AND_CHECK_STRCMP(iter, typename, literal); \ + if (!dbus_message_iter_next (&iter)) \ + _dbus_assert_not_reached ("failed to move iter to next"); \ + } while (0) + +static void +message_iter_test (DBusMessage *message) +{ + DBusMessageIter iter, array, array2; + const char *v_STRING; + double v_DOUBLE; + dbus_int16_t v_INT16; + dbus_uint16_t v_UINT16; + dbus_int32_t v_INT32; + dbus_uint32_t v_UINT32; +#ifdef DBUS_HAVE_INT64 + dbus_int64_t v_INT64; + dbus_uint64_t v_UINT64; +#endif + unsigned char v_BYTE; + dbus_bool_t v_BOOLEAN; + + const dbus_int32_t *our_int_array; + int len; + + dbus_message_iter_init (message, &iter); + + GET_AND_CHECK_STRCMP_AND_NEXT (iter, STRING, "Test string"); + GET_AND_CHECK_AND_NEXT (iter, INT32, -0x12345678); + GET_AND_CHECK_AND_NEXT (iter, UINT32, 0xedd1e); + GET_AND_CHECK_AND_NEXT (iter, DOUBLE, 3.14159); + + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) + _dbus_assert_not_reached ("Argument type not an array"); + + if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_DOUBLE) + _dbus_assert_not_reached ("Array type not double"); + + dbus_message_iter_recurse (&iter, &array); + + GET_AND_CHECK_AND_NEXT (array, DOUBLE, 1.5); + GET_AND_CHECK (array, DOUBLE, 2.5); + + if (dbus_message_iter_next (&array)) + _dbus_assert_not_reached ("Didn't reach end of array"); + + if (!dbus_message_iter_next (&iter)) + _dbus_assert_not_reached ("Reached end of arguments"); + + GET_AND_CHECK_AND_NEXT (iter, BYTE, 0xF0); + + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) + _dbus_assert_not_reached ("no array"); + + if (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_INT32) + _dbus_assert_not_reached ("Array type not int32"); + + /* Empty array */ + dbus_message_iter_recurse (&iter, &array); + + if (dbus_message_iter_next (&array)) + _dbus_assert_not_reached ("Didn't reach end of array"); + + if (!dbus_message_iter_next (&iter)) + _dbus_assert_not_reached ("Reached end of arguments"); + + GET_AND_CHECK (iter, BYTE, 0xF0); + + if (dbus_message_iter_next (&iter)) + _dbus_assert_not_reached ("Didn't reach end of arguments"); +} +#endif + +static void +verify_test_message (DBusMessage *message) +{ + DBusMessageIter iter; + DBusError error = DBUS_ERROR_INIT; + dbus_int16_t our_int16; + dbus_uint16_t our_uint16; + dbus_int32_t our_int; + dbus_uint32_t our_uint; + const char *our_str; + double our_double; + double v_DOUBLE; + dbus_bool_t our_bool; + unsigned char our_byte_1, our_byte_2; + const dbus_uint32_t *our_uint32_array = (void*)0xdeadbeef; + int our_uint32_array_len; + dbus_int32_t *our_int32_array = (void*)0xdeadbeef; + int our_int32_array_len; +#ifdef DBUS_HAVE_INT64 + dbus_int64_t our_int64; + dbus_uint64_t our_uint64; + dbus_int64_t *our_uint64_array = (void*)0xdeadbeef; + int our_uint64_array_len; + const dbus_int64_t *our_int64_array = (void*)0xdeadbeef; + int our_int64_array_len; +#endif + const double *our_double_array = (void*)0xdeadbeef; + int our_double_array_len; + const unsigned char *our_byte_array = (void*)0xdeadbeef; + int our_byte_array_len; + const dbus_bool_t *our_boolean_array = (void*)0xdeadbeef; + int our_boolean_array_len; + char **our_string_array; + int our_string_array_len; + + dbus_message_iter_init (message, &iter); + + if (!dbus_message_iter_get_args (&iter, &error, + DBUS_TYPE_INT16, &our_int16, + DBUS_TYPE_UINT16, &our_uint16, + DBUS_TYPE_INT32, &our_int, + DBUS_TYPE_UINT32, &our_uint, +#ifdef DBUS_HAVE_INT64 + DBUS_TYPE_INT64, &our_int64, + DBUS_TYPE_UINT64, &our_uint64, +#endif + DBUS_TYPE_STRING, &our_str, + DBUS_TYPE_DOUBLE, &our_double, + DBUS_TYPE_BOOLEAN, &our_bool, + DBUS_TYPE_BYTE, &our_byte_1, + DBUS_TYPE_BYTE, &our_byte_2, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, + &our_uint32_array, &our_uint32_array_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, + &our_int32_array, &our_int32_array_len, +#ifdef DBUS_HAVE_INT64 + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, + &our_uint64_array, &our_uint64_array_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, + &our_int64_array, &our_int64_array_len, +#endif + DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, + &our_double_array, &our_double_array_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &our_byte_array, &our_byte_array_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, + &our_boolean_array, &our_boolean_array_len, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, + &our_string_array, &our_string_array_len, + 0)) + { + _dbus_warn ("error: %s - %s\n", error.name, + (error.message != NULL) ? error.message : "no message"); + _dbus_assert_not_reached ("Could not get arguments"); + } + + if (our_int16 != -0x123) + _dbus_assert_not_reached ("16-bit integers differ!"); + + if (our_uint16 != 0x123) + _dbus_assert_not_reached ("16-bit uints differ!"); + + if (our_int != -0x12345678) + _dbus_assert_not_reached ("integers differ!"); + + if (our_uint != 0x12300042) + _dbus_assert_not_reached ("uints differ!"); + +#ifdef DBUS_HAVE_INT64 + if (our_int64 != DBUS_INT64_CONSTANT (-0x123456789abcd)) + _dbus_assert_not_reached ("64-bit integers differ!"); + if (our_uint64 != DBUS_UINT64_CONSTANT (0x123456789abcd)) + _dbus_assert_not_reached ("64-bit unsigned integers differ!"); +#endif + + v_DOUBLE = 3.14159; + if (! _DBUS_DOUBLES_BITWISE_EQUAL (our_double, v_DOUBLE)) + _dbus_assert_not_reached ("doubles differ!"); + + if (strcmp (our_str, "Test string") != 0) + _dbus_assert_not_reached ("strings differ!"); + + if (!our_bool) + _dbus_assert_not_reached ("booleans differ"); + + if (our_byte_1 != 42) + _dbus_assert_not_reached ("bytes differ!"); + + if (our_byte_2 != 24) + _dbus_assert_not_reached ("bytes differ!"); + + if (our_uint32_array_len != 4 || + our_uint32_array[0] != 0x12345678 || + our_uint32_array[1] != 0x23456781 || + our_uint32_array[2] != 0x34567812 || + our_uint32_array[3] != 0x45678123) + _dbus_assert_not_reached ("uint array differs"); + + if (our_int32_array_len != 4 || + our_int32_array[0] != 0x12345678 || + our_int32_array[1] != -0x23456781 || + our_int32_array[2] != 0x34567812 || + our_int32_array[3] != -0x45678123) + _dbus_assert_not_reached ("int array differs"); + +#ifdef DBUS_HAVE_INT64 + if (our_uint64_array_len != 4 || + our_uint64_array[0] != 0x12345678 || + our_uint64_array[1] != 0x23456781 || + our_uint64_array[2] != 0x34567812 || + our_uint64_array[3] != 0x45678123) + _dbus_assert_not_reached ("uint64 array differs"); + + if (our_int64_array_len != 4 || + our_int64_array[0] != 0x12345678 || + our_int64_array[1] != -0x23456781 || + our_int64_array[2] != 0x34567812 || + our_int64_array[3] != -0x45678123) + _dbus_assert_not_reached ("int64 array differs"); +#endif /* DBUS_HAVE_INT64 */ + + if (our_double_array_len != 3) + _dbus_assert_not_reached ("double array had wrong length"); + + /* On all IEEE machines (i.e. everything sane) exact equality + * should be preserved over the wire + */ + v_DOUBLE = 0.1234; + if (! _DBUS_DOUBLES_BITWISE_EQUAL (our_double_array[0], v_DOUBLE)) + _dbus_assert_not_reached ("double array had wrong values"); + v_DOUBLE = 9876.54321; + if (! _DBUS_DOUBLES_BITWISE_EQUAL (our_double_array[1], v_DOUBLE)) + _dbus_assert_not_reached ("double array had wrong values"); + v_DOUBLE = -300.0; + if (! _DBUS_DOUBLES_BITWISE_EQUAL (our_double_array[2], v_DOUBLE)) + _dbus_assert_not_reached ("double array had wrong values"); + + if (our_byte_array_len != 4) + _dbus_assert_not_reached ("byte array had wrong length"); + + if (our_byte_array[0] != 'a' || + our_byte_array[1] != 'b' || + our_byte_array[2] != 'c' || + our_byte_array[3] != 234) + _dbus_assert_not_reached ("byte array had wrong values"); + + if (our_boolean_array_len != 5) + _dbus_assert_not_reached ("bool array had wrong length"); + + if (our_boolean_array[0] != TRUE || + our_boolean_array[1] != FALSE || + our_boolean_array[2] != TRUE || + our_boolean_array[3] != TRUE || + our_boolean_array[4] != FALSE) + _dbus_assert_not_reached ("bool array had wrong values"); + + if (our_string_array_len != 4) + _dbus_assert_not_reached ("string array was wrong length"); + + if (strcmp (our_string_array[0], "Foo") != 0 || + strcmp (our_string_array[1], "bar") != 0 || + strcmp (our_string_array[2], "") != 0 || + strcmp (our_string_array[3], "woo woo woo woo") != 0) + _dbus_assert_not_reached ("string array had wrong values"); + + dbus_free_string_array (our_string_array); + + if (dbus_message_iter_next (&iter)) + _dbus_assert_not_reached ("Didn't reach end of arguments"); +} + +/** + * @ingroup DBusMessageInternals + * Unit test for DBusMessage. + * + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_message_test (const char *test_data_dir) +{ + DBusMessage *message; + DBusMessageLoader *loader; + int i; + const char *data; + DBusMessage *copy; + const char *name1; + const char *name2; + const dbus_uint32_t our_uint32_array[] = + { 0x12345678, 0x23456781, 0x34567812, 0x45678123 }; + const dbus_int32_t our_int32_array[] = + { 0x12345678, -0x23456781, 0x34567812, -0x45678123 }; + const dbus_uint32_t *v_ARRAY_UINT32 = our_uint32_array; + const dbus_int32_t *v_ARRAY_INT32 = our_int32_array; +#ifdef DBUS_HAVE_INT64 + const dbus_uint64_t our_uint64_array[] = + { 0x12345678, 0x23456781, 0x34567812, 0x45678123 }; + const dbus_int64_t our_int64_array[] = + { 0x12345678, -0x23456781, 0x34567812, -0x45678123 }; + const dbus_uint64_t *v_ARRAY_UINT64 = our_uint64_array; + const dbus_int64_t *v_ARRAY_INT64 = our_int64_array; +#endif + const char *our_string_array[] = { "Foo", "bar", "", "woo woo woo woo" }; + const char **v_ARRAY_STRING = our_string_array; + const double our_double_array[] = { 0.1234, 9876.54321, -300.0 }; + const double *v_ARRAY_DOUBLE = our_double_array; + const unsigned char our_byte_array[] = { 'a', 'b', 'c', 234 }; + const unsigned char *v_ARRAY_BYTE = our_byte_array; + const dbus_bool_t our_boolean_array[] = { TRUE, FALSE, TRUE, TRUE, FALSE }; + const dbus_bool_t *v_ARRAY_BOOLEAN = our_boolean_array; + char sig[64]; + const char *s; + const char *v_STRING; + double v_DOUBLE; + dbus_int16_t v_INT16; + dbus_uint16_t v_UINT16; + dbus_int32_t v_INT32; + dbus_uint32_t v_UINT32; +#ifdef DBUS_HAVE_INT64 + dbus_int64_t v_INT64; + dbus_uint64_t v_UINT64; +#endif + unsigned char v_BYTE; + unsigned char v2_BYTE; + dbus_bool_t v_BOOLEAN; + DBusMessageIter iter, array_iter, struct_iter; + + message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", + "/org/freedesktop/TestPath", + "Foo.TestInterface", + "TestMethod"); + _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); + _dbus_assert (dbus_message_is_method_call (message, "Foo.TestInterface", + "TestMethod")); + _dbus_assert (strcmp (dbus_message_get_path (message), + "/org/freedesktop/TestPath") == 0); + dbus_message_set_serial (message, 1234); + + /* string length including nul byte not a multiple of 4 */ + if (!dbus_message_set_sender (message, "org.foo.bar1")) + _dbus_assert_not_reached ("out of memory"); + + _dbus_assert (dbus_message_has_sender (message, "org.foo.bar1")); + dbus_message_set_reply_serial (message, 5678); + + _dbus_verbose_bytes_of_string (&message->header.data, 0, + _dbus_string_get_length (&message->header.data)); + _dbus_verbose_bytes_of_string (&message->body, 0, + _dbus_string_get_length (&message->body)); + + if (!dbus_message_set_sender (message, NULL)) + _dbus_assert_not_reached ("out of memory"); + + + _dbus_verbose_bytes_of_string (&message->header.data, 0, + _dbus_string_get_length (&message->header.data)); + _dbus_verbose_bytes_of_string (&message->body, 0, + _dbus_string_get_length (&message->body)); + + + _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar1")); + _dbus_assert (dbus_message_get_serial (message) == 1234); + _dbus_assert (dbus_message_get_reply_serial (message) == 5678); + _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService")); + + _dbus_assert (dbus_message_get_no_reply (message) == FALSE); + dbus_message_set_no_reply (message, TRUE); + _dbus_assert (dbus_message_get_no_reply (message) == TRUE); + dbus_message_set_no_reply (message, FALSE); + _dbus_assert (dbus_message_get_no_reply (message) == FALSE); + + /* Set/get some header fields */ + + if (!dbus_message_set_path (message, "/foo")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_path (message), + "/foo") == 0); + + if (!dbus_message_set_interface (message, "org.Foo")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_interface (message), + "org.Foo") == 0); + + if (!dbus_message_set_member (message, "Bar")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_member (message), + "Bar") == 0); + + /* Set/get them with longer values */ + if (!dbus_message_set_path (message, "/foo/bar")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_path (message), + "/foo/bar") == 0); + + if (!dbus_message_set_interface (message, "org.Foo.Bar")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_interface (message), + "org.Foo.Bar") == 0); + + if (!dbus_message_set_member (message, "BarFoo")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_member (message), + "BarFoo") == 0); + + /* Realloc shorter again */ + + if (!dbus_message_set_path (message, "/foo")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_path (message), + "/foo") == 0); + + if (!dbus_message_set_interface (message, "org.Foo")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_interface (message), + "org.Foo") == 0); + + if (!dbus_message_set_member (message, "Bar")) + _dbus_assert_not_reached ("out of memory"); + _dbus_assert (strcmp (dbus_message_get_member (message), + "Bar") == 0); + + dbus_message_unref (message); + + /* Test the vararg functions */ + message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", + "/org/freedesktop/TestPath", + "Foo.TestInterface", + "TestMethod"); + dbus_message_set_serial (message, 1); + dbus_message_set_reply_serial (message, 5678); + + v_INT16 = -0x123; + v_UINT16 = 0x123; + v_INT32 = -0x12345678; + v_UINT32 = 0x12300042; +#ifdef DBUS_HAVE_INT64 + v_INT64 = DBUS_INT64_CONSTANT (-0x123456789abcd); + v_UINT64 = DBUS_UINT64_CONSTANT (0x123456789abcd); +#endif + v_STRING = "Test string"; + v_DOUBLE = 3.14159; + v_BOOLEAN = TRUE; + v_BYTE = 42; + v2_BYTE = 24; + + dbus_message_append_args (message, + DBUS_TYPE_INT16, &v_INT16, + DBUS_TYPE_UINT16, &v_UINT16, + DBUS_TYPE_INT32, &v_INT32, + DBUS_TYPE_UINT32, &v_UINT32, +#ifdef DBUS_HAVE_INT64 + DBUS_TYPE_INT64, &v_INT64, + DBUS_TYPE_UINT64, &v_UINT64, +#endif + DBUS_TYPE_STRING, &v_STRING, + DBUS_TYPE_DOUBLE, &v_DOUBLE, + DBUS_TYPE_BOOLEAN, &v_BOOLEAN, + DBUS_TYPE_BYTE, &v_BYTE, + DBUS_TYPE_BYTE, &v2_BYTE, + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &v_ARRAY_UINT32, + _DBUS_N_ELEMENTS (our_uint32_array), + DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY_INT32, + _DBUS_N_ELEMENTS (our_int32_array), +#ifdef DBUS_HAVE_INT64 + DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, &v_ARRAY_UINT64, + _DBUS_N_ELEMENTS (our_uint64_array), + DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, &v_ARRAY_INT64, + _DBUS_N_ELEMENTS (our_int64_array), +#endif + DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, &v_ARRAY_DOUBLE, + _DBUS_N_ELEMENTS (our_double_array), + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &v_ARRAY_BYTE, + _DBUS_N_ELEMENTS (our_byte_array), + DBUS_TYPE_ARRAY, DBUS_TYPE_BOOLEAN, &v_ARRAY_BOOLEAN, + _DBUS_N_ELEMENTS (our_boolean_array), + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &v_ARRAY_STRING, + _DBUS_N_ELEMENTS (our_string_array), + DBUS_TYPE_INVALID); + + i = 0; + sig[i++] = DBUS_TYPE_INT16; + sig[i++] = DBUS_TYPE_UINT16; + sig[i++] = DBUS_TYPE_INT32; + sig[i++] = DBUS_TYPE_UINT32; +#ifdef DBUS_HAVE_INT64 + sig[i++] = DBUS_TYPE_INT64; + sig[i++] = DBUS_TYPE_UINT64; +#endif + sig[i++] = DBUS_TYPE_STRING; + sig[i++] = DBUS_TYPE_DOUBLE; + sig[i++] = DBUS_TYPE_BOOLEAN; + sig[i++] = DBUS_TYPE_BYTE; + sig[i++] = DBUS_TYPE_BYTE; + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_UINT32; + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_INT32; +#ifdef DBUS_HAVE_INT64 + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_UINT64; + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_INT64; +#endif + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_DOUBLE; + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_BYTE; + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_BOOLEAN; + sig[i++] = DBUS_TYPE_ARRAY; + sig[i++] = DBUS_TYPE_STRING; + sig[i++] = DBUS_TYPE_INVALID; + + _dbus_assert (i < (int) _DBUS_N_ELEMENTS (sig)); + + _dbus_verbose ("HEADER\n"); + _dbus_verbose_bytes_of_string (&message->header.data, 0, + _dbus_string_get_length (&message->header.data)); + _dbus_verbose ("BODY\n"); + _dbus_verbose_bytes_of_string (&message->body, 0, + _dbus_string_get_length (&message->body)); + + _dbus_verbose ("Signature expected \"%s\" actual \"%s\"\n", + sig, dbus_message_get_signature (message)); + + s = dbus_message_get_signature (message); + + _dbus_assert (dbus_message_has_signature (message, sig)); + _dbus_assert (strcmp (s, sig) == 0); + + verify_test_message (message); + + copy = dbus_message_copy (message); + + _dbus_assert (dbus_message_get_reply_serial (message) == + dbus_message_get_reply_serial (copy)); + _dbus_assert (message->header.padding == copy->header.padding); + + _dbus_assert (_dbus_string_get_length (&message->header.data) == + _dbus_string_get_length (©->header.data)); + + _dbus_assert (_dbus_string_get_length (&message->body) == + _dbus_string_get_length (©->body)); + + verify_test_message (copy); + + name1 = dbus_message_get_interface (message); + name2 = dbus_message_get_interface (copy); + + _dbus_assert (strcmp (name1, name2) == 0); + + name1 = dbus_message_get_member (message); + name2 = dbus_message_get_member (copy); + + _dbus_assert (strcmp (name1, name2) == 0); + + dbus_message_unref (copy); + + /* Message loader test */ + dbus_message_lock (message); + loader = _dbus_message_loader_new (); + + /* check ref/unref */ + _dbus_message_loader_ref (loader); + _dbus_message_loader_unref (loader); + + /* Write the header data one byte at a time */ + data = _dbus_string_get_const_data (&message->header.data); + for (i = 0; i < _dbus_string_get_length (&message->header.data); i++) + { + DBusString *buffer; + + _dbus_message_loader_get_buffer (loader, &buffer); + _dbus_string_append_byte (buffer, data[i]); + _dbus_message_loader_return_buffer (loader, buffer, 1); + } + + /* Write the body data one byte at a time */ + data = _dbus_string_get_const_data (&message->body); + for (i = 0; i < _dbus_string_get_length (&message->body); i++) + { + DBusString *buffer; + + _dbus_message_loader_get_buffer (loader, &buffer); + _dbus_string_append_byte (buffer, data[i]); + _dbus_message_loader_return_buffer (loader, buffer, 1); + } + + dbus_message_unref (message); + + /* Now pop back the message */ + if (!_dbus_message_loader_queue_messages (loader)) + _dbus_assert_not_reached ("no memory to queue messages"); + + if (_dbus_message_loader_get_is_corrupted (loader)) + _dbus_assert_not_reached ("message loader corrupted"); + + message = _dbus_message_loader_pop_message (loader); + if (!message) + _dbus_assert_not_reached ("received a NULL message"); + + if (dbus_message_get_reply_serial (message) != 5678) + _dbus_assert_not_reached ("reply serial fields differ"); + + verify_test_message (message); + + { + /* Marshal and demarshal the message. */ + + DBusMessage *message2; + DBusError error = DBUS_ERROR_INIT; + char *marshalled = NULL; + int len = 0; + char garbage_header[DBUS_MINIMUM_HEADER_SIZE] = "xxx"; + + if (!dbus_message_marshal (message, &marshalled, &len)) + _dbus_assert_not_reached ("failed to marshal message"); + + _dbus_assert (len != 0); + _dbus_assert (marshalled != NULL); + + _dbus_assert (dbus_message_demarshal_bytes_needed (marshalled, len) == len); + message2 = dbus_message_demarshal (marshalled, len, &error); + + _dbus_assert (message2 != NULL); + _dbus_assert (!dbus_error_is_set (&error)); + verify_test_message (message2); + + dbus_message_unref (message2); + dbus_free (marshalled); + + /* Demarshal invalid message. */ + + message2 = dbus_message_demarshal ("invalid", 7, &error); + _dbus_assert (message2 == NULL); + _dbus_assert (dbus_error_is_set (&error)); + dbus_error_free (&error); + + /* Demarshal invalid (empty) message. */ + + message2 = dbus_message_demarshal ("", 0, &error); + _dbus_assert (message2 == NULL); + _dbus_assert (dbus_error_is_set (&error)); + dbus_error_free (&error); + + /* Bytes needed to demarshal empty message: 0 (more) */ + + _dbus_assert (dbus_message_demarshal_bytes_needed ("", 0) == 0); + + /* Bytes needed to demarshal invalid message: -1 (error). */ + + _dbus_assert (dbus_message_demarshal_bytes_needed (garbage_header, DBUS_MINIMUM_HEADER_SIZE) == -1); + } + + dbus_message_unref (message); + _dbus_message_loader_unref (loader); + + check_memleaks (); + + /* Check that we can abandon a container */ + message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService", + "/org/freedesktop/TestPath", + "Foo.TestInterface", + "Method"); + + dbus_message_iter_init_append (message, &iter); + + _dbus_assert (dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, + (DBUS_STRUCT_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_STRUCT_END_CHAR_AS_STRING), + &array_iter)); + _dbus_assert (dbus_message_iter_open_container (&array_iter, DBUS_TYPE_STRUCT, + NULL, &struct_iter)); + + s = "peaches"; + _dbus_assert (dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, + &s)); + + /* uh-oh, error, try and unwind */ + + dbus_message_iter_abandon_container (&array_iter, &struct_iter); + dbus_message_iter_abandon_container (&array_iter, &iter); + + dbus_message_unref (message); + + /* Load all the sample messages from the message factory */ + { + DBusMessageDataIter diter; + DBusMessageData mdata; + int count; + + reset_validities_seen (); + + count = 0; + _dbus_message_data_iter_init (&diter); + + while (_dbus_message_data_iter_get_and_next (&diter, + &mdata)) + { + if (!dbus_internal_do_not_use_try_message_data (&mdata.data, + mdata.expected_validity)) + { + _dbus_warn ("expected validity %d and did not get it\n", + mdata.expected_validity); + _dbus_assert_not_reached ("message data failed"); + } + + _dbus_message_data_free (&mdata); + + count += 1; + } + + printf ("%d sample messages tested\n", count); + + print_validities_seen (FALSE); + print_validities_seen (TRUE); + } + + check_memleaks (); + + /* Now load every message in test_data_dir if we have one */ + if (test_data_dir == NULL) + return TRUE; + + return dbus_internal_do_not_use_foreach_message_file (test_data_dir, + (DBusForeachMessageFileFunc) + dbus_internal_do_not_use_try_message_file, + NULL); +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c new file mode 100644 index 00000000..272592e8 --- /dev/null +++ b/dbus/dbus-message.c @@ -0,0 +1,4173 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-message.c DBusMessage object + * + * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. + * Copyright (C) 2002, 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-marshal-recursive.h" +#include "dbus-marshal-validate.h" +#include "dbus-marshal-byteswap.h" +#include "dbus-marshal-header.h" +#include "dbus-signature.h" +#include "dbus-message-private.h" +#include "dbus-object-tree.h" +#include "dbus-memory.h" +#include "dbus-list.h" +#include "dbus-threads-internal.h" +#include + +static void dbus_message_finalize (DBusMessage *message); + +/** + * @defgroup DBusMessageInternals DBusMessage implementation details + * @ingroup DBusInternals + * @brief DBusMessage private implementation details. + * + * The guts of DBusMessage and its methods. + * + * @{ + */ + +/* Not thread locked, but strictly const/read-only so should be OK + */ +/** An static string representing an empty signature */ +_DBUS_STRING_DEFINE_STATIC(_dbus_empty_signature_str, ""); + +/* these have wacky values to help trap uninitialized iterators; + * but has to fit in 3 bits + */ +enum { + DBUS_MESSAGE_ITER_TYPE_READER = 3, + DBUS_MESSAGE_ITER_TYPE_WRITER = 7 +}; + +/** typedef for internals of message iterator */ +typedef struct DBusMessageRealIter DBusMessageRealIter; + +/** + * @brief Internals of DBusMessageIter + * + * Object representing a position in a message. All fields are internal. + */ +struct DBusMessageRealIter +{ + DBusMessage *message; /**< Message used */ + dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; /**< stamp to detect invalid iters */ + dbus_uint32_t iter_type : 3; /**< whether this is a reader or writer iter */ + dbus_uint32_t sig_refcount : 8; /**< depth of open_signature() */ + union + { + DBusTypeWriter writer; /**< writer */ + DBusTypeReader reader; /**< reader */ + } u; /**< the type writer or reader that does all the work */ +}; + +static void +get_const_signature (DBusHeader *header, + const DBusString **type_str_p, + int *type_pos_p) +{ + if (_dbus_header_get_field_raw (header, + DBUS_HEADER_FIELD_SIGNATURE, + type_str_p, + type_pos_p)) + { + *type_pos_p += 1; /* skip the signature length which is 1 byte */ + } + else + { + *type_str_p = &_dbus_empty_signature_str; + *type_pos_p = 0; + } +} + +/** + * Swaps the message to compiler byte order if required + * + * @param message the message + */ +static void +_dbus_message_byteswap (DBusMessage *message) +{ + const DBusString *type_str; + int type_pos; + + if (message->byte_order == DBUS_COMPILER_BYTE_ORDER) + return; + + _dbus_verbose ("Swapping message into compiler byte order\n"); + + get_const_signature (&message->header, &type_str, &type_pos); + + _dbus_marshal_byteswap (type_str, type_pos, + message->byte_order, + DBUS_COMPILER_BYTE_ORDER, + &message->body, 0); + + message->byte_order = DBUS_COMPILER_BYTE_ORDER; + + _dbus_header_byteswap (&message->header, DBUS_COMPILER_BYTE_ORDER); +} + +/** byte-swap the message if it doesn't match our byte order. + * Called only when we need the message in our own byte order, + * normally when reading arrays of integers or doubles. + * Otherwise should not be called since it would do needless + * work. + */ +#define ensure_byte_order(message) \ + if (message->byte_order != DBUS_COMPILER_BYTE_ORDER) \ + _dbus_message_byteswap (message) + +/** + * Gets the data to be sent over the network for this message. + * The header and then the body should be written out. + * This function is guaranteed to always return the same + * data once a message is locked (with dbus_message_lock()). + * + * @param message the message. + * @param header return location for message header data. + * @param body return location for message body data. + */ +void +_dbus_message_get_network_data (DBusMessage *message, + const DBusString **header, + const DBusString **body) +{ + _dbus_assert (message->locked); + + *header = &message->header.data; + *body = &message->body; +} + +/** + * Sets the serial number of a message. + * This can only be done once on a message. + * + * DBusConnection will automatically set the serial to an appropriate value + * when the message is sent; this function is only needed when encapsulating + * messages in another protocol, or otherwise bypassing DBusConnection. + * + * @param message the message + * @param serial the serial + */ +void +dbus_message_set_serial (DBusMessage *message, + dbus_uint32_t serial) +{ + _dbus_return_if_fail (message != NULL); + _dbus_return_if_fail (!message->locked); + + _dbus_header_set_serial (&message->header, serial); +} + +/** + * Adds a counter to be incremented immediately with the + * size of this message, and decremented by the size + * of this message when this message if finalized. + * The link contains a counter with its refcount already + * incremented, but the counter itself not incremented. + * Ownership of link and counter refcount is passed to + * the message. + * + * @param message the message + * @param link link with counter as data + */ +void +_dbus_message_add_size_counter_link (DBusMessage *message, + DBusList *link) +{ + /* right now we don't recompute the delta when message + * size changes, and that's OK for current purposes + * I think, but could be important to change later. + * Do recompute it whenever there are no outstanding counters, + * since it's basically free. + */ + if (message->size_counters == NULL) + { + message->size_counter_delta = + _dbus_string_get_length (&message->header.data) + + _dbus_string_get_length (&message->body); + +#if 0 + _dbus_verbose ("message has size %ld\n", + message->size_counter_delta); +#endif + } + + _dbus_list_append_link (&message->size_counters, link); + + _dbus_counter_adjust (link->data, message->size_counter_delta); +} + +/** + * Adds a counter to be incremented immediately with the + * size of this message, and decremented by the size + * of this message when this message if finalized. + * + * @param message the message + * @param counter the counter + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_message_add_size_counter (DBusMessage *message, + DBusCounter *counter) +{ + DBusList *link; + + link = _dbus_list_alloc_link (counter); + if (link == NULL) + return FALSE; + + _dbus_counter_ref (counter); + _dbus_message_add_size_counter_link (message, link); + + return TRUE; +} + +/** + * Removes a counter tracking the size of this message, and decrements + * the counter by the size of this message. + * + * @param message the message + * @param link_return return the link used + * @param counter the counter + */ +void +_dbus_message_remove_size_counter (DBusMessage *message, + DBusCounter *counter, + DBusList **link_return) +{ + DBusList *link; + + link = _dbus_list_find_last (&message->size_counters, + counter); + _dbus_assert (link != NULL); + + _dbus_list_unlink (&message->size_counters, + link); + if (link_return) + *link_return = link; + else + _dbus_list_free_link (link); + + _dbus_counter_adjust (counter, - message->size_counter_delta); + + _dbus_counter_unref (counter); +} + +/** + * Locks a message. Allows checking that applications don't keep a + * reference to a message in the outgoing queue and change it + * underneath us. Messages are locked when they enter the outgoing + * queue (dbus_connection_send_message()), and the library complains + * if the message is modified while locked. This function may also + * called externally, for applications wrapping D-Bus in another protocol. + * + * @param message the message to lock. + */ +void +dbus_message_lock (DBusMessage *message) +{ + if (!message->locked) + { + _dbus_header_update_lengths (&message->header, + _dbus_string_get_length (&message->body)); + + /* must have a signature if you have a body */ + _dbus_assert (_dbus_string_get_length (&message->body) == 0 || + dbus_message_get_signature (message) != NULL); + + message->locked = TRUE; + } +} + +static dbus_bool_t +set_or_delete_string_field (DBusMessage *message, + int field, + int typecode, + const char *value) +{ + if (value == NULL) + return _dbus_header_delete_field (&message->header, field); + else + return _dbus_header_set_field_basic (&message->header, + field, + typecode, + &value); +} + +#if 0 +/* Probably we don't need to use this */ +/** + * Sets the signature of the message, i.e. the arguments in the + * message payload. The signature includes only "in" arguments for + * #DBUS_MESSAGE_TYPE_METHOD_CALL and only "out" arguments for + * #DBUS_MESSAGE_TYPE_METHOD_RETURN, so is slightly different from + * what you might expect (it does not include the signature of the + * entire C++-style method). + * + * The signature is a string made up of type codes such as + * #DBUS_TYPE_INT32. The string is terminated with nul (nul is also + * the value of #DBUS_TYPE_INVALID). The macros such as + * #DBUS_TYPE_INT32 evaluate to integers; to assemble a signature you + * may find it useful to use the string forms, such as + * #DBUS_TYPE_INT32_AS_STRING. + * + * An "unset" or #NULL signature is considered the same as an empty + * signature. In fact dbus_message_get_signature() will never return + * #NULL. + * + * @param message the message + * @param signature the type signature or #NULL to unset + * @returns #FALSE if no memory + */ +static dbus_bool_t +_dbus_message_set_signature (DBusMessage *message, + const char *signature) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (!message->locked, FALSE); + _dbus_return_val_if_fail (signature == NULL || + _dbus_check_is_valid_signature (signature)); + /* can't delete the signature if you have a message body */ + _dbus_return_val_if_fail (_dbus_string_get_length (&message->body) == 0 || + signature != NULL); + + return set_or_delete_string_field (message, + DBUS_HEADER_FIELD_SIGNATURE, + DBUS_TYPE_SIGNATURE, + signature); +} +#endif + +/* Message Cache + * + * We cache some DBusMessage to reduce the overhead of allocating + * them. In my profiling this consistently made about an 8% + * difference. It avoids the malloc for the message, the malloc for + * the slot list, the malloc for the header string and body string, + * and the associated free() calls. It does introduce another global + * lock which could be a performance issue in certain cases. + * + * For the echo client/server the round trip time goes from around + * .000077 to .000069 with the message cache on my laptop. The sysprof + * change is as follows (numbers are cumulative percentage): + * + * with message cache implemented as array as it is now (0.000069 per): + * new_empty_header 1.46 + * mutex_lock 0.56 # i.e. _DBUS_LOCK(message_cache) + * mutex_unlock 0.25 + * self 0.41 + * unref 2.24 + * self 0.68 + * list_clear 0.43 + * mutex_lock 0.33 # i.e. _DBUS_LOCK(message_cache) + * mutex_unlock 0.25 + * + * with message cache implemented as list (0.000070 per roundtrip): + * new_empty_header 2.72 + * list_pop_first 1.88 + * unref 3.3 + * list_prepend 1.63 + * + * without cache (0.000077 per roundtrip): + * new_empty_header 6.7 + * string_init_preallocated 3.43 + * dbus_malloc 2.43 + * dbus_malloc0 2.59 + * + * unref 4.02 + * string_free 1.82 + * dbus_free 1.63 + * dbus_free 0.71 + * + * If you implement the message_cache with a list, the primary reason + * it's slower is that you add another thread lock (on the DBusList + * mempool). + */ + +/** Avoid caching huge messages */ +#define MAX_MESSAGE_SIZE_TO_CACHE 10 * _DBUS_ONE_KILOBYTE + +/** Avoid caching too many messages */ +#define MAX_MESSAGE_CACHE_SIZE 5 + +_DBUS_DEFINE_GLOBAL_LOCK (message_cache); +static DBusMessage *message_cache[MAX_MESSAGE_CACHE_SIZE]; +static int message_cache_count = 0; +static dbus_bool_t message_cache_shutdown_registered = FALSE; + +static void +dbus_message_cache_shutdown (void *data) +{ + int i; + + _DBUS_LOCK (message_cache); + + i = 0; + while (i < MAX_MESSAGE_CACHE_SIZE) + { + if (message_cache[i]) + dbus_message_finalize (message_cache[i]); + + ++i; + } + + message_cache_count = 0; + message_cache_shutdown_registered = FALSE; + + _DBUS_UNLOCK (message_cache); +} + +/** + * Tries to get a message from the message cache. The retrieved + * message will have junk in it, so it still needs to be cleared out + * in dbus_message_new_empty_header() + * + * @returns the message, or #NULL if none cached + */ +static DBusMessage* +dbus_message_get_cached (void) +{ + DBusMessage *message; + int i; + + message = NULL; + + _DBUS_LOCK (message_cache); + + _dbus_assert (message_cache_count >= 0); + + if (message_cache_count == 0) + { + _DBUS_UNLOCK (message_cache); + return NULL; + } + + /* This is not necessarily true unless count > 0, and + * message_cache is uninitialized until the shutdown is + * registered + */ + _dbus_assert (message_cache_shutdown_registered); + + i = 0; + while (i < MAX_MESSAGE_CACHE_SIZE) + { + if (message_cache[i]) + { + message = message_cache[i]; + message_cache[i] = NULL; + message_cache_count -= 1; + break; + } + ++i; + } + _dbus_assert (message_cache_count >= 0); + _dbus_assert (i < MAX_MESSAGE_CACHE_SIZE); + _dbus_assert (message != NULL); + + _dbus_assert (message->refcount.value == 0); + _dbus_assert (message->size_counters == NULL); + + _DBUS_UNLOCK (message_cache); + + return message; +} + +static void +free_size_counter (void *element, + void *data) +{ + DBusCounter *counter = element; + DBusMessage *message = data; + + _dbus_counter_adjust (counter, - message->size_counter_delta); + + _dbus_counter_unref (counter); +} + +/** + * Tries to cache a message, otherwise finalize it. + * + * @param message the message + */ +static void +dbus_message_cache_or_finalize (DBusMessage *message) +{ + dbus_bool_t was_cached; + int i; + + _dbus_assert (message->refcount.value == 0); + + /* This calls application code and has to be done first thing + * without holding the lock + */ + _dbus_data_slot_list_clear (&message->slot_list); + + _dbus_list_foreach (&message->size_counters, + free_size_counter, message); + _dbus_list_clear (&message->size_counters); + + was_cached = FALSE; + + _DBUS_LOCK (message_cache); + + if (!message_cache_shutdown_registered) + { + _dbus_assert (message_cache_count == 0); + + if (!_dbus_register_shutdown_func (dbus_message_cache_shutdown, NULL)) + goto out; + + i = 0; + while (i < MAX_MESSAGE_CACHE_SIZE) + { + message_cache[i] = NULL; + ++i; + } + + message_cache_shutdown_registered = TRUE; + } + + _dbus_assert (message_cache_count >= 0); + + if ((_dbus_string_get_length (&message->header.data) + + _dbus_string_get_length (&message->body)) > + MAX_MESSAGE_SIZE_TO_CACHE) + goto out; + + if (message_cache_count >= MAX_MESSAGE_CACHE_SIZE) + goto out; + + /* Find empty slot */ + i = 0; + while (message_cache[i] != NULL) + ++i; + + _dbus_assert (i < MAX_MESSAGE_CACHE_SIZE); + + _dbus_assert (message_cache[i] == NULL); + message_cache[i] = message; + message_cache_count += 1; + was_cached = TRUE; +#ifndef DBUS_DISABLE_CHECKS + message->in_cache = TRUE; +#endif + + out: + _dbus_assert (message->refcount.value == 0); + + _DBUS_UNLOCK (message_cache); + + if (!was_cached) + dbus_message_finalize (message); +} + +#ifndef DBUS_DISABLE_CHECKS +static dbus_bool_t +_dbus_message_iter_check (DBusMessageRealIter *iter) +{ + if (iter == NULL) + { + _dbus_warn_check_failed ("dbus message iterator is NULL\n"); + return FALSE; + } + + if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_READER) + { + if (iter->u.reader.byte_order != iter->message->byte_order) + { + _dbus_warn_check_failed ("dbus message changed byte order since iterator was created\n"); + return FALSE; + } + /* because we swap the message into compiler order when you init an iter */ + _dbus_assert (iter->u.reader.byte_order == DBUS_COMPILER_BYTE_ORDER); + } + else if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER) + { + if (iter->u.writer.byte_order != iter->message->byte_order) + { + _dbus_warn_check_failed ("dbus message changed byte order since append iterator was created\n"); + return FALSE; + } + /* because we swap the message into compiler order when you init an iter */ + _dbus_assert (iter->u.writer.byte_order == DBUS_COMPILER_BYTE_ORDER); + } + else + { + _dbus_warn_check_failed ("dbus message iterator looks uninitialized or corrupted\n"); + return FALSE; + } + + if (iter->changed_stamp != iter->message->changed_stamp) + { + _dbus_warn_check_failed ("dbus message iterator invalid because the message has been modified (or perhaps the iterator is just uninitialized)\n"); + return FALSE; + } + + return TRUE; +} +#endif /* DBUS_DISABLE_CHECKS */ + +/** + * Implementation of the varargs arg-getting functions. + * dbus_message_get_args() is the place to go for complete + * documentation. + * + * @see dbus_message_get_args + * @param iter the message iter + * @param error error to be filled in + * @param first_arg_type type of the first argument + * @param var_args return location for first argument, followed by list of type/location pairs + * @returns #FALSE if error was set + */ +dbus_bool_t +_dbus_message_iter_get_args_valist (DBusMessageIter *iter, + DBusError *error, + int first_arg_type, + va_list var_args) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + int spec_type, msg_type, i; + dbus_bool_t retval; + + _dbus_assert (_dbus_message_iter_check (real)); + + retval = FALSE; + + spec_type = first_arg_type; + i = 0; + + while (spec_type != DBUS_TYPE_INVALID) + { + msg_type = dbus_message_iter_get_arg_type (iter); + + if (msg_type != spec_type) + { + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Argument %d is specified to be of type \"%s\", but " + "is actually of type \"%s\"\n", i, + _dbus_type_to_string (spec_type), + _dbus_type_to_string (msg_type)); + + goto out; + } + + if (dbus_type_is_basic (spec_type)) + { + DBusBasicValue *ptr; + + ptr = va_arg (var_args, DBusBasicValue*); + + _dbus_assert (ptr != NULL); + + _dbus_type_reader_read_basic (&real->u.reader, + ptr); + } + else if (spec_type == DBUS_TYPE_ARRAY) + { + int element_type; + int spec_element_type; + const DBusBasicValue **ptr; + int *n_elements_p; + DBusTypeReader array; + + spec_element_type = va_arg (var_args, int); + element_type = _dbus_type_reader_get_element_type (&real->u.reader); + + if (spec_element_type != element_type) + { + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Argument %d is specified to be an array of \"%s\", but " + "is actually an array of \"%s\"\n", + i, + _dbus_type_to_string (spec_element_type), + _dbus_type_to_string (element_type)); + + goto out; + } + + if (dbus_type_is_fixed (spec_element_type)) + { + ptr = va_arg (var_args, const DBusBasicValue**); + n_elements_p = va_arg (var_args, int*); + + _dbus_assert (ptr != NULL); + _dbus_assert (n_elements_p != NULL); + + _dbus_type_reader_recurse (&real->u.reader, &array); + + _dbus_type_reader_read_fixed_multi (&array, + ptr, n_elements_p); + } + else if (spec_element_type == DBUS_TYPE_STRING || + spec_element_type == DBUS_TYPE_SIGNATURE || + spec_element_type == DBUS_TYPE_OBJECT_PATH) + { + char ***str_array_p; + int n_elements; + char **str_array; + + str_array_p = va_arg (var_args, char***); + n_elements_p = va_arg (var_args, int*); + + _dbus_assert (str_array_p != NULL); + _dbus_assert (n_elements_p != NULL); + + /* Count elements in the array */ + _dbus_type_reader_recurse (&real->u.reader, &array); + + n_elements = 0; + while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID) + { + ++n_elements; + _dbus_type_reader_next (&array); + } + + str_array = dbus_new0 (char*, n_elements + 1); + if (str_array == NULL) + { + _DBUS_SET_OOM (error); + goto out; + } + + /* Now go through and dup each string */ + _dbus_type_reader_recurse (&real->u.reader, &array); + + i = 0; + while (i < n_elements) + { + const char *s; + _dbus_type_reader_read_basic (&array, + &s); + + str_array[i] = _dbus_strdup (s); + if (str_array[i] == NULL) + { + dbus_free_string_array (str_array); + _DBUS_SET_OOM (error); + goto out; + } + + ++i; + + if (!_dbus_type_reader_next (&array)) + _dbus_assert (i == n_elements); + } + + _dbus_assert (_dbus_type_reader_get_current_type (&array) == DBUS_TYPE_INVALID); + _dbus_assert (i == n_elements); + _dbus_assert (str_array[i] == NULL); + + *str_array_p = str_array; + *n_elements_p = n_elements; + } +#ifndef DBUS_DISABLE_CHECKS + else + { + _dbus_warn ("you can't read arrays of container types (struct, variant, array) with %s for now\n", + _DBUS_FUNCTION_NAME); + goto out; + } +#endif + } +#ifndef DBUS_DISABLE_CHECKS + else + { + _dbus_warn ("you can only read arrays and basic types with %s for now\n", + _DBUS_FUNCTION_NAME); + goto out; + } +#endif + + spec_type = va_arg (var_args, int); + if (!_dbus_type_reader_next (&real->u.reader) && spec_type != DBUS_TYPE_INVALID) + { + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, + "Message has only %d arguments, but more were expected", i); + goto out; + } + + i++; + } + + retval = TRUE; + + out: + + return retval; +} + +/** @} */ + +/** + * @defgroup DBusMessage DBusMessage + * @ingroup DBus + * @brief Message to be sent or received over a #DBusConnection. + * + * A DBusMessage is the most basic unit of communication over a + * DBusConnection. A DBusConnection represents a stream of messages + * received from a remote application, and a stream of messages + * sent to a remote application. + * + * A message has a message type, returned from + * dbus_message_get_type(). This indicates whether the message is a + * method call, a reply to a method call, a signal, or an error reply. + * + * A message has header fields such as the sender, destination, method + * or signal name, and so forth. DBusMessage has accessor functions for + * these, such as dbus_message_get_member(). + * + * Convenience functions dbus_message_is_method_call(), dbus_message_is_signal(), + * and dbus_message_is_error() check several header fields at once and are + * slightly more efficient than checking the header fields with individual + * accessor functions. + * + * Finally, a message has arguments. The number and types of arguments + * are in the message's signature header field (accessed with + * dbus_message_get_signature()). Simple argument values are usually + * retrieved with dbus_message_get_args() but more complex values such + * as structs may require the use of #DBusMessageIter. + * + * The D-Bus specification goes into some more detail about header fields and + * message types. + * + * @{ + */ + +/** + * @typedef DBusMessage + * + * Opaque data type representing a message received from or to be + * sent to another application. + */ + +/** + * Returns the serial of a message or 0 if none has been specified. + * The message's serial number is provided by the application sending + * the message and is used to identify replies to this message. + * + * All messages received on a connection will have a serial provided + * by the remote application. + * + * For messages you're sending, dbus_connection_send() will assign a + * serial and return it to you. + * + * @param message the message + * @returns the serial + */ +dbus_uint32_t +dbus_message_get_serial (DBusMessage *message) +{ + _dbus_return_val_if_fail (message != NULL, 0); + + return _dbus_header_get_serial (&message->header); +} + +/** + * Sets the reply serial of a message (the serial of the message this + * is a reply to). + * + * @param message the message + * @param reply_serial the serial we're replying to + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_reply_serial (DBusMessage *message, + dbus_uint32_t reply_serial) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (!message->locked, FALSE); + _dbus_return_val_if_fail (reply_serial != 0, FALSE); /* 0 is invalid */ + + return _dbus_header_set_field_basic (&message->header, + DBUS_HEADER_FIELD_REPLY_SERIAL, + DBUS_TYPE_UINT32, + &reply_serial); +} + +/** + * Returns the serial that the message is a reply to or 0 if none. + * + * @param message the message + * @returns the reply serial + */ +dbus_uint32_t +dbus_message_get_reply_serial (DBusMessage *message) +{ + dbus_uint32_t v_UINT32; + + _dbus_return_val_if_fail (message != NULL, 0); + + if (_dbus_header_get_field_basic (&message->header, + DBUS_HEADER_FIELD_REPLY_SERIAL, + DBUS_TYPE_UINT32, + &v_UINT32)) + return v_UINT32; + else + return 0; +} + +static void +dbus_message_finalize (DBusMessage *message) +{ + _dbus_assert (message->refcount.value == 0); + + /* This calls application callbacks! */ + _dbus_data_slot_list_free (&message->slot_list); + + _dbus_list_foreach (&message->size_counters, + free_size_counter, message); + _dbus_list_clear (&message->size_counters); + + _dbus_header_free (&message->header); + _dbus_string_free (&message->body); + + _dbus_assert (message->refcount.value == 0); + + dbus_free (message); +} + +static DBusMessage* +dbus_message_new_empty_header (void) +{ + DBusMessage *message; + dbus_bool_t from_cache; + + message = dbus_message_get_cached (); + + if (message != NULL) + { + from_cache = TRUE; + } + else + { + from_cache = FALSE; + message = dbus_new (DBusMessage, 1); + if (message == NULL) + return NULL; +#ifndef DBUS_DISABLE_CHECKS + message->generation = _dbus_current_generation; +#endif + } + + message->refcount.value = 1; + message->byte_order = DBUS_COMPILER_BYTE_ORDER; + message->locked = FALSE; +#ifndef DBUS_DISABLE_CHECKS + message->in_cache = FALSE; +#endif + message->size_counters = NULL; + message->size_counter_delta = 0; + message->changed_stamp = 0; + + if (!from_cache) + _dbus_data_slot_list_init (&message->slot_list); + + if (from_cache) + { + _dbus_header_reinit (&message->header, message->byte_order); + _dbus_string_set_length (&message->body, 0); + } + else + { + if (!_dbus_header_init (&message->header, message->byte_order)) + { + dbus_free (message); + return NULL; + } + + if (!_dbus_string_init_preallocated (&message->body, 32)) + { + _dbus_header_free (&message->header); + dbus_free (message); + return NULL; + } + } + + return message; +} + +/** + * Constructs a new message of the given message type. + * Types include #DBUS_MESSAGE_TYPE_METHOD_CALL, + * #DBUS_MESSAGE_TYPE_SIGNAL, and so forth. + * + * Usually you want to use dbus_message_new_method_call(), + * dbus_message_new_method_return(), dbus_message_new_signal(), + * or dbus_message_new_error() instead. + * + * @param message_type type of message + * @returns new message or #NULL if no memory + */ +DBusMessage* +dbus_message_new (int message_type) +{ + DBusMessage *message; + + _dbus_return_val_if_fail (message_type != DBUS_MESSAGE_TYPE_INVALID, NULL); + + message = dbus_message_new_empty_header (); + if (message == NULL) + return NULL; + + if (!_dbus_header_create (&message->header, + message_type, + NULL, NULL, NULL, NULL, NULL)) + { + dbus_message_unref (message); + return NULL; + } + + return message; +} + +/** + * Constructs a new message to invoke a method on a remote + * object. Returns #NULL if memory can't be allocated for the + * message. The destination may be #NULL in which case no destination + * is set; this is appropriate when using D-Bus in a peer-to-peer + * context (no message bus). The interface may be #NULL, which means + * that if multiple methods with the given name exist it is undefined + * which one will be invoked. + * + * The path and method names may not be #NULL. + * + * Destination, path, interface, and method name can't contain + * any invalid characters (see the D-Bus specification). + * + * @param destination name that the message should be sent to or #NULL + * @param path object path the message should be sent to + * @param interface interface to invoke method on, or #NULL + * @param method method to invoke + * + * @returns a new DBusMessage, free with dbus_message_unref() + */ +DBusMessage* +dbus_message_new_method_call (const char *destination, + const char *path, + const char *interface, + const char *method) +{ + DBusMessage *message; + + _dbus_return_val_if_fail (path != NULL, NULL); + _dbus_return_val_if_fail (method != NULL, NULL); + _dbus_return_val_if_fail (destination == NULL || + _dbus_check_is_valid_bus_name (destination), NULL); + _dbus_return_val_if_fail (_dbus_check_is_valid_path (path), NULL); + _dbus_return_val_if_fail (interface == NULL || + _dbus_check_is_valid_interface (interface), NULL); + _dbus_return_val_if_fail (_dbus_check_is_valid_member (method), NULL); + + message = dbus_message_new_empty_header (); + if (message == NULL) + return NULL; + + if (!_dbus_header_create (&message->header, + DBUS_MESSAGE_TYPE_METHOD_CALL, + destination, path, interface, method, NULL)) + { + dbus_message_unref (message); + return NULL; + } + + return message; +} + +/** + * Constructs a message that is a reply to a method call. Returns + * #NULL if memory can't be allocated for the message. + * + * @param method_call the message being replied to + * @returns a new DBusMessage, free with dbus_message_unref() + */ +DBusMessage* +dbus_message_new_method_return (DBusMessage *method_call) +{ + DBusMessage *message; + const char *sender; + + _dbus_return_val_if_fail (method_call != NULL, NULL); + + sender = dbus_message_get_sender (method_call); + + /* sender is allowed to be null here in peer-to-peer case */ + + message = dbus_message_new_empty_header (); + if (message == NULL) + return NULL; + + if (!_dbus_header_create (&message->header, + DBUS_MESSAGE_TYPE_METHOD_RETURN, + sender, NULL, NULL, NULL, NULL)) + { + dbus_message_unref (message); + return NULL; + } + + dbus_message_set_no_reply (message, TRUE); + + if (!dbus_message_set_reply_serial (message, + dbus_message_get_serial (method_call))) + { + dbus_message_unref (message); + return NULL; + } + + return message; +} + +/** + * Constructs a new message representing a signal emission. Returns + * #NULL if memory can't be allocated for the message. A signal is + * identified by its originating object path, interface, and the name + * of the signal. + * + * Path, interface, and signal name must all be valid (the D-Bus + * specification defines the syntax of these fields). + * + * @param path the path to the object emitting the signal + * @param interface the interface the signal is emitted from + * @param name name of the signal + * @returns a new DBusMessage, free with dbus_message_unref() + */ +DBusMessage* +dbus_message_new_signal (const char *path, + const char *interface, + const char *name) +{ + DBusMessage *message; + + _dbus_return_val_if_fail (path != NULL, NULL); + _dbus_return_val_if_fail (interface != NULL, NULL); + _dbus_return_val_if_fail (name != NULL, NULL); + _dbus_return_val_if_fail (_dbus_check_is_valid_path (path), NULL); + _dbus_return_val_if_fail (_dbus_check_is_valid_interface (interface), NULL); + _dbus_return_val_if_fail (_dbus_check_is_valid_member (name), NULL); + + message = dbus_message_new_empty_header (); + if (message == NULL) + return NULL; + + if (!_dbus_header_create (&message->header, + DBUS_MESSAGE_TYPE_SIGNAL, + NULL, path, interface, name, NULL)) + { + dbus_message_unref (message); + return NULL; + } + + dbus_message_set_no_reply (message, TRUE); + + return message; +} + +/** + * Creates a new message that is an error reply to another message. + * Error replies are most common in response to method calls, but + * can be returned in reply to any message. + * + * The error name must be a valid error name according to the syntax + * given in the D-Bus specification. If you don't want to make + * up an error name just use #DBUS_ERROR_FAILED. + * + * @param reply_to the message we're replying to + * @param error_name the error name + * @param error_message the error message string (or #NULL for none, but please give a message) + * @returns a new error message object, free with dbus_message_unref() + */ +DBusMessage* +dbus_message_new_error (DBusMessage *reply_to, + const char *error_name, + const char *error_message) +{ + DBusMessage *message; + const char *sender; + DBusMessageIter iter; + + _dbus_return_val_if_fail (reply_to != NULL, NULL); + _dbus_return_val_if_fail (error_name != NULL, NULL); + _dbus_return_val_if_fail (_dbus_check_is_valid_error_name (error_name), NULL); + + sender = dbus_message_get_sender (reply_to); + + /* sender may be NULL for non-message-bus case or + * when the message bus is dealing with an unregistered + * connection. + */ + message = dbus_message_new_empty_header (); + if (message == NULL) + return NULL; + + if (!_dbus_header_create (&message->header, + DBUS_MESSAGE_TYPE_ERROR, + sender, NULL, NULL, NULL, error_name)) + { + dbus_message_unref (message); + return NULL; + } + + dbus_message_set_no_reply (message, TRUE); + + if (!dbus_message_set_reply_serial (message, + dbus_message_get_serial (reply_to))) + { + dbus_message_unref (message); + return NULL; + } + + if (error_message != NULL) + { + dbus_message_iter_init_append (message, &iter); + if (!dbus_message_iter_append_basic (&iter, + DBUS_TYPE_STRING, + &error_message)) + { + dbus_message_unref (message); + return NULL; + } + } + + return message; +} + +/** + * Creates a new message that is an error reply to another message, allowing + * you to use printf formatting. + * + * See dbus_message_new_error() for details - this function is the same + * aside from the printf formatting. + * + * @todo add _DBUS_GNUC_PRINTF to this (requires moving _DBUS_GNUC_PRINTF to + * public header, see DBUS_DEPRECATED for an example) + * + * @param reply_to the original message + * @param error_name the error name + * @param error_format the error message format as with printf + * @param ... format string arguments + * @returns a new error message + */ +DBusMessage* +dbus_message_new_error_printf (DBusMessage *reply_to, + const char *error_name, + const char *error_format, + ...) +{ + va_list args; + DBusString str; + DBusMessage *message; + + _dbus_return_val_if_fail (reply_to != NULL, NULL); + _dbus_return_val_if_fail (error_name != NULL, NULL); + _dbus_return_val_if_fail (_dbus_check_is_valid_error_name (error_name), NULL); + + if (!_dbus_string_init (&str)) + return NULL; + + va_start (args, error_format); + + if (_dbus_string_append_printf_valist (&str, error_format, args)) + message = dbus_message_new_error (reply_to, error_name, + _dbus_string_get_const_data (&str)); + else + message = NULL; + + _dbus_string_free (&str); + + va_end (args); + + return message; +} + + +/** + * Creates a new message that is an exact replica of the message + * specified, except that its refcount is set to 1, its message serial + * is reset to 0, and if the original message was "locked" (in the + * outgoing message queue and thus not modifiable) the new message + * will not be locked. + * + * @param message the message + * @returns the new message.or #NULL if not enough memory + */ +DBusMessage * +dbus_message_copy (const DBusMessage *message) +{ + DBusMessage *retval; + + _dbus_return_val_if_fail (message != NULL, NULL); + + retval = dbus_new0 (DBusMessage, 1); + if (retval == NULL) + return NULL; + + retval->refcount.value = 1; + retval->byte_order = message->byte_order; + retval->locked = FALSE; +#ifndef DBUS_DISABLE_CHECKS + retval->generation = message->generation; +#endif + + if (!_dbus_header_copy (&message->header, &retval->header)) + { + dbus_free (retval); + return NULL; + } + + if (!_dbus_string_init_preallocated (&retval->body, + _dbus_string_get_length (&message->body))) + { + _dbus_header_free (&retval->header); + dbus_free (retval); + return NULL; + } + + if (!_dbus_string_copy (&message->body, 0, + &retval->body, 0)) + goto failed_copy; + + return retval; + + failed_copy: + _dbus_header_free (&retval->header); + _dbus_string_free (&retval->body); + dbus_free (retval); + + return NULL; +} + + +/** + * Increments the reference count of a DBusMessage. + * + * @param message the message + * @returns the message + * @see dbus_message_unref + */ +DBusMessage * +dbus_message_ref (DBusMessage *message) +{ + dbus_int32_t old_refcount; + + _dbus_return_val_if_fail (message != NULL, NULL); + _dbus_return_val_if_fail (message->generation == _dbus_current_generation, NULL); + _dbus_return_val_if_fail (!message->in_cache, NULL); + + old_refcount = _dbus_atomic_inc (&message->refcount); + _dbus_assert (old_refcount >= 1); + + return message; +} + +/** + * Decrements the reference count of a DBusMessage, freeing the + * message if the count reaches 0. + * + * @param message the message + * @see dbus_message_ref + */ +void +dbus_message_unref (DBusMessage *message) +{ + dbus_int32_t old_refcount; + + _dbus_return_if_fail (message != NULL); + _dbus_return_if_fail (message->generation == _dbus_current_generation); + _dbus_return_if_fail (!message->in_cache); + + old_refcount = _dbus_atomic_dec (&message->refcount); + + _dbus_assert (old_refcount >= 0); + + if (old_refcount == 1) + { + /* Calls application callbacks! */ + dbus_message_cache_or_finalize (message); + } +} + +/** + * Gets the type of a message. Types include + * #DBUS_MESSAGE_TYPE_METHOD_CALL, #DBUS_MESSAGE_TYPE_METHOD_RETURN, + * #DBUS_MESSAGE_TYPE_ERROR, #DBUS_MESSAGE_TYPE_SIGNAL, but other + * types are allowed and all code must silently ignore messages of + * unknown type. #DBUS_MESSAGE_TYPE_INVALID will never be returned. + * + * @param message the message + * @returns the type of the message + */ +int +dbus_message_get_type (DBusMessage *message) +{ + _dbus_return_val_if_fail (message != NULL, DBUS_MESSAGE_TYPE_INVALID); + + return _dbus_header_get_message_type (&message->header); +} + +/** + * Appends fields to a message given a variable argument list. The + * variable argument list should contain the type of each argument + * followed by the value to append. Appendable types are basic types, + * and arrays of fixed-length basic types. To append variable-length + * basic types, or any more complex value, you have to use an iterator + * rather than this function. + * + * To append a basic type, specify its type code followed by the + * address of the value. For example: + * + * @code + * + * dbus_int32_t v_INT32 = 42; + * const char *v_STRING = "Hello World"; + * dbus_message_append_args (message, + * DBUS_TYPE_INT32, &v_INT32, + * DBUS_TYPE_STRING, &v_STRING, + * DBUS_TYPE_INVALID); + * @endcode + * + * To append an array of fixed-length basic types, pass in the + * DBUS_TYPE_ARRAY typecode, the element typecode, the address of + * the array pointer, and a 32-bit integer giving the number of + * elements in the array. So for example: + * @code + * const dbus_int32_t array[] = { 1, 2, 3 }; + * const dbus_int32_t *v_ARRAY = array; + * dbus_message_append_args (message, + * DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY, 3, + * DBUS_TYPE_INVALID); + * @endcode + * + * @warning in C, given "int array[]", "&array == array" (the + * comp.lang.c FAQ says otherwise, but gcc and the FAQ don't agree). + * So if you're using an array instead of a pointer you have to create + * a pointer variable, assign the array to it, then take the address + * of the pointer variable. For strings it works to write + * const char *array = "Hello" and then use &array though. + * + * The last argument to this function must be #DBUS_TYPE_INVALID, + * marking the end of the argument list. If you don't do this + * then libdbus won't know to stop and will read invalid memory. + * + * String/signature/path arrays should be passed in as "const char*** + * address_of_array" and "int n_elements" + * + * @todo support DBUS_TYPE_STRUCT and DBUS_TYPE_VARIANT and complex arrays + * + * @todo If this fails due to lack of memory, the message is hosed and + * you have to start over building the whole message. + * + * @param message the message + * @param first_arg_type type of the first argument + * @param ... value of first argument, list of additional type-value pairs + * @returns #TRUE on success + */ +dbus_bool_t +dbus_message_append_args (DBusMessage *message, + int first_arg_type, + ...) +{ + dbus_bool_t retval; + va_list var_args; + + _dbus_return_val_if_fail (message != NULL, FALSE); + + va_start (var_args, first_arg_type); + retval = dbus_message_append_args_valist (message, + first_arg_type, + var_args); + va_end (var_args); + + return retval; +} + +/** + * Like dbus_message_append_args() but takes a va_list for use by language bindings. + * + * @todo for now, if this function fails due to OOM it will leave + * the message half-written and you have to discard the message + * and start over. + * + * @see dbus_message_append_args. + * @param message the message + * @param first_arg_type type of first argument + * @param var_args value of first argument, then list of type/value pairs + * @returns #TRUE on success + */ +dbus_bool_t +dbus_message_append_args_valist (DBusMessage *message, + int first_arg_type, + va_list var_args) +{ + int type; + DBusMessageIter iter; + + _dbus_return_val_if_fail (message != NULL, FALSE); + + type = first_arg_type; + + dbus_message_iter_init_append (message, &iter); + + while (type != DBUS_TYPE_INVALID) + { + if (dbus_type_is_basic (type)) + { + const DBusBasicValue *value; + value = va_arg (var_args, const DBusBasicValue*); + + if (!dbus_message_iter_append_basic (&iter, + type, + value)) + goto failed; + } + else if (type == DBUS_TYPE_ARRAY) + { + int element_type; + DBusMessageIter array; + char buf[2]; + + element_type = va_arg (var_args, int); + + buf[0] = element_type; + buf[1] = '\0'; + if (!dbus_message_iter_open_container (&iter, + DBUS_TYPE_ARRAY, + buf, + &array)) + goto failed; + + if (dbus_type_is_fixed (element_type)) + { + const DBusBasicValue **value; + int n_elements; + + value = va_arg (var_args, const DBusBasicValue**); + n_elements = va_arg (var_args, int); + + if (!dbus_message_iter_append_fixed_array (&array, + element_type, + value, + n_elements)) { + dbus_message_iter_abandon_container (&iter, &array); + goto failed; + } + } + else if (element_type == DBUS_TYPE_STRING || + element_type == DBUS_TYPE_SIGNATURE || + element_type == DBUS_TYPE_OBJECT_PATH) + { + const char ***value_p; + const char **value; + int n_elements; + int i; + + value_p = va_arg (var_args, const char***); + n_elements = va_arg (var_args, int); + + value = *value_p; + + i = 0; + while (i < n_elements) + { + if (!dbus_message_iter_append_basic (&array, + element_type, + &value[i])) { + dbus_message_iter_abandon_container (&iter, &array); + goto failed; + } + ++i; + } + } + else + { + _dbus_warn ("arrays of %s can't be appended with %s for now\n", + _dbus_type_to_string (element_type), + _DBUS_FUNCTION_NAME); + goto failed; + } + + if (!dbus_message_iter_close_container (&iter, &array)) + goto failed; + } +#ifndef DBUS_DISABLE_CHECKS + else + { + _dbus_warn ("type %s isn't supported yet in %s\n", + _dbus_type_to_string (type), _DBUS_FUNCTION_NAME); + goto failed; + } +#endif + + type = va_arg (var_args, int); + } + + return TRUE; + + failed: + return FALSE; +} + +/** + * Gets arguments from a message given a variable argument list. The + * supported types include those supported by + * dbus_message_append_args(); that is, basic types and arrays of + * fixed-length basic types. The arguments are the same as they would + * be for dbus_message_iter_get_basic() or + * dbus_message_iter_get_fixed_array(). + * + * In addition to those types, arrays of string, object path, and + * signature are supported; but these are returned as allocated memory + * and must be freed with dbus_free_string_array(), while the other + * types are returned as const references. To get a string array + * pass in "char ***array_location" and "int *n_elements" + * + * The variable argument list should contain the type of the argument + * followed by a pointer to where the value should be stored. The list + * is terminated with #DBUS_TYPE_INVALID. + * + * Except for string arrays, the returned values are constant; do not + * free them. They point into the #DBusMessage. + * + * If the requested arguments are not present, or do not have the + * requested types, then an error will be set. + * + * If more arguments than requested are present, the requested + * arguments are returned and the extra arguments are ignored. + * + * @todo support DBUS_TYPE_STRUCT and DBUS_TYPE_VARIANT and complex arrays + * + * @param message the message + * @param error error to be filled in on failure + * @param first_arg_type the first argument type + * @param ... location for first argument value, then list of type-location pairs + * @returns #FALSE if the error was set + */ +dbus_bool_t +dbus_message_get_args (DBusMessage *message, + DBusError *error, + int first_arg_type, + ...) +{ + dbus_bool_t retval; + va_list var_args; + + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_error_is_set (error, FALSE); + + va_start (var_args, first_arg_type); + retval = dbus_message_get_args_valist (message, error, first_arg_type, var_args); + va_end (var_args); + + return retval; +} + +/** + * Like dbus_message_get_args but takes a va_list for use by language bindings. + * + * @see dbus_message_get_args + * @param message the message + * @param error error to be filled in + * @param first_arg_type type of the first argument + * @param var_args return location for first argument, followed by list of type/location pairs + * @returns #FALSE if error was set + */ +dbus_bool_t +dbus_message_get_args_valist (DBusMessage *message, + DBusError *error, + int first_arg_type, + va_list var_args) +{ + DBusMessageIter iter; + + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_error_is_set (error, FALSE); + + dbus_message_iter_init (message, &iter); + return _dbus_message_iter_get_args_valist (&iter, error, first_arg_type, var_args); +} + +static void +_dbus_message_iter_init_common (DBusMessage *message, + DBusMessageRealIter *real, + int iter_type) +{ + _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter)); + + /* Since the iterator will read or write who-knows-what from the + * message, we need to get in the right byte order + */ + ensure_byte_order (message); + + real->message = message; + real->changed_stamp = message->changed_stamp; + real->iter_type = iter_type; + real->sig_refcount = 0; +} + +/** + * Initializes a #DBusMessageIter for reading the arguments of the + * message passed in. + * + * When possible, dbus_message_get_args() is much more convenient. + * Some types of argument can only be read with #DBusMessageIter + * however. + * + * The easiest way to iterate is like this: + * @code + * dbus_message_iter_init (message, &iter); + * while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) + * dbus_message_iter_next (&iter); + * @endcode + * + * #DBusMessageIter contains no allocated memory; it need not be + * freed, and can be copied by assignment or memcpy(). + * + * @param message the message + * @param iter pointer to an iterator to initialize + * @returns #FALSE if the message has no arguments + */ +dbus_bool_t +dbus_message_iter_init (DBusMessage *message, + DBusMessageIter *iter) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + const DBusString *type_str; + int type_pos; + + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (iter != NULL, FALSE); + + get_const_signature (&message->header, &type_str, &type_pos); + + _dbus_message_iter_init_common (message, real, + DBUS_MESSAGE_ITER_TYPE_READER); + + _dbus_type_reader_init (&real->u.reader, + message->byte_order, + type_str, type_pos, + &message->body, + 0); + + return _dbus_type_reader_get_current_type (&real->u.reader) != DBUS_TYPE_INVALID; +} + +/** + * Checks if an iterator has any more fields. + * + * @param iter the message iter + * @returns #TRUE if there are more fields following + */ +dbus_bool_t +dbus_message_iter_has_next (DBusMessageIter *iter) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + + _dbus_return_val_if_fail (_dbus_message_iter_check (real), FALSE); + _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_READER, FALSE); + + return _dbus_type_reader_has_next (&real->u.reader); +} + +/** + * Moves the iterator to the next field, if any. If there's no next + * field, returns #FALSE. If the iterator moves forward, returns + * #TRUE. + * + * @param iter the message iter + * @returns #TRUE if the iterator was moved to the next field + */ +dbus_bool_t +dbus_message_iter_next (DBusMessageIter *iter) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + + _dbus_return_val_if_fail (_dbus_message_iter_check (real), FALSE); + _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_READER, FALSE); + + return _dbus_type_reader_next (&real->u.reader); +} + +/** + * Returns the argument type of the argument that the message iterator + * points to. If the iterator is at the end of the message, returns + * #DBUS_TYPE_INVALID. You can thus write a loop as follows: + * + * @code + * dbus_message_iter_init (&iter); + * while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID) + * dbus_message_iter_next (&iter); + * @endcode + * + * @param iter the message iter + * @returns the argument type + */ +int +dbus_message_iter_get_arg_type (DBusMessageIter *iter) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + + _dbus_return_val_if_fail (_dbus_message_iter_check (real), DBUS_TYPE_INVALID); + _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_READER, FALSE); + + return _dbus_type_reader_get_current_type (&real->u.reader); +} + +/** + * Returns the element type of the array that the message iterator + * points to. Note that you need to check that the iterator points to + * an array prior to using this function. + * + * @param iter the message iter + * @returns the array element type + */ +int +dbus_message_iter_get_element_type (DBusMessageIter *iter) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + + _dbus_return_val_if_fail (_dbus_message_iter_check (real), DBUS_TYPE_INVALID); + _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_READER, DBUS_TYPE_INVALID); + _dbus_return_val_if_fail (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY, DBUS_TYPE_INVALID); + + return _dbus_type_reader_get_element_type (&real->u.reader); +} + +/** + * Recurses into a container value when reading values from a message, + * initializing a sub-iterator to use for traversing the child values + * of the container. + * + * Note that this recurses into a value, not a type, so you can only + * recurse if the value exists. The main implication of this is that + * if you have for example an empty array of array of int32, you can + * recurse into the outermost array, but it will have no values, so + * you won't be able to recurse further. There's no array of int32 to + * recurse into. + * + * If a container is an array of fixed-length types, it is much more + * efficient to use dbus_message_iter_get_fixed_array() to get the + * whole array in one shot, rather than individually walking over the + * array elements. + * + * Be sure you have somehow checked that + * dbus_message_iter_get_arg_type() matches the type you are expecting + * to recurse into. Results of this function are undefined if there is + * no container to recurse into at the current iterator position. + * + * @param iter the message iterator + * @param sub the sub-iterator to initialize + */ +void +dbus_message_iter_recurse (DBusMessageIter *iter, + DBusMessageIter *sub) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub; + + _dbus_return_if_fail (_dbus_message_iter_check (real)); + _dbus_return_if_fail (sub != NULL); + + *real_sub = *real; + _dbus_type_reader_recurse (&real->u.reader, &real_sub->u.reader); +} + +/** + * Returns the current signature of a message iterator. This + * is useful primarily for dealing with variants; one can + * recurse into a variant and determine the signature of + * the variant's value. + * + * The returned string must be freed with dbus_free(). + * + * @param iter the message iterator + * @returns the contained signature, or NULL if out of memory + */ +char * +dbus_message_iter_get_signature (DBusMessageIter *iter) +{ + const DBusString *sig; + DBusString retstr; + char *ret; + int start, len; + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + + _dbus_return_val_if_fail (_dbus_message_iter_check (real), NULL); + + if (!_dbus_string_init (&retstr)) + return NULL; + + _dbus_type_reader_get_signature (&real->u.reader, &sig, + &start, &len); + if (!_dbus_string_append_len (&retstr, + _dbus_string_get_const_data (sig) + start, + len)) + return NULL; + if (!_dbus_string_steal_data (&retstr, &ret)) + return NULL; + _dbus_string_free (&retstr); + return ret; +} + +/** + * Reads a basic-typed value from the message iterator. + * Basic types are the non-containers such as integer and string. + * + * The value argument should be the address of a location to store + * the returned value. So for int32 it should be a "dbus_int32_t*" + * and for string a "const char**". The returned value is + * by reference and should not be freed. + * + * Be sure you have somehow checked that + * dbus_message_iter_get_arg_type() matches the type you are + * expecting, or you'll crash when you try to use an integer as a + * string or something. + * + * To read any container type (array, struct, dict) you will need + * to recurse into the container with dbus_message_iter_recurse(). + * If the container is an array of fixed-length values, you can + * get all the array elements at once with + * dbus_message_iter_get_fixed_array(). Otherwise, you have to + * iterate over the container's contents one value at a time. + * + * All basic-typed values are guaranteed to fit in 8 bytes. So you can + * write code like this: + * + * @code + * dbus_uint64_t value; + * int type; + * dbus_message_iter_get_basic (&read_iter, &value); + * type = dbus_message_iter_get_arg_type (&read_iter); + * dbus_message_iter_append_basic (&write_iter, type, &value); + * @endcode + * + * On some really obscure platforms dbus_uint64_t might not exist, if + * you need to worry about this you will know. dbus_uint64_t is just + * one example of a type that's large enough to hold any possible + * value, you could use a struct or char[8] instead if you like. + * + * @param iter the iterator + * @param value location to store the value + */ +void +dbus_message_iter_get_basic (DBusMessageIter *iter, + void *value) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + + _dbus_return_if_fail (_dbus_message_iter_check (real)); + _dbus_return_if_fail (value != NULL); + + _dbus_type_reader_read_basic (&real->u.reader, + value); +} + +/** + * Returns the number of bytes in the array as marshaled in the wire + * protocol. The iterator must currently be inside an array-typed + * value. + * + * This function is deprecated on the grounds that it is stupid. Why + * would you want to know how many bytes are in the array as marshaled + * in the wire protocol? For now, use the n_elements returned from + * dbus_message_iter_get_fixed_array() instead, or iterate over the + * array values and count them. + * + * @todo introduce a variant of this get_n_elements that returns + * the number of elements, though with a non-fixed array it will not + * be very efficient, so maybe it's not good. + * + * @param iter the iterator + * @returns the number of bytes in the array + */ +int +dbus_message_iter_get_array_len (DBusMessageIter *iter) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + + _dbus_return_val_if_fail (_dbus_message_iter_check (real), 0); + + return _dbus_type_reader_get_array_length (&real->u.reader); +} + +/** + * Reads a block of fixed-length values from the message iterator. + * Fixed-length values are those basic types that are not string-like, + * such as integers, bool, double. The returned block will be from the + * current position in the array until the end of the array. + * + * The message iter should be "in" the array (that is, you recurse into the + * array, and then you call dbus_message_iter_get_fixed_array() on the + * "sub-iterator" created by dbus_message_iter_recurse()). + * + * The value argument should be the address of a location to store the + * returned array. So for int32 it should be a "const dbus_int32_t**" + * The returned value is by reference and should not be freed. + * + * This function should only be used if dbus_type_is_fixed() returns + * #TRUE for the element type. + * + * If an array's elements are not fixed in size, you have to recurse + * into the array with dbus_message_iter_recurse() and read the + * elements one by one. + * + * Because the array is not copied, this function runs in constant + * time and is fast; it's much preferred over walking the entire array + * with an iterator. (However, you can always use + * dbus_message_iter_recurse(), even for fixed-length types; + * dbus_message_iter_get_fixed_array() is just an optimization.) + * + * @param iter the iterator + * @param value location to store the block + * @param n_elements number of elements in the block + */ +void +dbus_message_iter_get_fixed_array (DBusMessageIter *iter, + void *value, + int *n_elements) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + int subtype = _dbus_type_reader_get_current_type(&real->u.reader); + + _dbus_return_if_fail (_dbus_message_iter_check (real)); + _dbus_return_if_fail (value != NULL); + _dbus_return_if_fail ((subtype == DBUS_TYPE_INVALID) || + dbus_type_is_fixed (subtype)); + + _dbus_type_reader_read_fixed_multi (&real->u.reader, + value, n_elements); +} + +/** + * Initializes a #DBusMessageIter for appending arguments to the end + * of a message. + * + * @todo If appending any of the arguments fails due to lack of + * memory, the message is hosed and you have to start over building + * the whole message. + * + * @param message the message + * @param iter pointer to an iterator to initialize + */ +void +dbus_message_iter_init_append (DBusMessage *message, + DBusMessageIter *iter) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + + _dbus_return_if_fail (message != NULL); + _dbus_return_if_fail (iter != NULL); + + _dbus_message_iter_init_common (message, real, + DBUS_MESSAGE_ITER_TYPE_WRITER); + + /* We create the signature string and point iterators at it "on demand" + * when a value is actually appended. That means that init() never fails + * due to OOM. + */ + _dbus_type_writer_init_types_delayed (&real->u.writer, + message->byte_order, + &message->body, + _dbus_string_get_length (&message->body)); +} + +/** + * Creates a temporary signature string containing the current + * signature, stores it in the iterator, and points the iterator to + * the end of it. Used any time we write to the message. + * + * @param real an iterator without a type_str + * @returns #FALSE if no memory + */ +static dbus_bool_t +_dbus_message_iter_open_signature (DBusMessageRealIter *real) +{ + DBusString *str; + const DBusString *current_sig; + int current_sig_pos; + + _dbus_assert (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER); + + if (real->u.writer.type_str != NULL) + { + _dbus_assert (real->sig_refcount > 0); + real->sig_refcount += 1; + return TRUE; + } + + str = dbus_new (DBusString, 1); + if (str == NULL) + return FALSE; + + if (!_dbus_header_get_field_raw (&real->message->header, + DBUS_HEADER_FIELD_SIGNATURE, + ¤t_sig, ¤t_sig_pos)) + current_sig = NULL; + + if (current_sig) + { + int current_len; + + current_len = _dbus_string_get_byte (current_sig, current_sig_pos); + current_sig_pos += 1; /* move on to sig data */ + + if (!_dbus_string_init_preallocated (str, current_len + 4)) + { + dbus_free (str); + return FALSE; + } + + if (!_dbus_string_copy_len (current_sig, current_sig_pos, current_len, + str, 0)) + { + _dbus_string_free (str); + dbus_free (str); + return FALSE; + } + } + else + { + if (!_dbus_string_init_preallocated (str, 4)) + { + dbus_free (str); + return FALSE; + } + } + + real->sig_refcount = 1; + + _dbus_type_writer_add_types (&real->u.writer, + str, _dbus_string_get_length (str)); + return TRUE; +} + +/** + * Sets the new signature as the message signature, frees the + * signature string, and marks the iterator as not having a type_str + * anymore. Frees the signature even if it fails, so you can't + * really recover from failure. Kinda busted. + * + * @param real an iterator without a type_str + * @returns #FALSE if no memory + */ +static dbus_bool_t +_dbus_message_iter_close_signature (DBusMessageRealIter *real) +{ + DBusString *str; + const char *v_STRING; + dbus_bool_t retval; + + _dbus_assert (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER); + _dbus_assert (real->u.writer.type_str != NULL); + _dbus_assert (real->sig_refcount > 0); + + real->sig_refcount -= 1; + + if (real->sig_refcount > 0) + return TRUE; + _dbus_assert (real->sig_refcount == 0); + + retval = TRUE; + + str = real->u.writer.type_str; + + v_STRING = _dbus_string_get_const_data (str); + if (!_dbus_header_set_field_basic (&real->message->header, + DBUS_HEADER_FIELD_SIGNATURE, + DBUS_TYPE_SIGNATURE, + &v_STRING)) + retval = FALSE; + + _dbus_type_writer_remove_types (&real->u.writer); + _dbus_string_free (str); + dbus_free (str); + + return retval; +} + +/** + * Frees the signature string and marks the iterator as not having a + * type_str anymore. Since the new signature is not set, the message + * will generally be hosed after this is called. + * + * @param real an iterator without a type_str + */ +static void +_dbus_message_iter_abandon_signature (DBusMessageRealIter *real) +{ + DBusString *str; + + _dbus_assert (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER); + _dbus_assert (real->u.writer.type_str != NULL); + _dbus_assert (real->sig_refcount > 0); + + real->sig_refcount -= 1; + + if (real->sig_refcount > 0) + return; + _dbus_assert (real->sig_refcount == 0); + + str = real->u.writer.type_str; + + _dbus_type_writer_remove_types (&real->u.writer); + _dbus_string_free (str); + dbus_free (str); +} + +#ifndef DBUS_DISABLE_CHECKS +static dbus_bool_t +_dbus_message_iter_append_check (DBusMessageRealIter *iter) +{ + if (!_dbus_message_iter_check (iter)) + return FALSE; + + if (iter->message->locked) + { + _dbus_warn_check_failed ("dbus append iterator can't be used: message is locked (has already been sent)\n"); + return FALSE; + } + + return TRUE; +} +#endif /* DBUS_DISABLE_CHECKS */ + +/** + * Appends a basic-typed value to the message. The basic types are the + * non-container types such as integer and string. + * + * The "value" argument should be the address of a basic-typed value. + * So for string, const char**. For integer, dbus_int32_t*. + * + * @todo If this fails due to lack of memory, the message is hosed and + * you have to start over building the whole message. + * + * @param iter the append iterator + * @param type the type of the value + * @param value the address of the value + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_iter_append_basic (DBusMessageIter *iter, + int type, + const void *value) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + dbus_bool_t ret; + + _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); + _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); + _dbus_return_val_if_fail (dbus_type_is_basic (type), FALSE); + _dbus_return_val_if_fail (value != NULL, FALSE); + + if (!_dbus_message_iter_open_signature (real)) + return FALSE; + + ret = _dbus_type_writer_write_basic (&real->u.writer, type, value); + + if (!_dbus_message_iter_close_signature (real)) + ret = FALSE; + + return ret; +} + +/** + * Appends a block of fixed-length values to an array. The + * fixed-length types are all basic types that are not string-like. So + * int32, double, bool, etc. You must call + * dbus_message_iter_open_container() to open an array of values + * before calling this function. You may call this function multiple + * times (and intermixed with calls to + * dbus_message_iter_append_basic()) for the same array. + * + * The "value" argument should be the address of the array. So for + * integer, "dbus_int32_t**" is expected for example. + * + * @warning in C, given "int array[]", "&array == array" (the + * comp.lang.c FAQ says otherwise, but gcc and the FAQ don't agree). + * So if you're using an array instead of a pointer you have to create + * a pointer variable, assign the array to it, then take the address + * of the pointer variable. + * @code + * const dbus_int32_t array[] = { 1, 2, 3 }; + * const dbus_int32_t *v_ARRAY = array; + * if (!dbus_message_iter_append_fixed_array (&iter, DBUS_TYPE_INT32, &v_ARRAY, 3)) + * fprintf (stderr, "No memory!\n"); + * @endcode + * For strings it works to write const char *array = "Hello" and then + * use &array though. + * + * @todo If this fails due to lack of memory, the message is hosed and + * you have to start over building the whole message. + * + * @param iter the append iterator + * @param element_type the type of the array elements + * @param value the address of the array + * @param n_elements the number of elements to append + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_iter_append_fixed_array (DBusMessageIter *iter, + int element_type, + const void *value, + int n_elements) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + dbus_bool_t ret; + + _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); + _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); + _dbus_return_val_if_fail (dbus_type_is_fixed (element_type), FALSE); + _dbus_return_val_if_fail (real->u.writer.container_type == DBUS_TYPE_ARRAY, FALSE); + _dbus_return_val_if_fail (value != NULL, FALSE); + _dbus_return_val_if_fail (n_elements >= 0, FALSE); + _dbus_return_val_if_fail (n_elements <= + DBUS_MAXIMUM_ARRAY_LENGTH / _dbus_type_get_alignment (element_type), + FALSE); + + ret = _dbus_type_writer_write_fixed_multi (&real->u.writer, element_type, value, n_elements); + + return ret; +} + +/** + * Appends a container-typed value to the message; you are required to + * append the contents of the container using the returned + * sub-iterator, and then call + * dbus_message_iter_close_container(). Container types are for + * example struct, variant, and array. For variants, the + * contained_signature should be the type of the single value inside + * the variant. For structs and dict entries, contained_signature + * should be #NULL; it will be set to whatever types you write into + * the struct. For arrays, contained_signature should be the type of + * the array elements. + * + * @todo If this fails due to lack of memory, the message is hosed and + * you have to start over building the whole message. + * + * @param iter the append iterator + * @param type the type of the value + * @param contained_signature the type of container contents + * @param sub sub-iterator to initialize + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_iter_open_container (DBusMessageIter *iter, + int type, + const char *contained_signature, + DBusMessageIter *sub) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub; + DBusString contained_str; + + _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); + _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); + _dbus_return_val_if_fail (dbus_type_is_container (type), FALSE); + _dbus_return_val_if_fail (sub != NULL, FALSE); + _dbus_return_val_if_fail ((type == DBUS_TYPE_STRUCT && + contained_signature == NULL) || + (type == DBUS_TYPE_DICT_ENTRY && + contained_signature == NULL) || + (type == DBUS_TYPE_VARIANT && + contained_signature != NULL) || + (type == DBUS_TYPE_ARRAY && + contained_signature != NULL), FALSE); + + /* this would fail if the contained_signature is a dict entry, since + * dict entries are invalid signatures standalone (they must be in + * an array) + */ + _dbus_return_val_if_fail ((type == DBUS_TYPE_ARRAY && contained_signature && *contained_signature == DBUS_DICT_ENTRY_BEGIN_CHAR) || + (contained_signature == NULL || + _dbus_check_is_valid_signature (contained_signature)), + FALSE); + + if (!_dbus_message_iter_open_signature (real)) + return FALSE; + + *real_sub = *real; + + if (contained_signature != NULL) + { + _dbus_string_init_const (&contained_str, contained_signature); + + return _dbus_type_writer_recurse (&real->u.writer, + type, + &contained_str, 0, + &real_sub->u.writer); + } + else + { + return _dbus_type_writer_recurse (&real->u.writer, + type, + NULL, 0, + &real_sub->u.writer); + } +} + + +/** + * Closes a container-typed value appended to the message; may write + * out more information to the message known only after the entire + * container is written, and may free resources created by + * dbus_message_iter_open_container(). + * + * @todo If this fails due to lack of memory, the message is hosed and + * you have to start over building the whole message. + * + * @param iter the append iterator + * @param sub sub-iterator to close + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_iter_close_container (DBusMessageIter *iter, + DBusMessageIter *sub) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub; + dbus_bool_t ret; + + _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE); + _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); + _dbus_return_val_if_fail (_dbus_message_iter_append_check (real_sub), FALSE); + _dbus_return_val_if_fail (real_sub->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE); + + ret = _dbus_type_writer_unrecurse (&real->u.writer, + &real_sub->u.writer); + + if (!_dbus_message_iter_close_signature (real)) + ret = FALSE; + + return ret; +} + +/** + * Abandons creation of a contained-typed value and frees resources created + * by dbus_message_iter_open_container(). Once this returns, the message + * is hosed and you have to start over building the whole message. + * + * This should only be used to abandon creation of a message when you have + * open containers. + * + * @param iter the append iterator + * @param sub sub-iterator to close + */ +void +dbus_message_iter_abandon_container (DBusMessageIter *iter, + DBusMessageIter *sub) +{ + DBusMessageRealIter *real = (DBusMessageRealIter *)iter; + DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub; + + _dbus_return_if_fail (_dbus_message_iter_append_check (real)); + _dbus_return_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER); + _dbus_return_if_fail (_dbus_message_iter_append_check (real_sub)); + _dbus_return_if_fail (real_sub->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER); + + _dbus_message_iter_abandon_signature (real); +} + +/** + * Sets a flag indicating that the message does not want a reply; if + * this flag is set, the other end of the connection may (but is not + * required to) optimize by not sending method return or error + * replies. If this flag is set, there is no way to know whether the + * message successfully arrived at the remote end. Normally you know a + * message was received when you receive the reply to it. + * + * The flag is #FALSE by default, that is by default the other end is + * required to reply. + * + * On the protocol level this toggles #DBUS_HEADER_FLAG_NO_REPLY_EXPECTED + * + * @param message the message + * @param no_reply #TRUE if no reply is desired + */ +void +dbus_message_set_no_reply (DBusMessage *message, + dbus_bool_t no_reply) +{ + _dbus_return_if_fail (message != NULL); + _dbus_return_if_fail (!message->locked); + + _dbus_header_toggle_flag (&message->header, + DBUS_HEADER_FLAG_NO_REPLY_EXPECTED, + no_reply); +} + +/** + * Returns #TRUE if the message does not expect + * a reply. + * + * @param message the message + * @returns #TRUE if the message sender isn't waiting for a reply + */ +dbus_bool_t +dbus_message_get_no_reply (DBusMessage *message) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + + return _dbus_header_get_flag (&message->header, + DBUS_HEADER_FLAG_NO_REPLY_EXPECTED); +} + +/** + * Sets a flag indicating that an owner for the destination name will + * be automatically started before the message is delivered. When this + * flag is set, the message is held until a name owner finishes + * starting up, or fails to start up. In case of failure, the reply + * will be an error. + * + * The flag is set to #TRUE by default, i.e. auto starting is the default. + * + * On the protocol level this toggles #DBUS_HEADER_FLAG_NO_AUTO_START + * + * @param message the message + * @param auto_start #TRUE if auto-starting is desired + */ +void +dbus_message_set_auto_start (DBusMessage *message, + dbus_bool_t auto_start) +{ + _dbus_return_if_fail (message != NULL); + _dbus_return_if_fail (!message->locked); + + _dbus_header_toggle_flag (&message->header, + DBUS_HEADER_FLAG_NO_AUTO_START, + !auto_start); +} + +/** + * Returns #TRUE if the message will cause an owner for + * destination name to be auto-started. + * + * @param message the message + * @returns #TRUE if the message will use auto-start + */ +dbus_bool_t +dbus_message_get_auto_start (DBusMessage *message) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + + return !_dbus_header_get_flag (&message->header, + DBUS_HEADER_FLAG_NO_AUTO_START); +} + + +/** + * Sets the object path this message is being sent to (for + * DBUS_MESSAGE_TYPE_METHOD_CALL) or the one a signal is being + * emitted from (for DBUS_MESSAGE_TYPE_SIGNAL). + * + * The path must contain only valid characters as defined + * in the D-Bus specification. + * + * @param message the message + * @param object_path the path or #NULL to unset + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_path (DBusMessage *message, + const char *object_path) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (!message->locked, FALSE); + _dbus_return_val_if_fail (object_path == NULL || + _dbus_check_is_valid_path (object_path), + FALSE); + + return set_or_delete_string_field (message, + DBUS_HEADER_FIELD_PATH, + DBUS_TYPE_OBJECT_PATH, + object_path); +} + +/** + * Gets the object path this message is being sent to (for + * DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted from (for + * DBUS_MESSAGE_TYPE_SIGNAL). Returns #NULL if none. + * + * See also dbus_message_get_path_decomposed(). + * + * The returned string becomes invalid if the message is + * modified, since it points into the wire-marshaled message data. + * + * @param message the message + * @returns the path (should not be freed) or #NULL + */ +const char* +dbus_message_get_path (DBusMessage *message) +{ + const char *v; + + _dbus_return_val_if_fail (message != NULL, NULL); + + v = NULL; /* in case field doesn't exist */ + _dbus_header_get_field_basic (&message->header, + DBUS_HEADER_FIELD_PATH, + DBUS_TYPE_OBJECT_PATH, + &v); + return v; +} + +/** + * Checks if the message has a particular object path. The object + * path is the destination object for a method call or the emitting + * object for a signal. + * + * @param message the message + * @param path the path name + * @returns #TRUE if there is a path field in the header + */ +dbus_bool_t +dbus_message_has_path (DBusMessage *message, + const char *path) +{ + const char *msg_path; + msg_path = dbus_message_get_path (message); + + if (msg_path == NULL) + { + if (path == NULL) + return TRUE; + else + return FALSE; + } + + if (path == NULL) + return FALSE; + + if (strcmp (msg_path, path) == 0) + return TRUE; + + return FALSE; +} + +/** + * Gets the object path this message is being sent to + * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted + * from (for DBUS_MESSAGE_TYPE_SIGNAL) in a decomposed + * format (one array element per path component). + * Free the returned array with dbus_free_string_array(). + * + * An empty but non-NULL path array means the path "/". + * So the path "/foo/bar" becomes { "foo", "bar", NULL } + * and the path "/" becomes { NULL }. + * + * See also dbus_message_get_path(). + * + * @todo this could be optimized by using the len from the message + * instead of calling strlen() again + * + * @param message the message + * @param path place to store allocated array of path components; #NULL set here if no path field exists + * @returns #FALSE if no memory to allocate the array + */ +dbus_bool_t +dbus_message_get_path_decomposed (DBusMessage *message, + char ***path) +{ + const char *v; + + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (path != NULL, FALSE); + + *path = NULL; + + v = dbus_message_get_path (message); + if (v != NULL) + { + if (!_dbus_decompose_path (v, strlen (v), + path, NULL)) + return FALSE; + } + return TRUE; +} + +/** + * Sets the interface this message is being sent to + * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or + * the interface a signal is being emitted from + * (for DBUS_MESSAGE_TYPE_SIGNAL). + * + * The interface name must contain only valid characters as defined + * in the D-Bus specification. + * + * @param message the message + * @param interface the interface or #NULL to unset + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_interface (DBusMessage *message, + const char *interface) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (!message->locked, FALSE); + _dbus_return_val_if_fail (interface == NULL || + _dbus_check_is_valid_interface (interface), + FALSE); + + return set_or_delete_string_field (message, + DBUS_HEADER_FIELD_INTERFACE, + DBUS_TYPE_STRING, + interface); +} + +/** + * Gets the interface this message is being sent to + * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted + * from (for DBUS_MESSAGE_TYPE_SIGNAL). + * The interface name is fully-qualified (namespaced). + * Returns #NULL if none. + * + * The returned string becomes invalid if the message is + * modified, since it points into the wire-marshaled message data. + * + * @param message the message + * @returns the message interface (should not be freed) or #NULL + */ +const char* +dbus_message_get_interface (DBusMessage *message) +{ + const char *v; + + _dbus_return_val_if_fail (message != NULL, NULL); + + v = NULL; /* in case field doesn't exist */ + _dbus_header_get_field_basic (&message->header, + DBUS_HEADER_FIELD_INTERFACE, + DBUS_TYPE_STRING, + &v); + return v; +} + +/** + * Checks if the message has an interface + * + * @param message the message + * @param interface the interface name + * @returns #TRUE if the interface field in the header matches + */ +dbus_bool_t +dbus_message_has_interface (DBusMessage *message, + const char *interface) +{ + const char *msg_interface; + msg_interface = dbus_message_get_interface (message); + + if (msg_interface == NULL) + { + if (interface == NULL) + return TRUE; + else + return FALSE; + } + + if (interface == NULL) + return FALSE; + + if (strcmp (msg_interface, interface) == 0) + return TRUE; + + return FALSE; + +} + +/** + * Sets the interface member being invoked + * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted + * (DBUS_MESSAGE_TYPE_SIGNAL). + * + * The member name must contain only valid characters as defined + * in the D-Bus specification. + * + * @param message the message + * @param member the member or #NULL to unset + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_member (DBusMessage *message, + const char *member) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (!message->locked, FALSE); + _dbus_return_val_if_fail (member == NULL || + _dbus_check_is_valid_member (member), + FALSE); + + return set_or_delete_string_field (message, + DBUS_HEADER_FIELD_MEMBER, + DBUS_TYPE_STRING, + member); +} + +/** + * Gets the interface member being invoked + * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted + * (DBUS_MESSAGE_TYPE_SIGNAL). Returns #NULL if none. + * + * The returned string becomes invalid if the message is + * modified, since it points into the wire-marshaled message data. + * + * @param message the message + * @returns the member name (should not be freed) or #NULL + */ +const char* +dbus_message_get_member (DBusMessage *message) +{ + const char *v; + + _dbus_return_val_if_fail (message != NULL, NULL); + + v = NULL; /* in case field doesn't exist */ + _dbus_header_get_field_basic (&message->header, + DBUS_HEADER_FIELD_MEMBER, + DBUS_TYPE_STRING, + &v); + return v; +} + +/** + * Checks if the message has an interface member + * + * @param message the message + * @param member the member name + * @returns #TRUE if there is a member field in the header + */ +dbus_bool_t +dbus_message_has_member (DBusMessage *message, + const char *member) +{ + const char *msg_member; + msg_member = dbus_message_get_member (message); + + if (msg_member == NULL) + { + if (member == NULL) + return TRUE; + else + return FALSE; + } + + if (member == NULL) + return FALSE; + + if (strcmp (msg_member, member) == 0) + return TRUE; + + return FALSE; + +} + +/** + * Sets the name of the error (DBUS_MESSAGE_TYPE_ERROR). + * The name is fully-qualified (namespaced). + * + * The error name must contain only valid characters as defined + * in the D-Bus specification. + * + * @param message the message + * @param error_name the name or #NULL to unset + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_error_name (DBusMessage *message, + const char *error_name) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (!message->locked, FALSE); + _dbus_return_val_if_fail (error_name == NULL || + _dbus_check_is_valid_error_name (error_name), + FALSE); + + return set_or_delete_string_field (message, + DBUS_HEADER_FIELD_ERROR_NAME, + DBUS_TYPE_STRING, + error_name); +} + +/** + * Gets the error name (DBUS_MESSAGE_TYPE_ERROR only) + * or #NULL if none. + * + * The returned string becomes invalid if the message is + * modified, since it points into the wire-marshaled message data. + * + * @param message the message + * @returns the error name (should not be freed) or #NULL + */ +const char* +dbus_message_get_error_name (DBusMessage *message) +{ + const char *v; + + _dbus_return_val_if_fail (message != NULL, NULL); + + v = NULL; /* in case field doesn't exist */ + _dbus_header_get_field_basic (&message->header, + DBUS_HEADER_FIELD_ERROR_NAME, + DBUS_TYPE_STRING, + &v); + return v; +} + +/** + * Sets the message's destination. The destination is the name of + * another connection on the bus and may be either the unique name + * assigned by the bus to each connection, or a well-known name + * specified in advance. + * + * The destination name must contain only valid characters as defined + * in the D-Bus specification. + * + * @param message the message + * @param destination the destination name or #NULL to unset + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_destination (DBusMessage *message, + const char *destination) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (!message->locked, FALSE); + _dbus_return_val_if_fail (destination == NULL || + _dbus_check_is_valid_bus_name (destination), + FALSE); + + return set_or_delete_string_field (message, + DBUS_HEADER_FIELD_DESTINATION, + DBUS_TYPE_STRING, + destination); +} + +/** + * Gets the destination of a message or #NULL if there is none set. + * + * The returned string becomes invalid if the message is + * modified, since it points into the wire-marshaled message data. + * + * @param message the message + * @returns the message destination (should not be freed) or #NULL + */ +const char* +dbus_message_get_destination (DBusMessage *message) +{ + const char *v; + + _dbus_return_val_if_fail (message != NULL, NULL); + + v = NULL; /* in case field doesn't exist */ + _dbus_header_get_field_basic (&message->header, + DBUS_HEADER_FIELD_DESTINATION, + DBUS_TYPE_STRING, + &v); + return v; +} + +/** + * Sets the message sender. + * + * The sender must be a valid bus name as defined in the D-Bus + * specification. + * + * Usually you don't want to call this. The message bus daemon will + * call it to set the origin of each message. If you aren't implementing + * a message bus daemon you shouldn't need to set the sender. + * + * @param message the message + * @param sender the sender or #NULL to unset + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_message_set_sender (DBusMessage *message, + const char *sender) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (!message->locked, FALSE); + _dbus_return_val_if_fail (sender == NULL || + _dbus_check_is_valid_bus_name (sender), + FALSE); + + return set_or_delete_string_field (message, + DBUS_HEADER_FIELD_SENDER, + DBUS_TYPE_STRING, + sender); +} + +/** + * Gets the unique name of the connection which originated this + * message, or #NULL if unknown or inapplicable. The sender is filled + * in by the message bus. + * + * Note, the returned sender is always the unique bus name. + * Connections may own multiple other bus names, but those + * are not found in the sender field. + * + * The returned string becomes invalid if the message is + * modified, since it points into the wire-marshaled message data. + * + * @param message the message + * @returns the unique name of the sender or #NULL + */ +const char* +dbus_message_get_sender (DBusMessage *message) +{ + const char *v; + + _dbus_return_val_if_fail (message != NULL, NULL); + + v = NULL; /* in case field doesn't exist */ + _dbus_header_get_field_basic (&message->header, + DBUS_HEADER_FIELD_SENDER, + DBUS_TYPE_STRING, + &v); + return v; +} + +/** + * Gets the type signature of the message, i.e. the arguments in the + * message payload. The signature includes only "in" arguments for + * #DBUS_MESSAGE_TYPE_METHOD_CALL and only "out" arguments for + * #DBUS_MESSAGE_TYPE_METHOD_RETURN, so is slightly different from + * what you might expect (that is, it does not include the signature of the + * entire C++-style method). + * + * The signature is a string made up of type codes such as + * #DBUS_TYPE_INT32. The string is terminated with nul (nul is also + * the value of #DBUS_TYPE_INVALID). + * + * The returned string becomes invalid if the message is + * modified, since it points into the wire-marshaled message data. + * + * @param message the message + * @returns the type signature + */ +const char* +dbus_message_get_signature (DBusMessage *message) +{ + const DBusString *type_str; + int type_pos; + + _dbus_return_val_if_fail (message != NULL, NULL); + + get_const_signature (&message->header, &type_str, &type_pos); + + return _dbus_string_get_const_data_len (type_str, type_pos, 0); +} + +static dbus_bool_t +_dbus_message_has_type_interface_member (DBusMessage *message, + int type, + const char *interface, + const char *member) +{ + const char *n; + + _dbus_assert (message != NULL); + _dbus_assert (interface != NULL); + _dbus_assert (member != NULL); + + if (dbus_message_get_type (message) != type) + return FALSE; + + /* Optimize by checking the short member name first + * instead of the longer interface name + */ + + n = dbus_message_get_member (message); + + if (n && strcmp (n, member) == 0) + { + n = dbus_message_get_interface (message); + + if (n == NULL || strcmp (n, interface) == 0) + return TRUE; + } + + return FALSE; +} + +/** + * Checks whether the message is a method call with the given + * interface and member fields. If the message is not + * #DBUS_MESSAGE_TYPE_METHOD_CALL, or has a different interface or + * member field, returns #FALSE. If the interface field is missing, + * then it will be assumed equal to the provided interface. The D-Bus + * protocol allows method callers to leave out the interface name. + * + * @param message the message + * @param interface the name to check (must not be #NULL) + * @param method the name to check (must not be #NULL) + * + * @returns #TRUE if the message is the specified method call + */ +dbus_bool_t +dbus_message_is_method_call (DBusMessage *message, + const char *interface, + const char *method) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (interface != NULL, FALSE); + _dbus_return_val_if_fail (method != NULL, FALSE); + /* don't check that interface/method are valid since it would be + * expensive, and not catch many common errors + */ + + return _dbus_message_has_type_interface_member (message, + DBUS_MESSAGE_TYPE_METHOD_CALL, + interface, method); +} + +/** + * Checks whether the message is a signal with the given interface and + * member fields. If the message is not #DBUS_MESSAGE_TYPE_SIGNAL, or + * has a different interface or member field, returns #FALSE. + * + * @param message the message + * @param interface the name to check (must not be #NULL) + * @param signal_name the name to check (must not be #NULL) + * + * @returns #TRUE if the message is the specified signal + */ +dbus_bool_t +dbus_message_is_signal (DBusMessage *message, + const char *interface, + const char *signal_name) +{ + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (interface != NULL, FALSE); + _dbus_return_val_if_fail (signal_name != NULL, FALSE); + /* don't check that interface/name are valid since it would be + * expensive, and not catch many common errors + */ + + return _dbus_message_has_type_interface_member (message, + DBUS_MESSAGE_TYPE_SIGNAL, + interface, signal_name); +} + +/** + * Checks whether the message is an error reply with the given error + * name. If the message is not #DBUS_MESSAGE_TYPE_ERROR, or has a + * different name, returns #FALSE. + * + * @param message the message + * @param error_name the name to check (must not be #NULL) + * + * @returns #TRUE if the message is the specified error + */ +dbus_bool_t +dbus_message_is_error (DBusMessage *message, + const char *error_name) +{ + const char *n; + + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (error_name != NULL, FALSE); + /* don't check that error_name is valid since it would be expensive, + * and not catch many common errors + */ + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) + return FALSE; + + n = dbus_message_get_error_name (message); + + if (n && strcmp (n, error_name) == 0) + return TRUE; + else + return FALSE; +} + +/** + * Checks whether the message was sent to the given name. If the + * message has no destination specified or has a different + * destination, returns #FALSE. + * + * @param message the message + * @param name the name to check (must not be #NULL) + * + * @returns #TRUE if the message has the given destination name + */ +dbus_bool_t +dbus_message_has_destination (DBusMessage *message, + const char *name) +{ + const char *s; + + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (name != NULL, FALSE); + /* don't check that name is valid since it would be expensive, and + * not catch many common errors + */ + + s = dbus_message_get_destination (message); + + if (s && strcmp (s, name) == 0) + return TRUE; + else + return FALSE; +} + +/** + * Checks whether the message has the given unique name as its sender. + * If the message has no sender specified or has a different sender, + * returns #FALSE. Note that a peer application will always have the + * unique name of the connection as the sender. So you can't use this + * function to see whether a sender owned a well-known name. + * + * Messages from the bus itself will have #DBUS_SERVICE_DBUS + * as the sender. + * + * @param message the message + * @param name the name to check (must not be #NULL) + * + * @returns #TRUE if the message has the given sender + */ +dbus_bool_t +dbus_message_has_sender (DBusMessage *message, + const char *name) +{ + const char *s; + + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (name != NULL, FALSE); + /* don't check that name is valid since it would be expensive, and + * not catch many common errors + */ + + s = dbus_message_get_sender (message); + + if (s && strcmp (s, name) == 0) + return TRUE; + else + return FALSE; +} + +/** + * Checks whether the message has the given signature; see + * dbus_message_get_signature() for more details on what the signature + * looks like. + * + * @param message the message + * @param signature typecode array + * @returns #TRUE if message has the given signature +*/ +dbus_bool_t +dbus_message_has_signature (DBusMessage *message, + const char *signature) +{ + const char *s; + + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (signature != NULL, FALSE); + /* don't check that signature is valid since it would be expensive, + * and not catch many common errors + */ + + s = dbus_message_get_signature (message); + + if (s && strcmp (s, signature) == 0) + return TRUE; + else + return FALSE; +} + +/** + * Sets a #DBusError based on the contents of the given + * message. The error is only set if the message + * is an error message, as in #DBUS_MESSAGE_TYPE_ERROR. + * The name of the error is set to the name of the message, + * and the error message is set to the first argument + * if the argument exists and is a string. + * + * The return value indicates whether the error was set (the error is + * set if and only if the message is an error message). So you can + * check for an error reply and convert it to DBusError in one go: + * @code + * if (dbus_set_error_from_message (error, reply)) + * return error; + * else + * process reply; + * @endcode + * + * @param error the error to set + * @param message the message to set it from + * @returns #TRUE if the message had type #DBUS_MESSAGE_TYPE_ERROR + */ +dbus_bool_t +dbus_set_error_from_message (DBusError *error, + DBusMessage *message) +{ + const char *str; + + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_error_is_set (error, FALSE); + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR) + return FALSE; + + str = NULL; + dbus_message_get_args (message, NULL, + DBUS_TYPE_STRING, &str, + DBUS_TYPE_INVALID); + + dbus_set_error (error, dbus_message_get_error_name (message), + str ? "%s" : NULL, str); + + return TRUE; +} + +/** @} */ + +/** + * @addtogroup DBusMessageInternals + * + * @{ + */ + +/** + * The initial buffer size of the message loader. + * + * @todo this should be based on min header size plus some average + * body size, or something. Or rather, the min header size only, if we + * want to try to read only the header, store that in a DBusMessage, + * then read only the body and store that, etc., depends on + * how we optimize _dbus_message_loader_get_buffer() and what + * the exact message format is. + */ +#define INITIAL_LOADER_DATA_LEN 32 + +/** + * Creates a new message loader. Returns #NULL if memory can't + * be allocated. + * + * @returns new loader, or #NULL. + */ +DBusMessageLoader* +_dbus_message_loader_new (void) +{ + DBusMessageLoader *loader; + + loader = dbus_new0 (DBusMessageLoader, 1); + if (loader == NULL) + return NULL; + + loader->refcount = 1; + + loader->corrupted = FALSE; + loader->corruption_reason = DBUS_VALID; + + /* this can be configured by the app, but defaults to the protocol max */ + loader->max_message_size = DBUS_MAXIMUM_MESSAGE_LENGTH; + + if (!_dbus_string_init (&loader->data)) + { + dbus_free (loader); + return NULL; + } + + /* preallocate the buffer for speed, ignore failure */ + _dbus_string_set_length (&loader->data, INITIAL_LOADER_DATA_LEN); + _dbus_string_set_length (&loader->data, 0); + + return loader; +} + +/** + * Increments the reference count of the loader. + * + * @param loader the loader. + * @returns the loader + */ +DBusMessageLoader * +_dbus_message_loader_ref (DBusMessageLoader *loader) +{ + loader->refcount += 1; + + return loader; +} + +/** + * Decrements the reference count of the loader and finalizes the + * loader when the count reaches zero. + * + * @param loader the loader. + */ +void +_dbus_message_loader_unref (DBusMessageLoader *loader) +{ + loader->refcount -= 1; + if (loader->refcount == 0) + { + _dbus_list_foreach (&loader->messages, + (DBusForeachFunction) dbus_message_unref, + NULL); + _dbus_list_clear (&loader->messages); + _dbus_string_free (&loader->data); + dbus_free (loader); + } +} + +/** + * Gets the buffer to use for reading data from the network. Network + * data is read directly into an allocated buffer, which is then used + * in the DBusMessage, to avoid as many extra memcpy's as possible. + * The buffer must always be returned immediately using + * _dbus_message_loader_return_buffer(), even if no bytes are + * successfully read. + * + * @todo this function can be a lot more clever. For example + * it can probably always return a buffer size to read exactly + * the body of the next message, thus avoiding any memory wastage + * or reallocs. + * + * @todo we need to enforce a max length on strings in header fields. + * + * @param loader the message loader. + * @param buffer the buffer + */ +void +_dbus_message_loader_get_buffer (DBusMessageLoader *loader, + DBusString **buffer) +{ + _dbus_assert (!loader->buffer_outstanding); + + *buffer = &loader->data; + + loader->buffer_outstanding = TRUE; +} + +/** + * Returns a buffer obtained from _dbus_message_loader_get_buffer(), + * indicating to the loader how many bytes of the buffer were filled + * in. This function must always be called, even if no bytes were + * successfully read. + * + * @param loader the loader. + * @param buffer the buffer. + * @param bytes_read number of bytes that were read into the buffer. + */ +void +_dbus_message_loader_return_buffer (DBusMessageLoader *loader, + DBusString *buffer, + int bytes_read) +{ + _dbus_assert (loader->buffer_outstanding); + _dbus_assert (buffer == &loader->data); + + loader->buffer_outstanding = FALSE; +} + +/* + * FIXME when we move the header out of the buffer, that memmoves all + * buffered messages. Kind of crappy. + * + * Also we copy the header and body, which is kind of crappy. To + * avoid this, we have to allow header and body to be in a single + * memory block, which is good for messages we read and bad for + * messages we are creating. But we could move_len() the buffer into + * this single memory block, and move_len() will just swap the buffers + * if you're moving the entire buffer replacing the dest string. + * + * We could also have the message loader tell the transport how many + * bytes to read; so it would first ask for some arbitrary number like + * 256, then if the message was incomplete it would use the + * header/body len to ask for exactly the size of the message (or + * blocks the size of a typical kernel buffer for the socket). That + * way we don't get trailing bytes in the buffer that have to be + * memmoved. Though I suppose we also don't have a chance of reading a + * bunch of small messages at once, so the optimization may be stupid. + * + * Another approach would be to keep a "start" index into + * loader->data and only delete it occasionally, instead of after + * each message is loaded. + * + * load_message() returns FALSE if not enough memory OR the loader was corrupted + */ +static dbus_bool_t +load_message (DBusMessageLoader *loader, + DBusMessage *message, + int byte_order, + int fields_array_len, + int header_len, + int body_len) +{ + dbus_bool_t oom; + DBusValidity validity; + const DBusString *type_str; + int type_pos; + DBusValidationMode mode; + + mode = DBUS_VALIDATION_MODE_DATA_IS_UNTRUSTED; + + oom = FALSE; + +#if 0 + _dbus_verbose_bytes_of_string (&loader->data, 0, header_len /* + body_len */); +#endif + + /* 1. VALIDATE AND COPY OVER HEADER */ + _dbus_assert (_dbus_string_get_length (&message->header.data) == 0); + _dbus_assert ((header_len + body_len) <= _dbus_string_get_length (&loader->data)); + + if (!_dbus_header_load (&message->header, + mode, + &validity, + byte_order, + fields_array_len, + header_len, + body_len, + &loader->data, 0, + _dbus_string_get_length (&loader->data))) + { + _dbus_verbose ("Failed to load header for new message code %d\n", validity); + + /* assert here so we can catch any code that still uses DBUS_VALID to indicate + oom errors. They should use DBUS_VALIDITY_UNKNOWN_OOM_ERROR instead */ + _dbus_assert (validity != DBUS_VALID); + + if (validity == DBUS_VALIDITY_UNKNOWN_OOM_ERROR) + oom = TRUE; + else + { + loader->corrupted = TRUE; + loader->corruption_reason = validity; + } + goto failed; + } + + _dbus_assert (validity == DBUS_VALID); + + message->byte_order = byte_order; + + /* 2. VALIDATE BODY */ + if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY) + { + get_const_signature (&message->header, &type_str, &type_pos); + + /* Because the bytes_remaining arg is NULL, this validates that the + * body is the right length + */ + validity = _dbus_validate_body_with_reason (type_str, + type_pos, + byte_order, + NULL, + &loader->data, + header_len, + body_len); + if (validity != DBUS_VALID) + { + _dbus_verbose ("Failed to validate message body code %d\n", validity); + + loader->corrupted = TRUE; + loader->corruption_reason = validity; + + goto failed; + } + } + + /* 3. COPY OVER BODY AND QUEUE MESSAGE */ + + if (!_dbus_list_append (&loader->messages, message)) + { + _dbus_verbose ("Failed to append new message to loader queue\n"); + oom = TRUE; + goto failed; + } + + _dbus_assert (_dbus_string_get_length (&message->body) == 0); + _dbus_assert (_dbus_string_get_length (&loader->data) >= + (header_len + body_len)); + + if (!_dbus_string_copy_len (&loader->data, header_len, body_len, &message->body, 0)) + { + _dbus_verbose ("Failed to move body into new message\n"); + oom = TRUE; + goto failed; + } + + _dbus_string_delete (&loader->data, 0, header_len + body_len); + + /* don't waste more than 2k of memory */ + _dbus_string_compact (&loader->data, 2048); + + _dbus_assert (_dbus_string_get_length (&message->header.data) == header_len); + _dbus_assert (_dbus_string_get_length (&message->body) == body_len); + + _dbus_verbose ("Loaded message %p\n", message); + + _dbus_assert (!oom); + _dbus_assert (!loader->corrupted); + _dbus_assert (loader->messages != NULL); + _dbus_assert (_dbus_list_find_last (&loader->messages, message) != NULL); + + return TRUE; + + failed: + + /* Clean up */ + + /* does nothing if the message isn't in the list */ + _dbus_list_remove_last (&loader->messages, message); + + if (oom) + _dbus_assert (!loader->corrupted); + else + _dbus_assert (loader->corrupted); + + _dbus_verbose_bytes_of_string (&loader->data, 0, _dbus_string_get_length (&loader->data)); + + return FALSE; +} + +/** + * Converts buffered data into messages, if we have enough data. If + * we don't have enough data, does nothing. + * + * @todo we need to check that the proper named header fields exist + * for each message type. + * + * @todo If a message has unknown type, we should probably eat it + * right here rather than passing it out to applications. However + * it's not an error to see messages of unknown type. + * + * @param loader the loader. + * @returns #TRUE if we had enough memory to finish. + */ +dbus_bool_t +_dbus_message_loader_queue_messages (DBusMessageLoader *loader) +{ + while (!loader->corrupted && + _dbus_string_get_length (&loader->data) >= DBUS_MINIMUM_HEADER_SIZE) + { + DBusValidity validity; + int byte_order, fields_array_len, header_len, body_len; + + if (_dbus_header_have_message_untrusted (loader->max_message_size, + &validity, + &byte_order, + &fields_array_len, + &header_len, + &body_len, + &loader->data, 0, + _dbus_string_get_length (&loader->data))) + { + DBusMessage *message; + + _dbus_assert (validity == DBUS_VALID); + + message = dbus_message_new_empty_header (); + if (message == NULL) + return FALSE; + + if (!load_message (loader, message, + byte_order, fields_array_len, + header_len, body_len)) + { + dbus_message_unref (message); + /* load_message() returns false if corrupted or OOM; if + * corrupted then return TRUE for not OOM + */ + return loader->corrupted; + } + + _dbus_assert (loader->messages != NULL); + _dbus_assert (_dbus_list_find_last (&loader->messages, message) != NULL); + } + else + { + _dbus_verbose ("Initial peek at header says we don't have a whole message yet, or data broken with invalid code %d\n", + validity); + if (validity != DBUS_VALID) + { + loader->corrupted = TRUE; + loader->corruption_reason = validity; + } + return TRUE; + } + } + + return TRUE; +} + +/** + * Peeks at first loaded message, returns #NULL if no messages have + * been queued. + * + * @param loader the loader. + * @returns the next message, or #NULL if none. + */ +DBusMessage* +_dbus_message_loader_peek_message (DBusMessageLoader *loader) +{ + if (loader->messages) + return loader->messages->data; + else + return NULL; +} + +/** + * Pops a loaded message (passing ownership of the message + * to the caller). Returns #NULL if no messages have been + * queued. + * + * @param loader the loader. + * @returns the next message, or #NULL if none. + */ +DBusMessage* +_dbus_message_loader_pop_message (DBusMessageLoader *loader) +{ + return _dbus_list_pop_first (&loader->messages); +} + +/** + * Pops a loaded message inside a list link (passing ownership of the + * message and link to the caller). Returns #NULL if no messages have + * been loaded. + * + * @param loader the loader. + * @returns the next message link, or #NULL if none. + */ +DBusList* +_dbus_message_loader_pop_message_link (DBusMessageLoader *loader) +{ + return _dbus_list_pop_first_link (&loader->messages); +} + +/** + * Returns a popped message link, used to undo a pop. + * + * @param loader the loader + * @param link the link with a message in it + */ +void +_dbus_message_loader_putback_message_link (DBusMessageLoader *loader, + DBusList *link) +{ + _dbus_list_prepend_link (&loader->messages, link); +} + +/** + * Checks whether the loader is confused due to bad data. + * If messages are received that are invalid, the + * loader gets confused and gives up permanently. + * This state is called "corrupted." + * + * @param loader the loader + * @returns #TRUE if the loader is hosed. + */ +dbus_bool_t +_dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader) +{ + _dbus_assert ((loader->corrupted && loader->corruption_reason != DBUS_VALID) || + (!loader->corrupted && loader->corruption_reason == DBUS_VALID)); + return loader->corrupted; +} + +/** + * Checks what kind of bad data confused the loader. + * + * @param loader the loader + * @returns why the loader is hosed, or DBUS_VALID if it isn't. + */ +DBusValidity +_dbus_message_loader_get_corruption_reason (DBusMessageLoader *loader) +{ + _dbus_assert ((loader->corrupted && loader->corruption_reason != DBUS_VALID) || + (!loader->corrupted && loader->corruption_reason == DBUS_VALID)); + + return loader->corruption_reason; +} + +/** + * Sets the maximum size message we allow. + * + * @param loader the loader + * @param size the max message size in bytes + */ +void +_dbus_message_loader_set_max_message_size (DBusMessageLoader *loader, + long size) +{ + if (size > DBUS_MAXIMUM_MESSAGE_LENGTH) + { + _dbus_verbose ("clamping requested max message size %ld to %d\n", + size, DBUS_MAXIMUM_MESSAGE_LENGTH); + size = DBUS_MAXIMUM_MESSAGE_LENGTH; + } + loader->max_message_size = size; +} + +/** + * Gets the maximum allowed message size in bytes. + * + * @param loader the loader + * @returns max size in bytes + */ +long +_dbus_message_loader_get_max_message_size (DBusMessageLoader *loader) +{ + return loader->max_message_size; +} + +static DBusDataSlotAllocator slot_allocator; +_DBUS_DEFINE_GLOBAL_LOCK (message_slots); + +/** + * Allocates an integer ID to be used for storing application-specific + * data on any DBusMessage. The allocated ID may then be used + * with dbus_message_set_data() and dbus_message_get_data(). + * The passed-in slot must be initialized to -1, and is filled in + * with the slot ID. If the passed-in slot is not -1, it's assumed + * to be already allocated, and its refcount is incremented. + * + * The allocated slot is global, i.e. all DBusMessage objects will + * have a slot with the given integer ID reserved. + * + * @param slot_p address of a global variable storing the slot + * @returns #FALSE on failure (no memory) + */ +dbus_bool_t +dbus_message_allocate_data_slot (dbus_int32_t *slot_p) +{ + return _dbus_data_slot_allocator_alloc (&slot_allocator, + &_DBUS_LOCK_NAME (message_slots), + slot_p); +} + +/** + * Deallocates a global ID for message data slots. + * dbus_message_get_data() and dbus_message_set_data() may no + * longer be used with this slot. Existing data stored on existing + * DBusMessage objects will be freed when the message is + * finalized, but may not be retrieved (and may only be replaced if + * someone else reallocates the slot). When the refcount on the + * passed-in slot reaches 0, it is set to -1. + * + * @param slot_p address storing the slot to deallocate + */ +void +dbus_message_free_data_slot (dbus_int32_t *slot_p) +{ + _dbus_return_if_fail (*slot_p >= 0); + + _dbus_data_slot_allocator_free (&slot_allocator, slot_p); +} + +/** + * Stores a pointer on a DBusMessage, along + * with an optional function to be used for freeing + * the data when the data is set again, or when + * the message is finalized. The slot number + * must have been allocated with dbus_message_allocate_data_slot(). + * + * @param message the message + * @param slot the slot number + * @param data the data to store + * @param free_data_func finalizer function for the data + * @returns #TRUE if there was enough memory to store the data + */ +dbus_bool_t +dbus_message_set_data (DBusMessage *message, + dbus_int32_t slot, + void *data, + DBusFreeFunction free_data_func) +{ + DBusFreeFunction old_free_func; + void *old_data; + dbus_bool_t retval; + + _dbus_return_val_if_fail (message != NULL, FALSE); + _dbus_return_val_if_fail (slot >= 0, FALSE); + + retval = _dbus_data_slot_list_set (&slot_allocator, + &message->slot_list, + slot, data, free_data_func, + &old_free_func, &old_data); + + if (retval) + { + /* Do the actual free outside the message lock */ + if (old_free_func) + (* old_free_func) (old_data); + } + + return retval; +} + +/** + * Retrieves data previously set with dbus_message_set_data(). + * The slot must still be allocated (must not have been freed). + * + * @param message the message + * @param slot the slot to get data from + * @returns the data, or #NULL if not found + */ +void* +dbus_message_get_data (DBusMessage *message, + dbus_int32_t slot) +{ + void *res; + + _dbus_return_val_if_fail (message != NULL, NULL); + + res = _dbus_data_slot_list_get (&slot_allocator, + &message->slot_list, + slot); + + return res; +} + +/** + * Utility function to convert a machine-readable (not translated) + * string into a D-Bus message type. + * + * @code + * "method_call" -> DBUS_MESSAGE_TYPE_METHOD_CALL + * "method_return" -> DBUS_MESSAGE_TYPE_METHOD_RETURN + * "signal" -> DBUS_MESSAGE_TYPE_SIGNAL + * "error" -> DBUS_MESSAGE_TYPE_ERROR + * anything else -> DBUS_MESSAGE_TYPE_INVALID + * @endcode + * + */ +int +dbus_message_type_from_string (const char *type_str) +{ + if (strcmp (type_str, "method_call") == 0) + return DBUS_MESSAGE_TYPE_METHOD_CALL; + if (strcmp (type_str, "method_return") == 0) + return DBUS_MESSAGE_TYPE_METHOD_RETURN; + else if (strcmp (type_str, "signal") == 0) + return DBUS_MESSAGE_TYPE_SIGNAL; + else if (strcmp (type_str, "error") == 0) + return DBUS_MESSAGE_TYPE_ERROR; + else + return DBUS_MESSAGE_TYPE_INVALID; +} + +/** + * Utility function to convert a D-Bus message type into a + * machine-readable string (not translated). + * + * @code + * DBUS_MESSAGE_TYPE_METHOD_CALL -> "method_call" + * DBUS_MESSAGE_TYPE_METHOD_RETURN -> "method_return" + * DBUS_MESSAGE_TYPE_SIGNAL -> "signal" + * DBUS_MESSAGE_TYPE_ERROR -> "error" + * DBUS_MESSAGE_TYPE_INVALID -> "invalid" + * @endcode + * + */ +const char * +dbus_message_type_to_string (int type) +{ + switch (type) + { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + return "method_call"; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + return "method_return"; + case DBUS_MESSAGE_TYPE_SIGNAL: + return "signal"; + case DBUS_MESSAGE_TYPE_ERROR: + return "error"; + default: + return "invalid"; + } +} + +/** + * Turn a DBusMessage into the marshalled form as described in the D-Bus + * specification. + * + * Generally, this function is only useful for encapsulating D-Bus messages in + * a different protocol. + * + * @param msg the DBusMessage + * @param marshalled_data_p the location to save the marshalled form to + * @param len_p the location to save the length of the marshalled form to + * @returns #FALSE if there was not enough memory + */ +dbus_bool_t +dbus_message_marshal (DBusMessage *msg, + char **marshalled_data_p, + int *len_p) +{ + DBusString tmp; + dbus_bool_t was_locked; + + _dbus_return_val_if_fail (msg != NULL, FALSE); + _dbus_return_val_if_fail (marshalled_data_p != NULL, FALSE); + _dbus_return_val_if_fail (len_p != NULL, FALSE); + + if (!_dbus_string_init (&tmp)) + return FALSE; + + /* Ensure the message is locked, to ensure the length header is filled in. */ + was_locked = msg->locked; + + if (!was_locked) + dbus_message_lock (msg); + + if (!_dbus_string_copy (&(msg->header.data), 0, &tmp, 0)) + goto fail; + + *len_p = _dbus_string_get_length (&tmp); + + if (!_dbus_string_copy (&(msg->body), 0, &tmp, *len_p)) + goto fail; + + *len_p = _dbus_string_get_length (&tmp); + + if (!_dbus_string_steal_data (&tmp, marshalled_data_p)) + goto fail; + + _dbus_string_free (&tmp); + + if (!was_locked) + msg->locked = FALSE; + + return TRUE; + + fail: + _dbus_string_free (&tmp); + + if (!was_locked) + msg->locked = FALSE; + + return FALSE; +} + +/** + * Demarshal a D-Bus message from the format described in the D-Bus + * specification. + * + * Generally, this function is only useful for encapsulating D-Bus messages in + * a different protocol. + * + * @param str the marshalled DBusMessage + * @param len the length of str + * @param error the location to save errors to + * @returns #NULL if there was an error + */ +DBusMessage * +dbus_message_demarshal (const char *str, + int len, + DBusError *error) +{ + DBusMessageLoader *loader; + DBusString *buffer; + DBusMessage *msg; + + _dbus_return_val_if_fail (str != NULL, NULL); + + loader = _dbus_message_loader_new (); + + if (loader == NULL) + return NULL; + + _dbus_message_loader_get_buffer (loader, &buffer); + _dbus_string_append_len (buffer, str, len); + _dbus_message_loader_return_buffer (loader, buffer, len); + + if (!_dbus_message_loader_queue_messages (loader)) + goto fail_oom; + + if (_dbus_message_loader_get_is_corrupted (loader)) + goto fail_corrupt; + + msg = _dbus_message_loader_pop_message (loader); + + if (!msg) + goto fail_oom; + + _dbus_message_loader_unref (loader); + return msg; + + fail_corrupt: + dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Message is corrupted (%s)", + _dbus_validity_to_error_message (loader->corruption_reason)); + _dbus_message_loader_unref (loader); + return NULL; + + fail_oom: + _DBUS_SET_OOM (error); + _dbus_message_loader_unref (loader); + return NULL; +} + +/** + * Returns the number of bytes required to be in the buffer to demarshal a + * D-Bus message. + * + * Generally, this function is only useful for encapsulating D-Bus messages in + * a different protocol. + * + * @param str data to be marshalled + * @param len the length of str + * @param error the location to save errors to + * @returns -1 if there was no valid data to be demarshalled, 0 if there wasn't enough data to determine how much should be demarshalled. Otherwise returns the number of bytes to be demarshalled + * + */ +int +dbus_message_demarshal_bytes_needed(const char *buf, + int len) +{ + DBusString str; + int byte_order, fields_array_len, header_len, body_len; + DBusValidity validity = DBUS_VALID; + int have_message; + + if (!buf || len < DBUS_MINIMUM_HEADER_SIZE) + return 0; + + if (len > DBUS_MAXIMUM_MESSAGE_LENGTH) + len = DBUS_MAXIMUM_MESSAGE_LENGTH; + _dbus_string_init_const_len (&str, buf, len); + + validity = DBUS_VALID; + have_message + = _dbus_header_have_message_untrusted(DBUS_MAXIMUM_MESSAGE_LENGTH, + &validity, &byte_order, + &fields_array_len, + &header_len, + &body_len, + &str, 0, + len); + _dbus_string_free (&str); + + if (validity == DBUS_VALID) + { + _dbus_assert(have_message); + return header_len + body_len; + } + else + { + return -1; /* broken! */ + } +} + +/** @} */ + +/* tests in dbus-message-util.c */ diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h new file mode 100644 index 00000000..682e5a05 --- /dev/null +++ b/dbus/dbus-message.h @@ -0,0 +1,235 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-message.h DBusMessage object + * + * Copyright (C) 2002, 2003, 2005 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_MESSAGE_H +#define DBUS_MESSAGE_H + +#include +#include +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusMessage + * @{ + */ + +typedef struct DBusMessage DBusMessage; +/** Opaque type representing a message iterator. Can be copied by value, and contains no allocated memory so never needs to be freed and can be allocated on the stack. */ +typedef struct DBusMessageIter DBusMessageIter; + +/** + * DBusMessageIter struct; contains no public fields. + */ +struct DBusMessageIter +{ + void *dummy1; /**< Don't use this */ + void *dummy2; /**< Don't use this */ + dbus_uint32_t dummy3; /**< Don't use this */ + int dummy4; /**< Don't use this */ + int dummy5; /**< Don't use this */ + int dummy6; /**< Don't use this */ + int dummy7; /**< Don't use this */ + int dummy8; /**< Don't use this */ + int dummy9; /**< Don't use this */ + int dummy10; /**< Don't use this */ + int dummy11; /**< Don't use this */ + int pad1; /**< Don't use this */ + int pad2; /**< Don't use this */ + void *pad3; /**< Don't use this */ +}; + +DBusMessage* dbus_message_new (int message_type); +DBusMessage* dbus_message_new_method_call (const char *bus_name, + const char *path, + const char *interface, + const char *method); +DBusMessage* dbus_message_new_method_return (DBusMessage *method_call); +DBusMessage* dbus_message_new_signal (const char *path, + const char *interface, + const char *name); +DBusMessage* dbus_message_new_error (DBusMessage *reply_to, + const char *error_name, + const char *error_message); +DBusMessage* dbus_message_new_error_printf (DBusMessage *reply_to, + const char *error_name, + const char *error_format, + ...); + +DBusMessage* dbus_message_copy (const DBusMessage *message); + +DBusMessage* dbus_message_ref (DBusMessage *message); +void dbus_message_unref (DBusMessage *message); +int dbus_message_get_type (DBusMessage *message); +dbus_bool_t dbus_message_set_path (DBusMessage *message, + const char *object_path); +const char* dbus_message_get_path (DBusMessage *message); +dbus_bool_t dbus_message_has_path (DBusMessage *message, + const char *object_path); +dbus_bool_t dbus_message_set_interface (DBusMessage *message, + const char *interface); +const char* dbus_message_get_interface (DBusMessage *message); +dbus_bool_t dbus_message_has_interface (DBusMessage *message, + const char *interface); +dbus_bool_t dbus_message_set_member (DBusMessage *message, + const char *member); +const char* dbus_message_get_member (DBusMessage *message); +dbus_bool_t dbus_message_has_member (DBusMessage *message, + const char *member); +dbus_bool_t dbus_message_set_error_name (DBusMessage *message, + const char *name); +const char* dbus_message_get_error_name (DBusMessage *message); +dbus_bool_t dbus_message_set_destination (DBusMessage *message, + const char *destination); +const char* dbus_message_get_destination (DBusMessage *message); +dbus_bool_t dbus_message_set_sender (DBusMessage *message, + const char *sender); +const char* dbus_message_get_sender (DBusMessage *message); +const char* dbus_message_get_signature (DBusMessage *message); +void dbus_message_set_no_reply (DBusMessage *message, + dbus_bool_t no_reply); +dbus_bool_t dbus_message_get_no_reply (DBusMessage *message); +dbus_bool_t dbus_message_is_method_call (DBusMessage *message, + const char *interface, + const char *method); +dbus_bool_t dbus_message_is_signal (DBusMessage *message, + const char *interface, + const char *signal_name); +dbus_bool_t dbus_message_is_error (DBusMessage *message, + const char *error_name); +dbus_bool_t dbus_message_has_destination (DBusMessage *message, + const char *bus_name); +dbus_bool_t dbus_message_has_sender (DBusMessage *message, + const char *unique_bus_name); +dbus_bool_t dbus_message_has_signature (DBusMessage *message, + const char *signature); +dbus_uint32_t dbus_message_get_serial (DBusMessage *message); +void dbus_message_set_serial (DBusMessage *message, + dbus_uint32_t serial); +dbus_bool_t dbus_message_set_reply_serial (DBusMessage *message, + dbus_uint32_t reply_serial); +dbus_uint32_t dbus_message_get_reply_serial (DBusMessage *message); + +void dbus_message_set_auto_start (DBusMessage *message, + dbus_bool_t auto_start); +dbus_bool_t dbus_message_get_auto_start (DBusMessage *message); + +dbus_bool_t dbus_message_get_path_decomposed (DBusMessage *message, + char ***path); + +dbus_bool_t dbus_message_append_args (DBusMessage *message, + int first_arg_type, + ...); +dbus_bool_t dbus_message_append_args_valist (DBusMessage *message, + int first_arg_type, + va_list var_args); +dbus_bool_t dbus_message_get_args (DBusMessage *message, + DBusError *error, + int first_arg_type, + ...); +dbus_bool_t dbus_message_get_args_valist (DBusMessage *message, + DBusError *error, + int first_arg_type, + va_list var_args); + + +dbus_bool_t dbus_message_iter_init (DBusMessage *message, + DBusMessageIter *iter); +dbus_bool_t dbus_message_iter_has_next (DBusMessageIter *iter); +dbus_bool_t dbus_message_iter_next (DBusMessageIter *iter); +char* dbus_message_iter_get_signature (DBusMessageIter *iter); +int dbus_message_iter_get_arg_type (DBusMessageIter *iter); +int dbus_message_iter_get_element_type (DBusMessageIter *iter); +void dbus_message_iter_recurse (DBusMessageIter *iter, + DBusMessageIter *sub); +void dbus_message_iter_get_basic (DBusMessageIter *iter, + void *value); +#ifndef DBUS_DISABLE_DEPRECATED +/* This function returns the wire protocol size of the array in bytes, + * you do not want to know that probably + */ +DBUS_DEPRECATED int dbus_message_iter_get_array_len (DBusMessageIter *iter); +#endif +void dbus_message_iter_get_fixed_array (DBusMessageIter *iter, + void *value, + int *n_elements); + + +void dbus_message_iter_init_append (DBusMessage *message, + DBusMessageIter *iter); +dbus_bool_t dbus_message_iter_append_basic (DBusMessageIter *iter, + int type, + const void *value); +dbus_bool_t dbus_message_iter_append_fixed_array (DBusMessageIter *iter, + int element_type, + const void *value, + int n_elements); +dbus_bool_t dbus_message_iter_open_container (DBusMessageIter *iter, + int type, + const char *contained_signature, + DBusMessageIter *sub); +dbus_bool_t dbus_message_iter_close_container (DBusMessageIter *iter, + DBusMessageIter *sub); +void dbus_message_iter_abandon_container (DBusMessageIter *iter, + DBusMessageIter *sub); + +void dbus_message_lock (DBusMessage *message); + +dbus_bool_t dbus_set_error_from_message (DBusError *error, + DBusMessage *message); + + +dbus_bool_t dbus_message_allocate_data_slot (dbus_int32_t *slot_p); +void dbus_message_free_data_slot (dbus_int32_t *slot_p); +dbus_bool_t dbus_message_set_data (DBusMessage *message, + dbus_int32_t slot, + void *data, + DBusFreeFunction free_data_func); +void* dbus_message_get_data (DBusMessage *message, + dbus_int32_t slot); + +int dbus_message_type_from_string (const char *type_str); +const char* dbus_message_type_to_string (int type); + +dbus_bool_t dbus_message_marshal (DBusMessage *msg, + char **marshalled_data_p, + int *len_p); +DBusMessage* dbus_message_demarshal (const char *str, + int len, + DBusError *error); + +int dbus_message_demarshal_bytes_needed (const char *str, + int len); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_MESSAGE_H */ diff --git a/dbus/dbus-misc.c b/dbus/dbus-misc.c new file mode 100644 index 00000000..b1610133 --- /dev/null +++ b/dbus/dbus-misc.c @@ -0,0 +1,248 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-misc.c A few assorted public functions that don't fit elsewhere + * + * Copyright (C) 2006 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include "dbus-misc.h" +#include "dbus-internals.h" +#include "dbus-string.h" + +/** + * @defgroup DBusMisc Miscellaneous + * @ingroup DBus + * @brief Miscellaneous API that doesn't cleanly fit anywhere else + * + * @{ + */ + +/** + * Obtains the machine UUID of the machine this process is running on. + * + * The returned string must be freed with dbus_free(). + * + * This UUID is guaranteed to remain the same until the next reboot + * (unless the sysadmin foolishly changes it and screws themselves). + * It will usually remain the same across reboots also, but hardware + * configuration changes or rebuilding the machine could break that. + * + * The idea is that two processes with the same machine ID should be + * able to use shared memory, UNIX domain sockets, process IDs, and other + * features of the OS that require both processes to be running + * on the same OS kernel instance. + * + * The machine ID can also be used to create unique per-machine + * instances. For example, you could use it in bus names or + * X selection names. + * + * The machine ID is preferred over the machine hostname, because + * the hostname is frequently set to "localhost.localdomain" and + * may also change at runtime. + * + * You can get the machine ID of a remote application by invoking the + * method GetMachineId from interface org.freedesktop.DBus.Peer. + * + * If the remote application has the same machine ID as the one + * returned by this function, then the remote application is on the + * same machine as your application. + * + * The UUID is not a UUID in the sense of RFC4122; the details + * are explained in the D-Bus specification. + * + * @returns a 32-byte-long hex-encoded UUID string, or #NULL if insufficient memory + */ +char* +dbus_get_local_machine_id (void) +{ + DBusString uuid; + char *s; + + s = NULL; + + if (!_dbus_string_init (&uuid)) + return NULL; + + if (!_dbus_get_local_machine_uuid_encoded (&uuid) || + !_dbus_string_steal_data (&uuid, &s)) + { + _dbus_string_free (&uuid); + return NULL; + } + else + { + _dbus_string_free (&uuid); + return s; + } + +} + +/** + * @def DBUS_MAJOR_VERSION + * + * The COMPILE TIME major version of libdbus, that is, the "X" in "X.Y.Z", + * as an integer literal. Consider carefully whether to use this or the + * runtime version from dbus_get_version(). + */ + +/** + * @def DBUS_MINOR_VERSION + * + * The COMPILE TIME minor version of libdbus, that is, the "Y" in "X.Y.Z", + * as an integer literal. Consider carefully whether to use this or the + * runtime version from dbus_get_version(). + */ + +/** + * @def DBUS_MICRO_VERSION + * + * The COMPILE TIME micro version of libdbus, that is, the "Z" in "X.Y.Z", + * as an integer literal. Consider carefully whether to use this or the + * runtime version from dbus_get_version(). + */ + +/** + * @def DBUS_VERSION + * + * The COMPILE TIME version of libdbus, as a single integer that has 0 in the most + * significant byte, the major version in the next most significant byte, + * the minor version in the third most significant, and the micro version in the + * least significant byte. This means two DBUS_VERSION can be compared to see + * which is higher. + * + * Consider carefully whether to use this or the runtime version from + * dbus_get_version(). + */ + +/** + * @def DBUS_VERSION_STRING + * + * The COMPILE TIME version of libdbus, as a string "X.Y.Z". + * + * Consider carefully whether to use this or the runtime version from + * dbus_get_version(). + */ + +/** + * Gets the DYNAMICALLY LINKED version of libdbus. Alternatively, there + * are macros #DBUS_MAJOR_VERSION, #DBUS_MINOR_VERSION, #DBUS_MICRO_VERSION, + * and #DBUS_VERSION which allow you to test the VERSION YOU ARE COMPILED AGAINST. + * In other words, you can get either the runtime or the compile-time version. + * Think carefully about which of these you want in a given case. + * + * The libdbus full version number is "MAJOR.MINOR.MICRO" where the + * MINOR changes if API is added, and the MICRO changes with each + * release of a MAJOR.MINOR series. The MINOR is an odd number for + * development releases and an even number for stable releases. + * + * @param major_version_p pointer to return the major version, or #NULL + * @param minor_version_p pointer to return the minor version, or #NULL + * @param micro_version_p pointer to return the micro version, or #NULL + * + */ +void +dbus_get_version (int *major_version_p, + int *minor_version_p, + int *micro_version_p) +{ + if (major_version_p) + *major_version_p = DBUS_MAJOR_VERSION; + if (minor_version_p) + *minor_version_p = DBUS_MINOR_VERSION; + if (micro_version_p) + *micro_version_p = DBUS_MICRO_VERSION; +} + + +/** @} */ /* End of public API */ + +#ifdef DBUS_BUILD_TESTS + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#include "dbus-test.h" +#include + + +dbus_bool_t +_dbus_misc_test (void) +{ + int major, minor, micro; + DBusString str; + + /* make sure we don't crash on NULL */ + dbus_get_version (NULL, NULL, NULL); + + /* Now verify that all the compile-time version stuff + * is right and matches the runtime. These tests + * are mostly intended to catch various kinds of + * typo (mixing up major and minor, that sort of thing). + */ + dbus_get_version (&major, &minor, µ); + + _dbus_assert (major == DBUS_MAJOR_VERSION); + _dbus_assert (minor == DBUS_MINOR_VERSION); + _dbus_assert (micro == DBUS_MICRO_VERSION); + +#define MAKE_VERSION(x, y, z) (((x) << 16) | ((y) << 8) | (z)) + + /* check that MAKE_VERSION works and produces the intended ordering */ + _dbus_assert (MAKE_VERSION (1, 0, 0) > MAKE_VERSION (0, 0, 0)); + _dbus_assert (MAKE_VERSION (1, 1, 0) > MAKE_VERSION (1, 0, 0)); + _dbus_assert (MAKE_VERSION (1, 1, 1) > MAKE_VERSION (1, 1, 0)); + + _dbus_assert (MAKE_VERSION (2, 0, 0) > MAKE_VERSION (1, 1, 1)); + _dbus_assert (MAKE_VERSION (2, 1, 0) > MAKE_VERSION (1, 1, 1)); + _dbus_assert (MAKE_VERSION (2, 1, 1) > MAKE_VERSION (1, 1, 1)); + + /* check DBUS_VERSION */ + _dbus_assert (MAKE_VERSION (major, minor, micro) == DBUS_VERSION); + + /* check that ordering works with DBUS_VERSION */ + _dbus_assert (MAKE_VERSION (major - 1, minor, micro) < DBUS_VERSION); + _dbus_assert (MAKE_VERSION (major, minor - 1, micro) < DBUS_VERSION); + _dbus_assert (MAKE_VERSION (major, minor, micro - 1) < DBUS_VERSION); + + _dbus_assert (MAKE_VERSION (major + 1, minor, micro) > DBUS_VERSION); + _dbus_assert (MAKE_VERSION (major, minor + 1, micro) > DBUS_VERSION); + _dbus_assert (MAKE_VERSION (major, minor, micro + 1) > DBUS_VERSION); + + /* Check DBUS_VERSION_STRING */ + + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("no memory"); + + if (!(_dbus_string_append_int (&str, major) && + _dbus_string_append_byte (&str, '.') && + _dbus_string_append_int (&str, minor) && + _dbus_string_append_byte (&str, '.') && + _dbus_string_append_int (&str, micro))) + _dbus_assert_not_reached ("no memory"); + + _dbus_assert (_dbus_string_equal_c_str (&str, DBUS_VERSION_STRING)); + + _dbus_string_free (&str); + + return TRUE; +} + +#endif /* !DOXYGEN_SHOULD_SKIP_THIS */ + +#endif diff --git a/dbus/dbus-misc.h b/dbus/dbus-misc.h new file mode 100644 index 00000000..f8cb12ff --- /dev/null +++ b/dbus/dbus-misc.h @@ -0,0 +1,51 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-misc.h A few assorted public functions that don't fit elsewhere + * + * Copyright (C) 2006 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_MISC_H +#define DBUS_MISC_H + +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusMisc + * @{ + */ + +char* dbus_get_local_machine_id (void); + +void dbus_get_version (int *major_version_p, + int *minor_version_p, + int *micro_version_p); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_MISC_H */ + diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c new file mode 100644 index 00000000..4309d154 --- /dev/null +++ b/dbus/dbus-object-tree.c @@ -0,0 +1,1949 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-object-tree.c DBusObjectTree (internals of DBusConnection) + * + * Copyright (C) 2003, 2005 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-object-tree.h" +#include "dbus-connection-internal.h" +#include "dbus-internals.h" +#include "dbus-hash.h" +#include "dbus-protocol.h" +#include "dbus-string.h" +#include +#include + +/** + * @defgroup DBusObjectTree A hierarchy of objects with container-contained relationship + * @ingroup DBusInternals + * @brief DBusObjectTree is used by DBusConnection to track the object tree + * + * Types and functions related to DBusObjectTree. These + * are all library-internal. + * + * @{ + */ + +/** Subnode of the object hierarchy */ +typedef struct DBusObjectSubtree DBusObjectSubtree; + +static DBusObjectSubtree* _dbus_object_subtree_new (const char *name, + const DBusObjectPathVTable *vtable, + void *user_data); +static DBusObjectSubtree* _dbus_object_subtree_ref (DBusObjectSubtree *subtree); +static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree); + +/** + * Internals of DBusObjectTree + */ +struct DBusObjectTree +{ + int refcount; /**< Reference count */ + DBusConnection *connection; /**< Connection this tree belongs to */ + + DBusObjectSubtree *root; /**< Root of the tree ("/" node) */ +}; + +/** + * Struct representing a single registered subtree handler, or node + * that's a parent of a registered subtree handler. If + * message_function != NULL there's actually a handler at this node. + */ +struct DBusObjectSubtree +{ + DBusAtomic refcount; /**< Reference count */ + DBusObjectSubtree *parent; /**< Parent node */ + DBusObjectPathUnregisterFunction unregister_function; /**< Function to call on unregister */ + DBusObjectPathMessageFunction message_function; /**< Function to handle messages */ + void *user_data; /**< Data for functions */ + DBusObjectSubtree **subtrees; /**< Child nodes */ + int n_subtrees; /**< Number of child nodes */ + int max_subtrees; /**< Number of allocated entries in subtrees */ + unsigned int invoke_as_fallback : 1; /**< Whether to invoke message_function when child nodes don't handle the message */ + char name[1]; /**< Allocated as large as necessary */ +}; + +/** + * Creates a new object tree, representing a mapping from paths + * to handler vtables. + * + * @param connection the connection this tree belongs to + * @returns the new tree or #NULL if no memory + */ +DBusObjectTree* +_dbus_object_tree_new (DBusConnection *connection) +{ + DBusObjectTree *tree; + + /* the connection passed in here isn't fully constructed, + * so don't do anything more than store a pointer to + * it + */ + + tree = dbus_new0 (DBusObjectTree, 1); + if (tree == NULL) + goto oom; + + tree->refcount = 1; + tree->connection = connection; + tree->root = _dbus_object_subtree_new ("/", NULL, NULL); + if (tree->root == NULL) + goto oom; + tree->root->invoke_as_fallback = TRUE; + + return tree; + + oom: + if (tree) + { + dbus_free (tree); + } + + return NULL; +} + +/** + * Increment the reference count + * @param tree the object tree + * @returns the object tree + */ +DBusObjectTree * +_dbus_object_tree_ref (DBusObjectTree *tree) +{ + _dbus_assert (tree->refcount > 0); + + tree->refcount += 1; + + return tree; +} + +/** + * Decrement the reference count + * @param tree the object tree + */ +void +_dbus_object_tree_unref (DBusObjectTree *tree) +{ + _dbus_assert (tree->refcount > 0); + + tree->refcount -= 1; + + if (tree->refcount == 0) + { + _dbus_object_tree_free_all_unlocked (tree); + + dbus_free (tree); + } +} + +/** Set to 1 to get a bunch of debug spew about finding the + * subtree nodes + */ +#define VERBOSE_FIND 0 + +static DBusObjectSubtree* +find_subtree_recurse (DBusObjectSubtree *subtree, + const char **path, + dbus_bool_t create_if_not_found, + int *index_in_parent, + dbus_bool_t *exact_match) +{ + int i, j; + dbus_bool_t return_deepest_match; + + return_deepest_match = exact_match != NULL; + + _dbus_assert (!(return_deepest_match && create_if_not_found)); + + if (path[0] == NULL) + { +#if VERBOSE_FIND + _dbus_verbose (" path exhausted, returning %s\n", + subtree->name); +#endif + if (exact_match != NULL) + *exact_match = TRUE; + return subtree; + } + +#if VERBOSE_FIND + _dbus_verbose (" searching children of %s for %s\n", + subtree->name, path[0]); +#endif + + i = 0; + j = subtree->n_subtrees; + while (i < j) + { + int k, v; + + k = (i + j) / 2; + v = strcmp (path[0], subtree->subtrees[k]->name); + +#if VERBOSE_FIND + _dbus_verbose (" %s cmp %s = %d\n", + path[0], subtree->subtrees[k]->name, + v); +#endif + + if (v == 0) + { + if (index_in_parent) + { +#if VERBOSE_FIND + _dbus_verbose (" storing parent index %d\n", k); +#endif + *index_in_parent = k; + } + + if (return_deepest_match) + { + DBusObjectSubtree *next; + + next = find_subtree_recurse (subtree->subtrees[k], + &path[1], create_if_not_found, + index_in_parent, exact_match); + if (next == NULL && + subtree->invoke_as_fallback) + { +#if VERBOSE_FIND + _dbus_verbose (" no deeper match found, returning %s\n", + subtree->name); +#endif + if (exact_match != NULL) + *exact_match = FALSE; + return subtree; + } + else + return next; + } + else + return find_subtree_recurse (subtree->subtrees[k], + &path[1], create_if_not_found, + index_in_parent, exact_match); + } + else if (v < 0) + { + j = k; + } + else + { + i = k + 1; + } + } + +#if VERBOSE_FIND + _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n", + subtree->name, create_if_not_found); +#endif + + if (create_if_not_found) + { + DBusObjectSubtree* child; + int child_pos, new_n_subtrees; + +#if VERBOSE_FIND + _dbus_verbose (" creating subtree %s\n", + path[0]); +#endif + + child = _dbus_object_subtree_new (path[0], + NULL, NULL); + if (child == NULL) + return NULL; + + new_n_subtrees = subtree->n_subtrees + 1; + if (new_n_subtrees > subtree->max_subtrees) + { + int new_max_subtrees; + DBusObjectSubtree **new_subtrees; + + new_max_subtrees = subtree->max_subtrees == 0 ? 1 : 2 * subtree->max_subtrees; + new_subtrees = dbus_realloc (subtree->subtrees, + new_max_subtrees * sizeof (DBusObjectSubtree*)); + if (new_subtrees == NULL) + { + _dbus_object_subtree_unref (child); + return NULL; + } + subtree->subtrees = new_subtrees; + subtree->max_subtrees = new_max_subtrees; + } + + /* The binary search failed, so i == j points to the + place the child should be inserted. */ + child_pos = i; + _dbus_assert (child_pos < new_n_subtrees && + new_n_subtrees <= subtree->max_subtrees); + if (child_pos + 1 < new_n_subtrees) + { + memmove (&subtree->subtrees[child_pos+1], + &subtree->subtrees[child_pos], + (new_n_subtrees - child_pos - 1) * + sizeof subtree->subtrees[0]); + } + subtree->subtrees[child_pos] = child; + + if (index_in_parent) + *index_in_parent = child_pos; + subtree->n_subtrees = new_n_subtrees; + child->parent = subtree; + + return find_subtree_recurse (child, + &path[1], create_if_not_found, + index_in_parent, exact_match); + } + else + { + if (exact_match != NULL) + *exact_match = FALSE; + return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL; + } +} + +static DBusObjectSubtree* +find_subtree (DBusObjectTree *tree, + const char **path, + int *index_in_parent) +{ + DBusObjectSubtree *subtree; + +#if VERBOSE_FIND + _dbus_verbose ("Looking for exact registered subtree\n"); +#endif + + subtree = find_subtree_recurse (tree->root, path, FALSE, index_in_parent, NULL); + + if (subtree && subtree->message_function == NULL) + return NULL; + else + return subtree; +} + +static DBusObjectSubtree* +lookup_subtree (DBusObjectTree *tree, + const char **path) +{ +#if VERBOSE_FIND + _dbus_verbose ("Looking for subtree\n"); +#endif + return find_subtree_recurse (tree->root, path, FALSE, NULL, NULL); +} + +static DBusObjectSubtree* +find_handler (DBusObjectTree *tree, + const char **path, + dbus_bool_t *exact_match) +{ +#if VERBOSE_FIND + _dbus_verbose ("Looking for deepest handler\n"); +#endif + _dbus_assert (exact_match != NULL); + + *exact_match = FALSE; /* ensure always initialized */ + + return find_subtree_recurse (tree->root, path, FALSE, NULL, exact_match); +} + +static DBusObjectSubtree* +ensure_subtree (DBusObjectTree *tree, + const char **path) +{ +#if VERBOSE_FIND + _dbus_verbose ("Ensuring subtree\n"); +#endif + return find_subtree_recurse (tree->root, path, TRUE, NULL, NULL); +} + +static char *flatten_path (const char **path); + +/** + * Registers a new subtree in the global object tree. + * + * @param tree the global object tree + * @param fallback #TRUE to handle messages to children of this path + * @param path NULL-terminated array of path elements giving path to subtree + * @param vtable the vtable used to traverse this subtree + * @param user_data user data to pass to methods in the vtable + * @param error address where an error can be returned + * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or + * #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported + */ +dbus_bool_t +_dbus_object_tree_register (DBusObjectTree *tree, + dbus_bool_t fallback, + const char **path, + const DBusObjectPathVTable *vtable, + void *user_data, + DBusError *error) +{ + DBusObjectSubtree *subtree; + + _dbus_assert (tree != NULL); + _dbus_assert (vtable->message_function != NULL); + _dbus_assert (path != NULL); + + subtree = ensure_subtree (tree, path); + if (subtree == NULL) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + if (subtree->message_function != NULL) + { + if (error != NULL) + { + char *complete_path = flatten_path (path); + + dbus_set_error (error, DBUS_ERROR_OBJECT_PATH_IN_USE, + "A handler is already registered for %s", + complete_path ? complete_path + : "(cannot represent path: out of memory!)"); + + dbus_free (complete_path); + } + + return FALSE; + } + + subtree->message_function = vtable->message_function; + subtree->unregister_function = vtable->unregister_function; + subtree->user_data = user_data; + subtree->invoke_as_fallback = fallback != FALSE; + + return TRUE; +} + +/** + * Unregisters an object subtree that was registered with the + * same path. + * + * @param tree the global object tree + * @param path path to the subtree (same as the one passed to _dbus_object_tree_register()) + */ +void +_dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, + const char **path) +{ + int i; + DBusObjectSubtree *subtree; + DBusObjectPathUnregisterFunction unregister_function; + void *user_data; + DBusConnection *connection; + + _dbus_assert (path != NULL); + + unregister_function = NULL; + user_data = NULL; + + subtree = find_subtree (tree, path, &i); + +#ifndef DBUS_DISABLE_CHECKS + if (subtree == NULL) + { + _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n", + path[0] ? path[0] : "null", + path[1] ? path[1] : "null"); + goto unlock; + } +#else + _dbus_assert (subtree != NULL); +#endif + + _dbus_assert (subtree->parent == NULL || + (i >= 0 && subtree->parent->subtrees[i] == subtree)); + + subtree->message_function = NULL; + + unregister_function = subtree->unregister_function; + user_data = subtree->user_data; + + subtree->unregister_function = NULL; + subtree->user_data = NULL; + + /* If we have no subtrees of our own, remove from + * our parent (FIXME could also be more aggressive + * and remove our parent if it becomes empty) + */ + if (subtree->parent && subtree->n_subtrees == 0) + { + /* assumes a 0-byte memmove is OK */ + memmove (&subtree->parent->subtrees[i], + &subtree->parent->subtrees[i+1], + (subtree->parent->n_subtrees - i - 1) * + sizeof (subtree->parent->subtrees[0])); + subtree->parent->n_subtrees -= 1; + + subtree->parent = NULL; + + _dbus_object_subtree_unref (subtree); + } + subtree = NULL; + +unlock: + connection = tree->connection; + + /* Unlock and call application code */ +#ifdef DBUS_BUILD_TESTS + if (connection) +#endif + { + _dbus_connection_ref_unlocked (connection); + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (connection); + } + + if (unregister_function) + (* unregister_function) (connection, user_data); + +#ifdef DBUS_BUILD_TESTS + if (connection) +#endif + dbus_connection_unref (connection); +} + +static void +free_subtree_recurse (DBusConnection *connection, + DBusObjectSubtree *subtree) +{ + /* Delete them from the end, for slightly + * more robustness against odd reentrancy. + */ + while (subtree->n_subtrees > 0) + { + DBusObjectSubtree *child; + + child = subtree->subtrees[subtree->n_subtrees - 1]; + subtree->subtrees[subtree->n_subtrees - 1] = NULL; + subtree->n_subtrees -= 1; + child->parent = NULL; + + free_subtree_recurse (connection, child); + } + + /* Call application code */ + if (subtree->unregister_function) + (* subtree->unregister_function) (connection, + subtree->user_data); + + subtree->message_function = NULL; + subtree->unregister_function = NULL; + subtree->user_data = NULL; + + /* Now free ourselves */ + _dbus_object_subtree_unref (subtree); +} + +/** + * Free all the handlers in the tree. Lock on tree's connection + * must not be held. + * + * @param tree the object tree + */ +void +_dbus_object_tree_free_all_unlocked (DBusObjectTree *tree) +{ + if (tree->root) + free_subtree_recurse (tree->connection, + tree->root); + tree->root = NULL; +} + +static dbus_bool_t +_dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree, + const char **parent_path, + char ***child_entries) +{ + DBusObjectSubtree *subtree; + char **retval; + + _dbus_assert (parent_path != NULL); + _dbus_assert (child_entries != NULL); + + *child_entries = NULL; + + subtree = lookup_subtree (tree, parent_path); + if (subtree == NULL) + { + retval = dbus_new0 (char *, 1); + } + else + { + int i; + retval = dbus_new0 (char*, subtree->n_subtrees + 1); + if (retval == NULL) + goto out; + i = 0; + while (i < subtree->n_subtrees) + { + retval[i] = _dbus_strdup (subtree->subtrees[i]->name); + if (retval[i] == NULL) + { + dbus_free_string_array (retval); + retval = NULL; + goto out; + } + ++i; + } + } + + out: + + *child_entries = retval; + return retval != NULL; +} + +static DBusHandlerResult +handle_default_introspect_and_unlock (DBusObjectTree *tree, + DBusMessage *message, + const char **path) +{ + DBusString xml; + DBusHandlerResult result; + char **children; + int i; + DBusMessage *reply; + DBusMessageIter iter; + const char *v_STRING; + dbus_bool_t already_unlocked; + + /* We have the connection lock here */ + + already_unlocked = FALSE; + + _dbus_verbose (" considering default Introspect() handler...\n"); + + reply = NULL; + + if (!dbus_message_is_method_call (message, + DBUS_INTERFACE_INTROSPECTABLE, + "Introspect")) + { +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + { + _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + _dbus_connection_unlock (tree->connection); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + _dbus_verbose (" using default Introspect() handler!\n"); + + if (!_dbus_string_init (&xml)) + { +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + { + _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + _dbus_connection_unlock (tree->connection); + } + + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + result = DBUS_HANDLER_RESULT_NEED_MEMORY; + + children = NULL; + if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children)) + goto out; + + if (!_dbus_string_append (&xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE)) + goto out; + + if (!_dbus_string_append (&xml, "\n")) + goto out; + + i = 0; + while (children[i] != NULL) + { + if (!_dbus_string_append_printf (&xml, " \n", + children[i])) + goto out; + + ++i; + } + + if (!_dbus_string_append (&xml, "\n")) + goto out; + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + goto out; + + dbus_message_iter_init_append (reply, &iter); + v_STRING = _dbus_string_get_const_data (&xml); + if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING)) + goto out; + +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + { + already_unlocked = TRUE; + + if (!_dbus_connection_send_and_unlock (tree->connection, reply, NULL)) + goto out; + } + + result = DBUS_HANDLER_RESULT_HANDLED; + + out: +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + { + if (!already_unlocked) + { + _dbus_verbose ("unlock %s %d\n", _DBUS_FUNCTION_NAME, __LINE__); + _dbus_connection_unlock (tree->connection); + } + } + + _dbus_string_free (&xml); + dbus_free_string_array (children); + if (reply) + dbus_message_unref (reply); + + return result; +} + +/** + * Tries to dispatch a message by directing it to handler for the + * object path listed in the message header, if any. Messages are + * dispatched first to the registered handler that matches the largest + * number of path elements; that is, message to /foo/bar/baz would go + * to the handler for /foo/bar before the one for /foo. + * + * @todo thread problems + * + * @param tree the global object tree + * @param message the message to dispatch + * @returns whether message was handled successfully + */ +DBusHandlerResult +_dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, + DBusMessage *message) +{ + char **path; + dbus_bool_t exact_match; + DBusList *list; + DBusList *link; + DBusHandlerResult result; + DBusObjectSubtree *subtree; + +#if 0 + _dbus_verbose ("Dispatch of message by object path\n"); +#endif + + path = NULL; + if (!dbus_message_get_path_decomposed (message, &path)) + { +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } + + _dbus_verbose ("No memory to get decomposed path\n"); + + return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + if (path == NULL) + { +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } + + _dbus_verbose ("No path field in message\n"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + /* Find the deepest path that covers the path in the message */ + subtree = find_handler (tree, (const char**) path, &exact_match); + + /* Build a list of all paths that cover the path in the message */ + + list = NULL; + + while (subtree != NULL) + { + if (subtree->message_function != NULL && (exact_match || subtree->invoke_as_fallback)) + { + _dbus_object_subtree_ref (subtree); + + /* run deepest paths first */ + if (!_dbus_list_append (&list, subtree)) + { + result = DBUS_HANDLER_RESULT_NEED_MEMORY; + _dbus_object_subtree_unref (subtree); + goto free_and_return; + } + } + + exact_match = FALSE; + subtree = subtree->parent; + } + + _dbus_verbose ("%d handlers in the path tree for this message\n", + _dbus_list_get_length (&list)); + + /* Invoke each handler in the list */ + + result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + link = _dbus_list_get_first_link (&list); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&list, link); + subtree = link->data; + + /* message_function is NULL if we're unregistered + * due to reentrancy + */ + if (subtree->message_function) + { + DBusObjectPathMessageFunction message_function; + void *user_data; + + message_function = subtree->message_function; + user_data = subtree->user_data; + +#if 0 + _dbus_verbose (" (invoking a handler)\n"); +#endif + +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } + + /* FIXME you could unregister the subtree in another thread + * before we invoke the callback, and I can't figure out a + * good way to solve this. + */ + + result = (* message_function) (tree->connection, + message, + user_data); + +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + _dbus_connection_lock (tree->connection); + + if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED) + goto free_and_return; + } + + link = next; + } + + free_and_return: + + if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED) + { + /* This hardcoded default handler does a minimal Introspect() + */ + result = handle_default_introspect_and_unlock (tree, message, + (const char**) path); + } + else + { +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } + } + + while (list != NULL) + { + link = _dbus_list_get_first_link (&list); + _dbus_object_subtree_unref (link->data); + _dbus_list_remove_link (&list, link); + } + + dbus_free_string_array (path); + + return result; +} + +/** + * Looks up the data passed to _dbus_object_tree_register() for a + * handler at the given path. + * + * @param tree the global object tree + * @param path NULL-terminated array of path elements giving path to subtree + * @returns the object's user_data or #NULL if none found + */ +void* +_dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree, + const char **path) +{ + dbus_bool_t exact_match; + DBusObjectSubtree *subtree; + + _dbus_assert (tree != NULL); + _dbus_assert (path != NULL); + + /* Find the deepest path that covers the path in the message */ + subtree = find_handler (tree, (const char**) path, &exact_match); + + if ((subtree == NULL) || !exact_match) + { + _dbus_verbose ("%s: No object at specified path found\n", + _DBUS_FUNCTION_NAME); + return NULL; + } + + return subtree->user_data; +} + +/** + * Allocates a subtree object. + * + * @param name name to duplicate. + * @returns newly-allocated subtree + */ +static DBusObjectSubtree* +allocate_subtree_object (const char *name) +{ + int len; + DBusObjectSubtree *subtree; + const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name); + + _dbus_assert (name != NULL); + + len = strlen (name); + + subtree = dbus_malloc (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree))); + + if (subtree == NULL) + return NULL; + + memcpy (subtree->name, name, len + 1); + + return subtree; +} + +static DBusObjectSubtree* +_dbus_object_subtree_new (const char *name, + const DBusObjectPathVTable *vtable, + void *user_data) +{ + DBusObjectSubtree *subtree; + + subtree = allocate_subtree_object (name); + if (subtree == NULL) + goto oom; + + _dbus_assert (name != NULL); + + subtree->parent = NULL; + + if (vtable) + { + subtree->message_function = vtable->message_function; + subtree->unregister_function = vtable->unregister_function; + } + else + { + subtree->message_function = NULL; + subtree->unregister_function = NULL; + } + + subtree->user_data = user_data; + subtree->refcount.value = 1; + subtree->subtrees = NULL; + subtree->n_subtrees = 0; + subtree->max_subtrees = 0; + subtree->invoke_as_fallback = FALSE; + + return subtree; + + oom: + return NULL; +} + +static DBusObjectSubtree * +_dbus_object_subtree_ref (DBusObjectSubtree *subtree) +{ + _dbus_assert (subtree->refcount.value > 0); + _dbus_atomic_inc (&subtree->refcount); + + return subtree; +} + +static void +_dbus_object_subtree_unref (DBusObjectSubtree *subtree) +{ + _dbus_assert (subtree->refcount.value > 0); + + if (_dbus_atomic_dec (&subtree->refcount) == 1) + { + _dbus_assert (subtree->unregister_function == NULL); + _dbus_assert (subtree->message_function == NULL); + + dbus_free (subtree->subtrees); + dbus_free (subtree); + } +} + +/** + * Lists the registered fallback handlers and object path handlers at + * the given parent_path. The returned array should be freed with + * dbus_free_string_array(). + * + * @param tree the object tree + * @param parent_path the path to list the child handlers of + * @param child_entries returns #NULL-terminated array of children + * @returns #FALSE if no memory to allocate the child entries + */ +dbus_bool_t +_dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, + const char **parent_path, + char ***child_entries) +{ + dbus_bool_t result; + + result = _dbus_object_tree_list_registered_unlocked (tree, + parent_path, + child_entries); + +#ifdef DBUS_BUILD_TESTS + if (tree->connection) +#endif + { + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (tree->connection); + } + + return result; +} + + +/** Set to 1 to get a bunch of spew about disassembling the path string */ +#define VERBOSE_DECOMPOSE 0 + +/** + * Decompose an object path. A path of just "/" is + * represented as an empty vector of strings. + * The path need not be nul terminated. + * + * @param data the path data + * @param len the length of the path string + * @param path address to store new object path + * @param path_len length of stored path + */ +dbus_bool_t +_dbus_decompose_path (const char* data, + int len, + char ***path, + int *path_len) +{ + char **retval; + int n_components; + int i, j, comp; + + _dbus_assert (data != NULL); + +#if VERBOSE_DECOMPOSE + _dbus_verbose ("Decomposing path \"%s\"\n", + data); +#endif + + n_components = 0; + if (len > 1) /* if path is not just "/" */ + { + i = 0; + while (i < len) + { + if (data[i] == '/') + n_components += 1; + ++i; + } + } + + retval = dbus_new0 (char*, n_components + 1); + + if (retval == NULL) + return FALSE; + + comp = 0; + if (n_components == 0) + i = 1; + else + i = 0; + while (comp < n_components) + { + _dbus_assert (i < len); + + if (data[i] == '/') + ++i; + j = i; + + while (j < len && data[j] != '/') + ++j; + + /* Now [i, j) is the path component */ + _dbus_assert (i < j); + _dbus_assert (data[i] != '/'); + _dbus_assert (j == len || data[j] == '/'); + +#if VERBOSE_DECOMPOSE + _dbus_verbose (" (component in [%d,%d))\n", + i, j); +#endif + + retval[comp] = _dbus_memdup (&data[i], j - i + 1); + if (retval[comp] == NULL) + { + dbus_free_string_array (retval); + return FALSE; + } + retval[comp][j-i] = '\0'; +#if VERBOSE_DECOMPOSE + _dbus_verbose (" (component %d = \"%s\")\n", + comp, retval[comp]); +#endif + + ++comp; + i = j; + } + _dbus_assert (i == len); + + *path = retval; + if (path_len) + *path_len = n_components; + + return TRUE; +} + +/** @} */ + +static char* +flatten_path (const char **path) +{ + DBusString str; + char *s; + + if (!_dbus_string_init (&str)) + return NULL; + + if (path[0] == NULL) + { + if (!_dbus_string_append_byte (&str, '/')) + goto nomem; + } + else + { + int i; + + i = 0; + while (path[i]) + { + if (!_dbus_string_append_byte (&str, '/')) + goto nomem; + + if (!_dbus_string_append (&str, path[i])) + goto nomem; + + ++i; + } + } + + if (!_dbus_string_steal_data (&str, &s)) + goto nomem; + + _dbus_string_free (&str); + + return s; + + nomem: + _dbus_string_free (&str); + return NULL; +} + + +#ifdef DBUS_BUILD_TESTS + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#include "dbus-test.h" +#include + +typedef enum +{ + STR_EQUAL, + STR_PREFIX, + STR_DIFFERENT +} StrComparison; + +/* Returns TRUE if container is a parent of child + */ +static StrComparison +path_contains (const char **container, + const char **child) +{ + int i; + + i = 0; + while (child[i] != NULL) + { + int v; + + if (container[i] == NULL) + return STR_PREFIX; /* container ran out, child continues; + * thus the container is a parent of the + * child. + */ + + _dbus_assert (container[i] != NULL); + _dbus_assert (child[i] != NULL); + + v = strcmp (container[i], child[i]); + + if (v != 0) + return STR_DIFFERENT; /* they overlap until here and then are different, + * not overlapping + */ + + ++i; + } + + /* Child ran out; if container also did, they are equal; + * otherwise, the child is a parent of the container. + */ + if (container[i] == NULL) + return STR_EQUAL; + else + return STR_DIFFERENT; +} + +#if 0 +static void +spew_subtree_recurse (DBusObjectSubtree *subtree, + int indent) +{ + int i; + + i = 0; + while (i < indent) + { + _dbus_verbose (" "); + ++i; + } + + _dbus_verbose ("%s (%d children)\n", + subtree->name, subtree->n_subtrees); + + i = 0; + while (i < subtree->n_subtrees) + { + spew_subtree_recurse (subtree->subtrees[i], indent + 2); + + ++i; + } +} + +static void +spew_tree (DBusObjectTree *tree) +{ + spew_subtree_recurse (tree->root, 0); +} +#endif + +/** + * Callback data used in tests + */ +typedef struct +{ + const char **path; /**< Path */ + dbus_bool_t handler_fallback; /**< true if the handler may be called as fallback */ + dbus_bool_t message_handled; /**< Gets set to true if message handler called */ + dbus_bool_t handler_unregistered; /**< gets set to true if handler is unregistered */ +} TreeTestData; + + +static void +test_unregister_function (DBusConnection *connection, + void *user_data) +{ + TreeTestData *ttd = user_data; + + ttd->handler_unregistered = TRUE; +} + +static DBusHandlerResult +test_message_function (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + TreeTestData *ttd = user_data; + + ttd->message_handled = TRUE; + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static dbus_bool_t +do_register (DBusObjectTree *tree, + const char **path, + dbus_bool_t fallback, + int i, + TreeTestData *tree_test_data) +{ + DBusObjectPathVTable vtable = { test_unregister_function, + test_message_function, NULL }; + + tree_test_data[i].message_handled = FALSE; + tree_test_data[i].handler_unregistered = FALSE; + tree_test_data[i].handler_fallback = fallback; + tree_test_data[i].path = path; + + if (!_dbus_object_tree_register (tree, fallback, path, + &vtable, + &tree_test_data[i], + NULL)) + return FALSE; + + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path) == + &tree_test_data[i]); + + return TRUE; +} + +static dbus_bool_t +do_test_dispatch (DBusObjectTree *tree, + const char **path, + int i, + TreeTestData *tree_test_data, + int n_test_data) +{ + DBusMessage *message; + int j; + DBusHandlerResult result; + char *flat; + + message = NULL; + + flat = flatten_path (path); + if (flat == NULL) + goto oom; + + message = dbus_message_new_method_call (NULL, + flat, + "org.freedesktop.TestInterface", + "Foo"); + dbus_free (flat); + if (message == NULL) + goto oom; + + j = 0; + while (j < n_test_data) + { + tree_test_data[j].message_handled = FALSE; + ++j; + } + + result = _dbus_object_tree_dispatch_and_unlock (tree, message); + if (result == DBUS_HANDLER_RESULT_NEED_MEMORY) + goto oom; + + _dbus_assert (tree_test_data[i].message_handled); + + j = 0; + while (j < n_test_data) + { + if (tree_test_data[j].message_handled) + { + if (tree_test_data[j].handler_fallback) + _dbus_assert (path_contains (tree_test_data[j].path, + path) != STR_DIFFERENT); + else + _dbus_assert (path_contains (tree_test_data[j].path, path) == STR_EQUAL); + } + else + { + if (tree_test_data[j].handler_fallback) + _dbus_assert (path_contains (tree_test_data[j].path, + path) == STR_DIFFERENT); + else + _dbus_assert (path_contains (tree_test_data[j].path, path) != STR_EQUAL); + } + + ++j; + } + + dbus_message_unref (message); + + return TRUE; + + oom: + if (message) + dbus_message_unref (message); + return FALSE; +} + +static size_t +string_array_length (const char **array) +{ + size_t i; + for (i = 0; array[i]; i++) ; + return i; +} + +typedef struct +{ + const char *path; + const char *result[20]; +} DecomposePathTest; + +static DecomposePathTest decompose_tests[] = { + { "/foo", { "foo", NULL } }, + { "/foo/bar", { "foo", "bar", NULL } }, + { "/", { NULL } }, + { "/a/b", { "a", "b", NULL } }, + { "/a/b/c", { "a", "b", "c", NULL } }, + { "/a/b/c/d", { "a", "b", "c", "d", NULL } }, + { "/foo/bar/q", { "foo", "bar", "q", NULL } }, + { "/foo/bar/this/is/longer", { "foo", "bar", "this", "is", "longer", NULL } } +}; + +static dbus_bool_t +run_decompose_tests (void) +{ + int i; + + i = 0; + while (i < _DBUS_N_ELEMENTS (decompose_tests)) + { + char **result; + int result_len; + int expected_len; + + if (!_dbus_decompose_path (decompose_tests[i].path, + strlen (decompose_tests[i].path), + &result, &result_len)) + return FALSE; + + expected_len = string_array_length (decompose_tests[i].result); + + if (result_len != (int) string_array_length ((const char**)result) || + expected_len != result_len || + path_contains (decompose_tests[i].result, + (const char**) result) != STR_EQUAL) + { + int real_len = string_array_length ((const char**)result); + _dbus_warn ("Expected decompose of %s to have len %d, returned %d, appears to have %d\n", + decompose_tests[i].path, expected_len, result_len, + real_len); + _dbus_warn ("Decompose resulted in elements: { "); + i = 0; + while (i < real_len) + { + _dbus_warn ("\"%s\"%s", result[i], + (i + 1) == real_len ? "" : ", "); + ++i; + } + _dbus_warn ("}\n"); + _dbus_assert_not_reached ("path decompose failed\n"); + } + + dbus_free_string_array (result); + + ++i; + } + + return TRUE; +} + +static dbus_bool_t +object_tree_test_iteration (void *data) +{ + const char *path0[] = { NULL }; + const char *path1[] = { "foo", NULL }; + const char *path2[] = { "foo", "bar", NULL }; + const char *path3[] = { "foo", "bar", "baz", NULL }; + const char *path4[] = { "foo", "bar", "boo", NULL }; + const char *path5[] = { "blah", NULL }; + const char *path6[] = { "blah", "boof", NULL }; + const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL }; + const char *path8[] = { "childless", NULL }; + DBusObjectTree *tree; + TreeTestData tree_test_data[9]; + int i; + dbus_bool_t exact_match; + + if (!run_decompose_tests ()) + return FALSE; + + tree = NULL; + + tree = _dbus_object_tree_new (NULL); + if (tree == NULL) + goto out; + + if (!do_register (tree, path0, TRUE, 0, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path0, NULL)); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree (tree, path4, NULL)); + _dbus_assert (!find_subtree (tree, path5, NULL)); + _dbus_assert (!find_subtree (tree, path6, NULL)); + _dbus_assert (!find_subtree (tree, path7, NULL)); + _dbus_assert (!find_subtree (tree, path8, NULL)); + + _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); + _dbus_assert (find_handler (tree, path1, &exact_match) == tree->root && !exact_match); + _dbus_assert (find_handler (tree, path2, &exact_match) == tree->root && !exact_match); + _dbus_assert (find_handler (tree, path3, &exact_match) == tree->root && !exact_match); + _dbus_assert (find_handler (tree, path4, &exact_match) == tree->root && !exact_match); + _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); + _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); + _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); + _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); + + if (!do_register (tree, path1, TRUE, 1, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path0, NULL)); + _dbus_assert (find_subtree (tree, path1, NULL)); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree (tree, path4, NULL)); + _dbus_assert (!find_subtree (tree, path5, NULL)); + _dbus_assert (!find_subtree (tree, path6, NULL)); + _dbus_assert (!find_subtree (tree, path7, NULL)); + _dbus_assert (!find_subtree (tree, path8, NULL)); + + _dbus_assert (find_handler (tree, path0, &exact_match) && exact_match); + _dbus_assert (find_handler (tree, path1, &exact_match) && exact_match); + _dbus_assert (find_handler (tree, path2, &exact_match) && !exact_match); + _dbus_assert (find_handler (tree, path3, &exact_match) && !exact_match); + _dbus_assert (find_handler (tree, path4, &exact_match) && !exact_match); + _dbus_assert (find_handler (tree, path5, &exact_match) == tree->root && !exact_match); + _dbus_assert (find_handler (tree, path6, &exact_match) == tree->root && !exact_match); + _dbus_assert (find_handler (tree, path7, &exact_match) == tree->root && !exact_match); + _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); + + if (!do_register (tree, path2, TRUE, 2, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree (tree, path4, NULL)); + _dbus_assert (!find_subtree (tree, path5, NULL)); + _dbus_assert (!find_subtree (tree, path6, NULL)); + _dbus_assert (!find_subtree (tree, path7, NULL)); + _dbus_assert (!find_subtree (tree, path8, NULL)); + + if (!do_register (tree, path3, TRUE, 3, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path0, NULL)); + _dbus_assert (find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree (tree, path4, NULL)); + _dbus_assert (!find_subtree (tree, path5, NULL)); + _dbus_assert (!find_subtree (tree, path6, NULL)); + _dbus_assert (!find_subtree (tree, path7, NULL)); + _dbus_assert (!find_subtree (tree, path8, NULL)); + + if (!do_register (tree, path4, TRUE, 4, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path0, NULL)); + _dbus_assert (find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (find_subtree (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + _dbus_assert (!find_subtree (tree, path5, NULL)); + _dbus_assert (!find_subtree (tree, path6, NULL)); + _dbus_assert (!find_subtree (tree, path7, NULL)); + _dbus_assert (!find_subtree (tree, path8, NULL)); + + if (!do_register (tree, path5, TRUE, 5, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path0, NULL)); + _dbus_assert (find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (find_subtree (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + _dbus_assert (find_subtree (tree, path5, NULL)); + _dbus_assert (!find_subtree (tree, path6, NULL)); + _dbus_assert (!find_subtree (tree, path7, NULL)); + _dbus_assert (!find_subtree (tree, path8, NULL)); + + _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); + _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); + _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); + _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); + _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); + _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); + _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && !exact_match); + _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && !exact_match); + _dbus_assert (find_handler (tree, path8, &exact_match) == tree->root && !exact_match); + + if (!do_register (tree, path6, TRUE, 6, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path0, NULL)); + _dbus_assert (find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (find_subtree (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + _dbus_assert (find_subtree (tree, path5, NULL)); + _dbus_assert (find_subtree (tree, path6, NULL)); + _dbus_assert (!find_subtree (tree, path7, NULL)); + _dbus_assert (!find_subtree (tree, path8, NULL)); + + if (!do_register (tree, path7, TRUE, 7, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path0, NULL)); + _dbus_assert (find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (find_subtree (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + _dbus_assert (find_subtree (tree, path5, NULL)); + _dbus_assert (find_subtree (tree, path6, NULL)); + _dbus_assert (find_subtree (tree, path7, NULL)); + _dbus_assert (!find_subtree (tree, path8, NULL)); + + if (!do_register (tree, path8, TRUE, 8, tree_test_data)) + goto out; + + _dbus_assert (find_subtree (tree, path0, NULL)); + _dbus_assert (find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (find_subtree (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + _dbus_assert (find_subtree (tree, path5, NULL)); + _dbus_assert (find_subtree (tree, path6, NULL)); + _dbus_assert (find_subtree (tree, path7, NULL)); + _dbus_assert (find_subtree (tree, path8, NULL)); + + _dbus_assert (find_handler (tree, path0, &exact_match) == tree->root && exact_match); + _dbus_assert (find_handler (tree, path1, &exact_match) != tree->root && exact_match); + _dbus_assert (find_handler (tree, path2, &exact_match) != tree->root && exact_match); + _dbus_assert (find_handler (tree, path3, &exact_match) != tree->root && exact_match); + _dbus_assert (find_handler (tree, path4, &exact_match) != tree->root && exact_match); + _dbus_assert (find_handler (tree, path5, &exact_match) != tree->root && exact_match); + _dbus_assert (find_handler (tree, path6, &exact_match) != tree->root && exact_match); + _dbus_assert (find_handler (tree, path7, &exact_match) != tree->root && exact_match); + _dbus_assert (find_handler (tree, path8, &exact_match) != tree->root && exact_match); + + /* test the list_registered function */ + + { + const char *root[] = { NULL }; + char **child_entries; + int nb; + + _dbus_object_tree_list_registered_unlocked (tree, path1, &child_entries); + if (child_entries != NULL) + { + nb = string_array_length ((const char**)child_entries); + _dbus_assert (nb == 1); + dbus_free_string_array (child_entries); + } + + _dbus_object_tree_list_registered_unlocked (tree, path2, &child_entries); + if (child_entries != NULL) + { + nb = string_array_length ((const char**)child_entries); + _dbus_assert (nb == 2); + dbus_free_string_array (child_entries); + } + + _dbus_object_tree_list_registered_unlocked (tree, path8, &child_entries); + if (child_entries != NULL) + { + nb = string_array_length ((const char**)child_entries); + _dbus_assert (nb == 0); + dbus_free_string_array (child_entries); + } + + _dbus_object_tree_list_registered_unlocked (tree, root, &child_entries); + if (child_entries != NULL) + { + nb = string_array_length ((const char**)child_entries); + _dbus_assert (nb == 3); + dbus_free_string_array (child_entries); + } + } + + /* Check that destroying tree calls unregister funcs */ + _dbus_object_tree_unref (tree); + + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) + { + _dbus_assert (tree_test_data[i].handler_unregistered); + _dbus_assert (!tree_test_data[i].message_handled); + ++i; + } + + /* Now start again and try the individual unregister function */ + tree = _dbus_object_tree_new (NULL); + if (tree == NULL) + goto out; + + if (!do_register (tree, path0, TRUE, 0, tree_test_data)) + goto out; + if (!do_register (tree, path1, TRUE, 1, tree_test_data)) + goto out; + if (!do_register (tree, path2, TRUE, 2, tree_test_data)) + goto out; + if (!do_register (tree, path3, TRUE, 3, tree_test_data)) + goto out; + if (!do_register (tree, path4, TRUE, 4, tree_test_data)) + goto out; + if (!do_register (tree, path5, TRUE, 5, tree_test_data)) + goto out; + if (!do_register (tree, path6, TRUE, 6, tree_test_data)) + goto out; + if (!do_register (tree, path7, TRUE, 7, tree_test_data)) + goto out; + if (!do_register (tree, path8, TRUE, 8, tree_test_data)) + goto out; + + _dbus_object_tree_unregister_and_unlock (tree, path0); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path0) == NULL); + + _dbus_assert (!find_subtree (tree, path0, NULL)); + _dbus_assert (find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (find_subtree (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + _dbus_assert (find_subtree (tree, path5, NULL)); + _dbus_assert (find_subtree (tree, path6, NULL)); + _dbus_assert (find_subtree (tree, path7, NULL)); + _dbus_assert (find_subtree (tree, path8, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path1); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path1) == NULL); + + _dbus_assert (!find_subtree (tree, path0, NULL)); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (find_subtree (tree, path2, NULL)); + _dbus_assert (find_subtree (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + _dbus_assert (find_subtree (tree, path5, NULL)); + _dbus_assert (find_subtree (tree, path6, NULL)); + _dbus_assert (find_subtree (tree, path7, NULL)); + _dbus_assert (find_subtree (tree, path8, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path2); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path2) == NULL); + + _dbus_assert (!find_subtree (tree, path0, NULL)); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (find_subtree (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + _dbus_assert (find_subtree (tree, path5, NULL)); + _dbus_assert (find_subtree (tree, path6, NULL)); + _dbus_assert (find_subtree (tree, path7, NULL)); + _dbus_assert (find_subtree (tree, path8, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path3); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path3) == NULL); + + _dbus_assert (!find_subtree (tree, path0, NULL)); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (find_subtree (tree, path4, NULL)); + _dbus_assert (find_subtree (tree, path5, NULL)); + _dbus_assert (find_subtree (tree, path6, NULL)); + _dbus_assert (find_subtree (tree, path7, NULL)); + _dbus_assert (find_subtree (tree, path8, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path4); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path4) == NULL); + + _dbus_assert (!find_subtree (tree, path0, NULL)); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree (tree, path4, NULL)); + _dbus_assert (find_subtree (tree, path5, NULL)); + _dbus_assert (find_subtree (tree, path6, NULL)); + _dbus_assert (find_subtree (tree, path7, NULL)); + _dbus_assert (find_subtree (tree, path8, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path5); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path5) == NULL); + + _dbus_assert (!find_subtree (tree, path0, NULL)); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree (tree, path4, NULL)); + _dbus_assert (!find_subtree (tree, path5, NULL)); + _dbus_assert (find_subtree (tree, path6, NULL)); + _dbus_assert (find_subtree (tree, path7, NULL)); + _dbus_assert (find_subtree (tree, path8, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path6); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path6) == NULL); + + _dbus_assert (!find_subtree (tree, path0, NULL)); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree (tree, path4, NULL)); + _dbus_assert (!find_subtree (tree, path5, NULL)); + _dbus_assert (!find_subtree (tree, path6, NULL)); + _dbus_assert (find_subtree (tree, path7, NULL)); + _dbus_assert (find_subtree (tree, path8, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path7); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path7) == NULL); + + _dbus_assert (!find_subtree (tree, path0, NULL)); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree (tree, path4, NULL)); + _dbus_assert (!find_subtree (tree, path5, NULL)); + _dbus_assert (!find_subtree (tree, path6, NULL)); + _dbus_assert (!find_subtree (tree, path7, NULL)); + _dbus_assert (find_subtree (tree, path8, NULL)); + + _dbus_object_tree_unregister_and_unlock (tree, path8); + _dbus_assert (_dbus_object_tree_get_user_data_unlocked (tree, path8) == NULL); + + _dbus_assert (!find_subtree (tree, path0, NULL)); + _dbus_assert (!find_subtree (tree, path1, NULL)); + _dbus_assert (!find_subtree (tree, path2, NULL)); + _dbus_assert (!find_subtree (tree, path3, NULL)); + _dbus_assert (!find_subtree (tree, path4, NULL)); + _dbus_assert (!find_subtree (tree, path5, NULL)); + _dbus_assert (!find_subtree (tree, path6, NULL)); + _dbus_assert (!find_subtree (tree, path7, NULL)); + _dbus_assert (!find_subtree (tree, path8, NULL)); + + i = 0; + while (i < (int) _DBUS_N_ELEMENTS (tree_test_data)) + { + _dbus_assert (tree_test_data[i].handler_unregistered); + _dbus_assert (!tree_test_data[i].message_handled); + ++i; + } + + /* Register it all again, and test dispatch */ + + if (!do_register (tree, path0, TRUE, 0, tree_test_data)) + goto out; + if (!do_register (tree, path1, FALSE, 1, tree_test_data)) + goto out; + if (!do_register (tree, path2, TRUE, 2, tree_test_data)) + goto out; + if (!do_register (tree, path3, TRUE, 3, tree_test_data)) + goto out; + if (!do_register (tree, path4, TRUE, 4, tree_test_data)) + goto out; + if (!do_register (tree, path5, TRUE, 5, tree_test_data)) + goto out; + if (!do_register (tree, path6, FALSE, 6, tree_test_data)) + goto out; + if (!do_register (tree, path7, TRUE, 7, tree_test_data)) + goto out; + if (!do_register (tree, path8, TRUE, 8, tree_test_data)) + goto out; + +#if 0 + spew_tree (tree); +#endif + + if (!do_test_dispatch (tree, path0, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) + goto out; + if (!do_test_dispatch (tree, path1, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) + goto out; + if (!do_test_dispatch (tree, path2, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) + goto out; + if (!do_test_dispatch (tree, path3, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) + goto out; + if (!do_test_dispatch (tree, path4, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) + goto out; + if (!do_test_dispatch (tree, path5, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) + goto out; + if (!do_test_dispatch (tree, path6, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) + goto out; + if (!do_test_dispatch (tree, path7, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) + goto out; + if (!do_test_dispatch (tree, path8, 8, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data))) + goto out; + + out: + if (tree) + { + /* test ref */ + _dbus_object_tree_ref (tree); + _dbus_object_tree_unref (tree); + _dbus_object_tree_unref (tree); + } + + return TRUE; +} + +/** + * @ingroup DBusObjectTree + * Unit test for DBusObjectTree + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_object_tree_test (void) +{ + _dbus_test_oom_handling ("object tree", + object_tree_test_iteration, + NULL); + + return TRUE; +} + +#endif /* !DOXYGEN_SHOULD_SKIP_THIS */ + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-object-tree.h b/dbus/dbus-object-tree.h new file mode 100644 index 00000000..022dd93f --- /dev/null +++ b/dbus/dbus-object-tree.h @@ -0,0 +1,62 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-object-tree.h DBusObjectTree (internals of DBusConnection) + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_OBJECT_TREE_H +#define DBUS_OBJECT_TREE_H + +#include + +DBUS_BEGIN_DECLS + +typedef struct DBusObjectTree DBusObjectTree; + +DBusObjectTree* _dbus_object_tree_new (DBusConnection *connection); +DBusObjectTree* _dbus_object_tree_ref (DBusObjectTree *tree); +void _dbus_object_tree_unref (DBusObjectTree *tree); + +dbus_bool_t _dbus_object_tree_register (DBusObjectTree *tree, + dbus_bool_t fallback, + const char **path, + const DBusObjectPathVTable *vtable, + void *user_data, + DBusError *error); +void _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree, + const char **path); +DBusHandlerResult _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree, + DBusMessage *message); +void* _dbus_object_tree_get_user_data_unlocked (DBusObjectTree *tree, + const char **path); +void _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree); + + +dbus_bool_t _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree, + const char **parent_path, + char ***child_entries); + +dbus_bool_t _dbus_decompose_path (const char *data, + int len, + char ***path, + int *path_len); + +DBUS_END_DECLS + +#endif /* DBUS_OBJECT_TREE_H */ diff --git a/dbus/dbus-pending-call-internal.h b/dbus/dbus-pending-call-internal.h new file mode 100644 index 00000000..1875eea8 --- /dev/null +++ b/dbus/dbus-pending-call-internal.h @@ -0,0 +1,67 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-pending-call-internal.h DBusPendingCall internal interfaces + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_PENDING_CALL_INTERNAL_H +#define DBUS_PENDING_CALL_INTERNAL_H + + +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +dbus_bool_t _dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall *pending); +void _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall *pending, + dbus_bool_t is_added); +DBusTimeout * _dbus_pending_call_get_timeout_unlocked (DBusPendingCall *pending); +dbus_uint32_t _dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall *pending); +void _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending, + dbus_uint32_t serial); +DBusConnection * _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending); +DBusConnection * _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending); +dbus_bool_t _dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending); +void _dbus_pending_call_complete (DBusPendingCall *pending); +void _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending, + DBusMessage *message); +void _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending, + DBusConnection *connection); +void _dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending, + dbus_uint32_t serial); +dbus_bool_t _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending, + DBusMessage *message, + dbus_uint32_t serial); +DBusPendingCall* _dbus_pending_call_new_unlocked (DBusConnection *connection, + int timeout_milliseconds, + DBusTimeoutHandler timeout_handler); +DBusPendingCall* _dbus_pending_call_ref_unlocked (DBusPendingCall *pending); +void _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending); +dbus_bool_t _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending, + dbus_int32_t slot, + void *data, + DBusFreeFunction free_data_func); + + +DBUS_END_DECLS + +#endif /* DBUS_PENDING_CALL_INTERNAL_H */ diff --git a/dbus/dbus-pending-call.c b/dbus/dbus-pending-call.c new file mode 100644 index 00000000..43fad052 --- /dev/null +++ b/dbus/dbus-pending-call.c @@ -0,0 +1,824 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-pending-call.c Object representing a call in progress. + * + * Copyright (C) 2002, 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-connection-internal.h" +#include "dbus-pending-call-internal.h" +#include "dbus-pending-call.h" +#include "dbus-list.h" +#include "dbus-threads.h" +#include "dbus-test.h" + +/** + * @defgroup DBusPendingCallInternals DBusPendingCall implementation details + * @ingroup DBusInternals + * @brief DBusPendingCall private implementation details. + * + * The guts of DBusPendingCall and its methods. + * + * @{ + */ + +/** + * @brief Internals of DBusPendingCall + * + * Opaque object representing a reply message that we're waiting for. + */ + +/** + * shorter and more visible way to write _dbus_connection_lock() + */ +#define CONNECTION_LOCK(connection) _dbus_connection_lock(connection) +/** + * shorter and more visible way to write _dbus_connection_unlock() + */ +#define CONNECTION_UNLOCK(connection) _dbus_connection_unlock(connection) + +/** + * Implementation details of #DBusPendingCall - all fields are private. + */ +struct DBusPendingCall +{ + DBusAtomic refcount; /**< reference count */ + + DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ + + DBusPendingCallNotifyFunction function; /**< Notifier when reply arrives. */ + + DBusConnection *connection; /**< Connections we're associated with */ + DBusMessage *reply; /**< Reply (after we've received it) */ + DBusTimeout *timeout; /**< Timeout */ + + DBusList *timeout_link; /**< Preallocated timeout response */ + + dbus_uint32_t reply_serial; /**< Expected serial of reply */ + + unsigned int completed : 1; /**< TRUE if completed */ + unsigned int timeout_added : 1; /**< Have added the timeout */ +}; + +static dbus_int32_t notify_user_data_slot = -1; + +/** + * Creates a new pending reply object. + * + * @param connection connection where reply will arrive + * @param timeout_milliseconds length of timeout, -1 for default, INT_MAX for no timeout + * @param timeout_handler timeout handler, takes pending call as data + * @returns a new #DBusPendingCall or #NULL if no memory. + */ +DBusPendingCall* +_dbus_pending_call_new_unlocked (DBusConnection *connection, + int timeout_milliseconds, + DBusTimeoutHandler timeout_handler) +{ + DBusPendingCall *pending; + DBusTimeout *timeout; + + _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1); + + if (timeout_milliseconds == -1) + timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE; + + if (!dbus_pending_call_allocate_data_slot (¬ify_user_data_slot)) + return NULL; + + pending = dbus_new0 (DBusPendingCall, 1); + + if (pending == NULL) + { + dbus_pending_call_free_data_slot (¬ify_user_data_slot); + return NULL; + } + + if (timeout_milliseconds != _DBUS_INT_MAX) + { + timeout = _dbus_timeout_new (timeout_milliseconds, + timeout_handler, + pending, NULL); + + if (timeout == NULL) + { + dbus_pending_call_free_data_slot (¬ify_user_data_slot); + dbus_free (pending); + return NULL; + } + + pending->timeout = timeout; + } + else + { + pending->timeout = NULL; + } + + pending->refcount.value = 1; + pending->connection = connection; + _dbus_connection_ref_unlocked (pending->connection); + + _dbus_data_slot_list_init (&pending->slot_list); + + return pending; +} + +/** + * Sets the reply of a pending call with the given message, + * or if the message is #NULL, by timing out the pending call. + * + * @param pending the pending call + * @param message the message to complete the call with, or #NULL + * to time out the call + */ +void +_dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending, + DBusMessage *message) +{ + if (message == NULL) + { + message = pending->timeout_link->data; + _dbus_list_clear (&pending->timeout_link); + } + else + dbus_message_ref (message); + + _dbus_verbose (" handing message %p (%s) to pending call serial %u\n", + message, + dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ? + "method return" : + dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? + "error" : "other type", + pending->reply_serial); + + _dbus_assert (pending->reply == NULL); + _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message)); + pending->reply = message; +} + +/** + * Calls notifier function for the pending call + * and sets the call to completed. + * + * @param pending the pending call + * + */ +void +_dbus_pending_call_complete (DBusPendingCall *pending) +{ + _dbus_assert (!pending->completed); + + pending->completed = TRUE; + + if (pending->function) + { + void *user_data; + user_data = dbus_pending_call_get_data (pending, + notify_user_data_slot); + + (* pending->function) (pending, user_data); + } +} + +/** + * If the pending call hasn't been timed out, add its timeout + * error reply to the connection's incoming message queue. + * + * @param pending the pending call + * @param connection the connection the call was sent to + */ +void +_dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending, + DBusConnection *connection) +{ + _dbus_assert (connection == pending->connection); + + if (pending->timeout_link) + { + _dbus_connection_queue_synthesized_message_link (connection, + pending->timeout_link); + pending->timeout_link = NULL; + } +} + +/** + * Checks to see if a timeout has been added + * + * @param pending the pending_call + * @returns #TRUE if there is a timeout or #FALSE if not + */ +dbus_bool_t +_dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall *pending) +{ + _dbus_assert (pending != NULL); + + return pending->timeout_added; +} + + +/** + * Sets wether the timeout has been added + * + * @param pending the pending_call + * @param is_added whether or not a timeout is added + */ +void +_dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall *pending, + dbus_bool_t is_added) +{ + _dbus_assert (pending != NULL); + + pending->timeout_added = is_added; +} + + +/** + * Retrives the timeout + * + * @param pending the pending_call + * @returns a timeout object or NULL if call has no timeout + */ +DBusTimeout * +_dbus_pending_call_get_timeout_unlocked (DBusPendingCall *pending) +{ + _dbus_assert (pending != NULL); + + return pending->timeout; +} + +/** + * Gets the reply's serial number + * + * @param pending the pending_call + * @returns a serial number for the reply or 0 + */ +dbus_uint32_t +_dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall *pending) +{ + _dbus_assert (pending != NULL); + + return pending->reply_serial; +} + +/** + * Sets the reply's serial number + * + * @param pending the pending_call + * @param serial the serial number + */ +void +_dbus_pending_call_set_reply_serial_unlocked (DBusPendingCall *pending, + dbus_uint32_t serial) +{ + _dbus_assert (pending != NULL); + _dbus_assert (pending->reply_serial == 0); + + pending->reply_serial = serial; +} + +/** + * Gets the connection associated with this pending call. + * + * @param pending the pending_call + * @returns the connection associated with the pending call + */ +DBusConnection * +_dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending) +{ + _dbus_assert (pending != NULL); + + CONNECTION_LOCK (pending->connection); + return pending->connection; +} + +/** + * Gets the connection associated with this pending call. + * + * @param pending the pending_call + * @returns the connection associated with the pending call + */ +DBusConnection * +_dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending) +{ + _dbus_assert (pending != NULL); + + return pending->connection; +} + +/** + * Sets the reply message associated with the pending call to a timeout error + * + * @param pending the pending_call + * @param message the message we are sending the error reply to + * @param serial serial number for the reply + * @return #FALSE on OOM + */ +dbus_bool_t +_dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending, + DBusMessage *message, + dbus_uint32_t serial) +{ + DBusList *reply_link; + DBusMessage *reply; + + reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY, + "Did not receive a reply. Possible causes include: " + "the remote application did not send a reply, " + "the message bus security policy blocked the reply, " + "the reply timeout expired, or " + "the network connection was broken."); + if (reply == NULL) + return FALSE; + + reply_link = _dbus_list_alloc_link (reply); + if (reply_link == NULL) + { + dbus_message_unref (reply); + return FALSE; + } + + pending->timeout_link = reply_link; + + _dbus_pending_call_set_reply_serial_unlocked (pending, serial); + + return TRUE; +} + +/** + * Increments the reference count on a pending call, + * while the lock on its connection is already held. + * + * @param pending the pending call object + * @returns the pending call object + */ +DBusPendingCall * +_dbus_pending_call_ref_unlocked (DBusPendingCall *pending) +{ + pending->refcount.value += 1; + + return pending; +} + + +static void +_dbus_pending_call_last_unref (DBusPendingCall *pending) +{ + DBusConnection *connection; + + /* If we get here, we should be already detached + * from the connection, or never attached. + */ + _dbus_assert (!pending->timeout_added); + + connection = pending->connection; + + /* this assumes we aren't holding connection lock... */ + _dbus_data_slot_list_free (&pending->slot_list); + + if (pending->timeout != NULL) + _dbus_timeout_unref (pending->timeout); + + if (pending->timeout_link) + { + dbus_message_unref ((DBusMessage *)pending->timeout_link->data); + _dbus_list_free_link (pending->timeout_link); + pending->timeout_link = NULL; + } + + if (pending->reply) + { + dbus_message_unref (pending->reply); + pending->reply = NULL; + } + + dbus_free (pending); + + dbus_pending_call_free_data_slot (¬ify_user_data_slot); + + /* connection lock should not be held. */ + /* Free the connection last to avoid a weird state while + * calling out to application code where the pending exists + * but not the connection. + */ + dbus_connection_unref (connection); +} + +/** + * Decrements the reference count on a pending call, + * freeing it if the count reaches 0. Assumes + * connection lock is already held. + * + * @param pending the pending call object + */ +void +_dbus_pending_call_unref_and_unlock (DBusPendingCall *pending) +{ + dbus_bool_t last_unref; + + _dbus_assert (pending->refcount.value > 0); + + pending->refcount.value -= 1; + last_unref = pending->refcount.value == 0; + + CONNECTION_UNLOCK (pending->connection); + if (last_unref) + _dbus_pending_call_last_unref (pending); +} + +/** + * Checks whether the pending call has received a reply + * yet, or not. Assumes connection lock is held. + * + * @param pending the pending call + * @returns #TRUE if a reply has been received + */ +dbus_bool_t +_dbus_pending_call_get_completed_unlocked (DBusPendingCall *pending) +{ + return pending->completed; +} + +static DBusDataSlotAllocator slot_allocator; +_DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots); + +/** + * Stores a pointer on a #DBusPendingCall, along + * with an optional function to be used for freeing + * the data when the data is set again, or when + * the pending call is finalized. The slot number + * must have been allocated with dbus_pending_call_allocate_data_slot(). + * + * @param pending the pending_call + * @param slot the slot number + * @param data the data to store + * @param free_data_func finalizer function for the data + * @returns #TRUE if there was enough memory to store the data + */ +dbus_bool_t +_dbus_pending_call_set_data_unlocked (DBusPendingCall *pending, + dbus_int32_t slot, + void *data, + DBusFreeFunction free_data_func) +{ + DBusFreeFunction old_free_func; + void *old_data; + dbus_bool_t retval; + + retval = _dbus_data_slot_list_set (&slot_allocator, + &pending->slot_list, + slot, data, free_data_func, + &old_free_func, &old_data); + + /* Drop locks to call out to app code */ + CONNECTION_UNLOCK (pending->connection); + + if (retval) + { + if (old_free_func) + (* old_free_func) (old_data); + } + + CONNECTION_LOCK (pending->connection); + + return retval; +} + +/** @} */ + +/** + * @defgroup DBusPendingCall DBusPendingCall + * @ingroup DBus + * @brief Pending reply to a method call message + * + * A DBusPendingCall is an object representing an + * expected reply. A #DBusPendingCall can be created + * when you send a message that should have a reply. + * + * @{ + */ + +/** + * @typedef DBusPendingCall + * + * Opaque data type representing a message pending. + */ + +/** + * Increments the reference count on a pending call. + * + * @param pending the pending call object + * @returns the pending call object + */ +DBusPendingCall * +dbus_pending_call_ref (DBusPendingCall *pending) +{ + _dbus_return_val_if_fail (pending != NULL, NULL); + + /* The connection lock is better than the global + * lock in the atomic increment fallback + */ +#ifdef DBUS_HAVE_ATOMIC_INT + _dbus_atomic_inc (&pending->refcount); +#else + CONNECTION_LOCK (pending->connection); + _dbus_assert (pending->refcount.value > 0); + + pending->refcount.value += 1; + CONNECTION_UNLOCK (pending->connection); +#endif + + return pending; +} + +/** + * Decrements the reference count on a pending call, + * freeing it if the count reaches 0. + * + * @param pending the pending call object + */ +void +dbus_pending_call_unref (DBusPendingCall *pending) +{ + dbus_bool_t last_unref; + + _dbus_return_if_fail (pending != NULL); + + /* More efficient to use the connection lock instead of atomic + * int fallback if we lack atomic int decrement + */ +#ifdef DBUS_HAVE_ATOMIC_INT + last_unref = (_dbus_atomic_dec (&pending->refcount) == 1); +#else + CONNECTION_LOCK (pending->connection); + _dbus_assert (pending->refcount.value > 0); + pending->refcount.value -= 1; + last_unref = pending->refcount.value == 0; + CONNECTION_UNLOCK (pending->connection); +#endif + + if (last_unref) + _dbus_pending_call_last_unref(pending); +} + +/** + * Sets a notification function to be called when the reply is + * received or the pending call times out. + * + * @param pending the pending call + * @param function notifier function + * @param user_data data to pass to notifier function + * @param free_user_data function to free the user data + * @returns #FALSE if not enough memory + */ +dbus_bool_t +dbus_pending_call_set_notify (DBusPendingCall *pending, + DBusPendingCallNotifyFunction function, + void *user_data, + DBusFreeFunction free_user_data) +{ + _dbus_return_val_if_fail (pending != NULL, FALSE); + + CONNECTION_LOCK (pending->connection); + + /* could invoke application code! */ + if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot, + user_data, free_user_data)) + return FALSE; + + pending->function = function; + + CONNECTION_UNLOCK (pending->connection); + + return TRUE; +} + +/** + * Cancels the pending call, such that any reply or error received + * will just be ignored. Drops the dbus library's internal reference + * to the #DBusPendingCall so will free the call if nobody else is + * holding a reference. However you usually get a reference from + * dbus_connection_send_with_reply() so probably your app owns a ref + * also. + * + * Note that canceling a pending call will not simulate a + * timed-out call; if a call times out, then a timeout error reply is + * received. If you cancel the call, no reply is received unless the + * the reply was already received before you canceled. + * + * @param pending the pending call + */ +void +dbus_pending_call_cancel (DBusPendingCall *pending) +{ + _dbus_return_if_fail (pending != NULL); + + _dbus_connection_remove_pending_call (pending->connection, + pending); +} + +/** + * Checks whether the pending call has received a reply + * yet, or not. + * + * @param pending the pending call + * @returns #TRUE if a reply has been received + */ +dbus_bool_t +dbus_pending_call_get_completed (DBusPendingCall *pending) +{ + dbus_bool_t completed; + + _dbus_return_val_if_fail (pending != NULL, FALSE); + + CONNECTION_LOCK (pending->connection); + completed = pending->completed; + CONNECTION_UNLOCK (pending->connection); + + return completed; +} + +/** + * Gets the reply, or returns #NULL if none has been received + * yet. Ownership of the reply message passes to the caller. This + * function can only be called once per pending call, since the reply + * message is tranferred to the caller. + * + * @param pending the pending call + * @returns the reply message or #NULL. + */ +DBusMessage* +dbus_pending_call_steal_reply (DBusPendingCall *pending) +{ + DBusMessage *message; + + _dbus_return_val_if_fail (pending != NULL, NULL); + _dbus_return_val_if_fail (pending->completed, NULL); + _dbus_return_val_if_fail (pending->reply != NULL, NULL); + + CONNECTION_LOCK (pending->connection); + + message = pending->reply; + pending->reply = NULL; + + CONNECTION_UNLOCK (pending->connection); + + return message; +} + +/** + * Block until the pending call is completed. The blocking is as with + * dbus_connection_send_with_reply_and_block(); it does not enter the + * main loop or process other messages, it simply waits for the reply + * in question. + * + * If the pending call is already completed, this function returns + * immediately. + * + * @todo when you start blocking, the timeout is reset, but it should + * really only use time remaining since the pending call was created. + * This requires storing timestamps instead of intervals in the timeout + * + * @param pending the pending call + */ +void +dbus_pending_call_block (DBusPendingCall *pending) +{ + _dbus_return_if_fail (pending != NULL); + + _dbus_connection_block_pending_call (pending); +} + +/** + * Allocates an integer ID to be used for storing application-specific + * data on any DBusPendingCall. The allocated ID may then be used + * with dbus_pending_call_set_data() and dbus_pending_call_get_data(). + * The passed-in slot must be initialized to -1, and is filled in + * with the slot ID. If the passed-in slot is not -1, it's assumed + * to be already allocated, and its refcount is incremented. + * + * The allocated slot is global, i.e. all DBusPendingCall objects will + * have a slot with the given integer ID reserved. + * + * @param slot_p address of a global variable storing the slot + * @returns #FALSE on failure (no memory) + */ +dbus_bool_t +dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p) +{ + _dbus_return_val_if_fail (slot_p != NULL, FALSE); + + return _dbus_data_slot_allocator_alloc (&slot_allocator, + &_DBUS_LOCK_NAME (pending_call_slots), + slot_p); +} + +/** + * Deallocates a global ID for #DBusPendingCall data slots. + * dbus_pending_call_get_data() and dbus_pending_call_set_data() may + * no longer be used with this slot. Existing data stored on existing + * DBusPendingCall objects will be freed when the #DBusPendingCall is + * finalized, but may not be retrieved (and may only be replaced if + * someone else reallocates the slot). When the refcount on the + * passed-in slot reaches 0, it is set to -1. + * + * @param slot_p address storing the slot to deallocate + */ +void +dbus_pending_call_free_data_slot (dbus_int32_t *slot_p) +{ + _dbus_return_if_fail (slot_p != NULL); + _dbus_return_if_fail (*slot_p >= 0); + + _dbus_data_slot_allocator_free (&slot_allocator, slot_p); +} + +/** + * Stores a pointer on a #DBusPendingCall, along + * with an optional function to be used for freeing + * the data when the data is set again, or when + * the pending call is finalized. The slot number + * must have been allocated with dbus_pending_call_allocate_data_slot(). + * + * @param pending the pending_call + * @param slot the slot number + * @param data the data to store + * @param free_data_func finalizer function for the data + * @returns #TRUE if there was enough memory to store the data + */ +dbus_bool_t +dbus_pending_call_set_data (DBusPendingCall *pending, + dbus_int32_t slot, + void *data, + DBusFreeFunction free_data_func) +{ + dbus_bool_t retval; + + _dbus_return_val_if_fail (pending != NULL, FALSE); + _dbus_return_val_if_fail (slot >= 0, FALSE); + + + CONNECTION_LOCK (pending->connection); + retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func); + CONNECTION_UNLOCK (pending->connection); + return retval; +} + +/** + * Retrieves data previously set with dbus_pending_call_set_data(). + * The slot must still be allocated (must not have been freed). + * + * @param pending the pending_call + * @param slot the slot to get data from + * @returns the data, or #NULL if not found + */ +void* +dbus_pending_call_get_data (DBusPendingCall *pending, + dbus_int32_t slot) +{ + void *res; + + _dbus_return_val_if_fail (pending != NULL, NULL); + + CONNECTION_LOCK (pending->connection); + res = _dbus_data_slot_list_get (&slot_allocator, + &pending->slot_list, + slot); + CONNECTION_UNLOCK (pending->connection); + + return res; +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS + +/** + * @ingroup DBusPendingCallInternals + * Unit test for DBusPendingCall. + * + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_pending_call_test (const char *test_data_dir) +{ + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-pending-call.h b/dbus/dbus-pending-call.h new file mode 100644 index 00000000..b1b4e235 --- /dev/null +++ b/dbus/dbus-pending-call.h @@ -0,0 +1,65 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-pending-call.h Object representing a call in progress. + * + * Copyright (C) 2002, 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_PENDING_CALL_H +#define DBUS_PENDING_CALL_H + +#include +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusPendingCall + * @{ + */ + +DBusPendingCall* dbus_pending_call_ref (DBusPendingCall *pending); +void dbus_pending_call_unref (DBusPendingCall *pending); +dbus_bool_t dbus_pending_call_set_notify (DBusPendingCall *pending, + DBusPendingCallNotifyFunction function, + void *user_data, + DBusFreeFunction free_user_data); +void dbus_pending_call_cancel (DBusPendingCall *pending); +dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pending); +DBusMessage* dbus_pending_call_steal_reply (DBusPendingCall *pending); +void dbus_pending_call_block (DBusPendingCall *pending); + +dbus_bool_t dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p); +void dbus_pending_call_free_data_slot (dbus_int32_t *slot_p); +dbus_bool_t dbus_pending_call_set_data (DBusPendingCall *pending, + dbus_int32_t slot, + void *data, + DBusFreeFunction free_data_func); +void* dbus_pending_call_get_data (DBusPendingCall *pending, + dbus_int32_t slot); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_PENDING_CALL_H */ diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h new file mode 100644 index 00000000..ed718fec --- /dev/null +++ b/dbus/dbus-protocol.h @@ -0,0 +1,439 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-protocol.h D-Bus protocol constants + * + * Copyright (C) 2002, 2003 CodeFactory AB + * Copyright (C) 2004, 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_PROTOCOL_H +#define DBUS_PROTOCOL_H + +/* Don't include anything in here from anywhere else. It's + * intended for use by any random library. + */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* avoids confusing emacs indentation */ +#endif +#endif + +/* Normally docs are in .c files, but there isn't a .c file for this. */ +/** + * @defgroup DBusProtocol Protocol constants + * @ingroup DBus + * + * @brief Defines constants which are part of the D-Bus protocol + * + * This header is intended for use by any library, not only libdbus. + * + * @{ + */ + + +/* Message byte order */ +#define DBUS_LITTLE_ENDIAN ('l') /**< Code marking LSB-first byte order in the wire protocol. */ +#define DBUS_BIG_ENDIAN ('B') /**< Code marking MSB-first byte order in the wire protocol. */ + +/** Protocol version. */ +#define DBUS_MAJOR_PROTOCOL_VERSION 1 + +/** Type code that is never equal to a legitimate type code */ +#define DBUS_TYPE_INVALID ((int) '\0') +/** #DBUS_TYPE_INVALID as a string literal instead of a int literal */ +#define DBUS_TYPE_INVALID_AS_STRING "\0" + +/* Primitive types */ +/** Type code marking an 8-bit unsigned integer */ +#define DBUS_TYPE_BYTE ((int) 'y') +/** #DBUS_TYPE_BYTE as a string literal instead of a int literal */ +#define DBUS_TYPE_BYTE_AS_STRING "y" +/** Type code marking a boolean */ +#define DBUS_TYPE_BOOLEAN ((int) 'b') +/** #DBUS_TYPE_BOOLEAN as a string literal instead of a int literal */ +#define DBUS_TYPE_BOOLEAN_AS_STRING "b" +/** Type code marking a 16-bit signed integer */ +#define DBUS_TYPE_INT16 ((int) 'n') +/** #DBUS_TYPE_INT16 as a string literal instead of a int literal */ +#define DBUS_TYPE_INT16_AS_STRING "n" +/** Type code marking a 16-bit unsigned integer */ +#define DBUS_TYPE_UINT16 ((int) 'q') +/** #DBUS_TYPE_UINT16 as a string literal instead of a int literal */ +#define DBUS_TYPE_UINT16_AS_STRING "q" +/** Type code marking a 32-bit signed integer */ +#define DBUS_TYPE_INT32 ((int) 'i') +/** #DBUS_TYPE_INT32 as a string literal instead of a int literal */ +#define DBUS_TYPE_INT32_AS_STRING "i" +/** Type code marking a 32-bit unsigned integer */ +#define DBUS_TYPE_UINT32 ((int) 'u') +/** #DBUS_TYPE_UINT32 as a string literal instead of a int literal */ +#define DBUS_TYPE_UINT32_AS_STRING "u" +/** Type code marking a 64-bit signed integer */ +#define DBUS_TYPE_INT64 ((int) 'x') +/** #DBUS_TYPE_INT64 as a string literal instead of a int literal */ +#define DBUS_TYPE_INT64_AS_STRING "x" +/** Type code marking a 64-bit unsigned integer */ +#define DBUS_TYPE_UINT64 ((int) 't') +/** #DBUS_TYPE_UINT64 as a string literal instead of a int literal */ +#define DBUS_TYPE_UINT64_AS_STRING "t" +/** Type code marking an 8-byte double in IEEE 754 format */ +#define DBUS_TYPE_DOUBLE ((int) 'd') +/** #DBUS_TYPE_DOUBLE as a string literal instead of a int literal */ +#define DBUS_TYPE_DOUBLE_AS_STRING "d" +/** Type code marking a UTF-8 encoded, nul-terminated Unicode string */ +#define DBUS_TYPE_STRING ((int) 's') +/** #DBUS_TYPE_STRING as a string literal instead of a int literal */ +#define DBUS_TYPE_STRING_AS_STRING "s" +/** Type code marking a D-Bus object path */ +#define DBUS_TYPE_OBJECT_PATH ((int) 'o') +/** #DBUS_TYPE_OBJECT_PATH as a string literal instead of a int literal */ +#define DBUS_TYPE_OBJECT_PATH_AS_STRING "o" +/** Type code marking a D-Bus type signature */ +#define DBUS_TYPE_SIGNATURE ((int) 'g') +/** #DBUS_TYPE_SIGNATURE as a string literal instead of a int literal */ +#define DBUS_TYPE_SIGNATURE_AS_STRING "g" + +/* Compound types */ +/** Type code marking a D-Bus array type */ +#define DBUS_TYPE_ARRAY ((int) 'a') +/** #DBUS_TYPE_ARRAY as a string literal instead of a int literal */ +#define DBUS_TYPE_ARRAY_AS_STRING "a" +/** Type code marking a D-Bus variant type */ +#define DBUS_TYPE_VARIANT ((int) 'v') +/** #DBUS_TYPE_VARIANT as a string literal instead of a int literal */ +#define DBUS_TYPE_VARIANT_AS_STRING "v" + +/** STRUCT and DICT_ENTRY are sort of special since their codes can't + * appear in a type string, instead + * DBUS_STRUCT_BEGIN_CHAR/DBUS_DICT_ENTRY_BEGIN_CHAR have to appear + */ +/** Type code used to represent a struct; however, this type code does not appear + * in type signatures, instead #DBUS_STRUCT_BEGIN_CHAR and #DBUS_STRUCT_END_CHAR will + * appear in a signature. + */ +#define DBUS_TYPE_STRUCT ((int) 'r') +/** #DBUS_TYPE_STRUCT as a string literal instead of a int literal */ +#define DBUS_TYPE_STRUCT_AS_STRING "r" +/** Type code used to represent a dict entry; however, this type code does not appear + * in type signatures, instead #DBUS_DICT_ENTRY_BEGIN_CHAR and #DBUS_DICT_ENTRY_END_CHAR will + * appear in a signature. + */ +#define DBUS_TYPE_DICT_ENTRY ((int) 'e') +/** #DBUS_TYPE_DICT_ENTRY as a string literal instead of a int literal */ +#define DBUS_TYPE_DICT_ENTRY_AS_STRING "e" + +/** Does not include #DBUS_TYPE_INVALID, #DBUS_STRUCT_BEGIN_CHAR, #DBUS_STRUCT_END_CHAR, + * #DBUS_DICT_ENTRY_BEGIN_CHAR, or #DBUS_DICT_ENTRY_END_CHAR - i.e. it is the number of + * valid types, not the number of distinct characters that may appear in a type signature. + */ +#define DBUS_NUMBER_OF_TYPES (16) + +/* characters other than typecodes that appear in type signatures */ + +/** Code marking the start of a struct type in a type signature */ +#define DBUS_STRUCT_BEGIN_CHAR ((int) '(') +/** #DBUS_STRUCT_BEGIN_CHAR as a string literal instead of a int literal */ +#define DBUS_STRUCT_BEGIN_CHAR_AS_STRING "(" +/** Code marking the end of a struct type in a type signature */ +#define DBUS_STRUCT_END_CHAR ((int) ')') +/** #DBUS_STRUCT_END_CHAR a string literal instead of a int literal */ +#define DBUS_STRUCT_END_CHAR_AS_STRING ")" +/** Code marking the start of a dict entry type in a type signature */ +#define DBUS_DICT_ENTRY_BEGIN_CHAR ((int) '{') +/** #DBUS_DICT_ENTRY_BEGIN_CHAR as a string literal instead of a int literal */ +#define DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING "{" +/** Code marking the end of a dict entry type in a type signature */ +#define DBUS_DICT_ENTRY_END_CHAR ((int) '}') +/** #DBUS_DICT_ENTRY_END_CHAR as a string literal instead of a int literal */ +#define DBUS_DICT_ENTRY_END_CHAR_AS_STRING "}" + +/** Max length in bytes of a bus name, interface, or member (not object + * path, paths are unlimited). This is limited because lots of stuff + * is O(n) in this number, plus it would be obnoxious to type in a + * paragraph-long method name so most likely something like that would + * be an exploit. + */ +#define DBUS_MAXIMUM_NAME_LENGTH 255 + +/** This one is 255 so it fits in a byte */ +#define DBUS_MAXIMUM_SIGNATURE_LENGTH 255 + +/** Max length of a match rule string; to keep people from hosing the + * daemon with some huge rule + */ +#define DBUS_MAXIMUM_MATCH_RULE_LENGTH 1024 + +/** Max arg number you can match on in a match rule, e.g. + * arg0='hello' is OK, arg3489720987='hello' is not + */ +#define DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER 63 + +/** Max length of a marshaled array in bytes (64M, 2^26) We use signed + * int for lengths so must be INT_MAX or less. We need something a + * bit smaller than INT_MAX because the array is inside a message with + * header info, etc. so an INT_MAX array wouldn't allow the message + * overhead. The 64M number is an attempt at a larger number than + * we'd reasonably ever use, but small enough that your bus would chew + * through it fairly quickly without locking up forever. If you have + * data that's likely to be larger than this, you should probably be + * sending it in multiple incremental messages anyhow. + */ +#define DBUS_MAXIMUM_ARRAY_LENGTH (67108864) +/** Number of bits you need in an unsigned to store the max array size */ +#define DBUS_MAXIMUM_ARRAY_LENGTH_BITS 26 + +/** The maximum total message size including header and body; similar + * rationale to max array size. + */ +#define DBUS_MAXIMUM_MESSAGE_LENGTH (DBUS_MAXIMUM_ARRAY_LENGTH * 2) +/** Number of bits you need in an unsigned to store the max message size */ +#define DBUS_MAXIMUM_MESSAGE_LENGTH_BITS 27 + +/** Depth of recursion in the type tree. This is automatically limited + * to DBUS_MAXIMUM_SIGNATURE_LENGTH since you could only have an array + * of array of array of ... that fit in the max signature. But that's + * probably a bit too large. + */ +#define DBUS_MAXIMUM_TYPE_RECURSION_DEPTH 32 + +/* Types of message */ + +/** This value is never a valid message type, see dbus_message_get_type() */ +#define DBUS_MESSAGE_TYPE_INVALID 0 +/** Message type of a method call message, see dbus_message_get_type() */ +#define DBUS_MESSAGE_TYPE_METHOD_CALL 1 +/** Message type of a method return message, see dbus_message_get_type() */ +#define DBUS_MESSAGE_TYPE_METHOD_RETURN 2 +/** Message type of an error reply message, see dbus_message_get_type() */ +#define DBUS_MESSAGE_TYPE_ERROR 3 +/** Message type of a signal message, see dbus_message_get_type() */ +#define DBUS_MESSAGE_TYPE_SIGNAL 4 + +/* Header flags */ + +/** If set, this flag means that the sender of a message does not care about getting + * a reply, so the recipient need not send one. See dbus_message_set_no_reply(). + */ +#define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x1 +/** + * If set, this flag means that even if the message bus knows how to start an owner for + * the destination bus name (see dbus_message_set_destination()), it should not + * do so. If this flag is not set, the bus may launch a program to process the + * message. + */ +#define DBUS_HEADER_FLAG_NO_AUTO_START 0x2 + +/* Header fields */ + +/** Not equal to any valid header field code */ +#define DBUS_HEADER_FIELD_INVALID 0 +/** Header field code for the path - the path is the object emitting a signal or the object receiving a method call. + * See dbus_message_set_path(). + */ +#define DBUS_HEADER_FIELD_PATH 1 +/** Header field code for the interface containing a member (method or signal). + * See dbus_message_set_interface(). + */ +#define DBUS_HEADER_FIELD_INTERFACE 2 +/** Header field code for a member (method or signal). See dbus_message_set_member(). */ +#define DBUS_HEADER_FIELD_MEMBER 3 +/** Header field code for an error name (found in #DBUS_MESSAGE_TYPE_ERROR messages). + * See dbus_message_set_error_name(). + */ +#define DBUS_HEADER_FIELD_ERROR_NAME 4 +/** Header field code for a reply serial, used to match a #DBUS_MESSAGE_TYPE_METHOD_RETURN message with the + * message that it's a reply to. See dbus_message_set_reply_serial(). + */ +#define DBUS_HEADER_FIELD_REPLY_SERIAL 5 +/** + * Header field code for the destination bus name of a message. See dbus_message_set_destination(). + */ +#define DBUS_HEADER_FIELD_DESTINATION 6 +/** + * Header field code for the sender of a message; usually initialized by the message bus. + * See dbus_message_set_sender(). + */ +#define DBUS_HEADER_FIELD_SENDER 7 +/** + * Header field code for the type signature of a message. + */ +#define DBUS_HEADER_FIELD_SIGNATURE 8 + +/** + * Value of the highest-numbered header field code, can be used to determine + * the size of an array indexed by header field code. Remember though + * that unknown codes must be ignored, so check for that before + * indexing the array. + */ +#define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_SIGNATURE + +/** Header format is defined as a signature: + * byte byte order + * byte message type ID + * byte flags + * byte protocol version + * uint32 body length + * uint32 serial + * array of struct (byte,variant) (field name, value) + * + * The length of the header can be computed as the + * fixed size of the initial data, plus the length of + * the array at the end, plus padding to an 8-boundary. + */ +#define DBUS_HEADER_SIGNATURE \ + DBUS_TYPE_BYTE_AS_STRING \ + DBUS_TYPE_BYTE_AS_STRING \ + DBUS_TYPE_BYTE_AS_STRING \ + DBUS_TYPE_BYTE_AS_STRING \ + DBUS_TYPE_UINT32_AS_STRING \ + DBUS_TYPE_UINT32_AS_STRING \ + DBUS_TYPE_ARRAY_AS_STRING \ + DBUS_STRUCT_BEGIN_CHAR_AS_STRING \ + DBUS_TYPE_BYTE_AS_STRING \ + DBUS_TYPE_VARIANT_AS_STRING \ + DBUS_STRUCT_END_CHAR_AS_STRING + + +/** + * The smallest header size that can occur. (It won't be valid due to + * missing required header fields.) This is 4 bytes, two uint32, an + * array length. This isn't any kind of resource limit, just the + * necessary/logical outcome of the header signature. + */ +#define DBUS_MINIMUM_HEADER_SIZE 16 + +/* Errors */ +/* WARNING these get autoconverted to an enum in dbus-glib.h. Thus, + * if you change the order it breaks the ABI. Keep them in order. + * Also, don't change the formatting since that will break the sed + * script. + */ +/** A generic error; "something went wrong" - see the error message for more. */ +#define DBUS_ERROR_FAILED "org.freedesktop.DBus.Error.Failed" +/** There was not enough memory to complete an operation. */ +#define DBUS_ERROR_NO_MEMORY "org.freedesktop.DBus.Error.NoMemory" +/** The bus doesn't know how to launch a service to supply the bus name you wanted. */ +#define DBUS_ERROR_SERVICE_UNKNOWN "org.freedesktop.DBus.Error.ServiceUnknown" +/** The bus name you referenced doesn't exist (i.e. no application owns it). */ +#define DBUS_ERROR_NAME_HAS_NO_OWNER "org.freedesktop.DBus.Error.NameHasNoOwner" +/** No reply to a message expecting one, usually means a timeout occurred. */ +#define DBUS_ERROR_NO_REPLY "org.freedesktop.DBus.Error.NoReply" +/** Something went wrong reading or writing to a socket, for example. */ +#define DBUS_ERROR_IO_ERROR "org.freedesktop.DBus.Error.IOError" +/** A D-Bus bus address was malformed. */ +#define DBUS_ERROR_BAD_ADDRESS "org.freedesktop.DBus.Error.BadAddress" +/** Requested operation isn't supported (like ENOSYS on UNIX). */ +#define DBUS_ERROR_NOT_SUPPORTED "org.freedesktop.DBus.Error.NotSupported" +/** Some limited resource is exhausted. */ +#define DBUS_ERROR_LIMITS_EXCEEDED "org.freedesktop.DBus.Error.LimitsExceeded" +/** Security restrictions don't allow doing what you're trying to do. */ +#define DBUS_ERROR_ACCESS_DENIED "org.freedesktop.DBus.Error.AccessDenied" +/** Authentication didn't work. */ +#define DBUS_ERROR_AUTH_FAILED "org.freedesktop.DBus.Error.AuthFailed" +/** Unable to connect to server (probably caused by ECONNREFUSED on a socket). */ +#define DBUS_ERROR_NO_SERVER "org.freedesktop.DBus.Error.NoServer" +/** Certain timeout errors, possibly ETIMEDOUT on a socket. + * Note that #DBUS_ERROR_NO_REPLY is used for message reply timeouts. + * @warning this is confusingly-named given that #DBUS_ERROR_TIMED_OUT also exists. We can't fix + * it for compatibility reasons so just be careful. + */ +#define DBUS_ERROR_TIMEOUT "org.freedesktop.DBus.Error.Timeout" +/** No network access (probably ENETUNREACH on a socket). */ +#define DBUS_ERROR_NO_NETWORK "org.freedesktop.DBus.Error.NoNetwork" +/** Can't bind a socket since its address is in use (i.e. EADDRINUSE). */ +#define DBUS_ERROR_ADDRESS_IN_USE "org.freedesktop.DBus.Error.AddressInUse" +/** The connection is disconnected and you're trying to use it. */ +#define DBUS_ERROR_DISCONNECTED "org.freedesktop.DBus.Error.Disconnected" +/** Invalid arguments passed to a method call. */ +#define DBUS_ERROR_INVALID_ARGS "org.freedesktop.DBus.Error.InvalidArgs" +/** Missing file. */ +#define DBUS_ERROR_FILE_NOT_FOUND "org.freedesktop.DBus.Error.FileNotFound" +/** Existing file and the operation you're using does not silently overwrite. */ +#define DBUS_ERROR_FILE_EXISTS "org.freedesktop.DBus.Error.FileExists" +/** Method name you invoked isn't known by the object you invoked it on. */ +#define DBUS_ERROR_UNKNOWN_METHOD "org.freedesktop.DBus.Error.UnknownMethod" +/** Certain timeout errors, e.g. while starting a service. + * @warning this is confusingly-named given that #DBUS_ERROR_TIMEOUT also exists. We can't fix + * it for compatibility reasons so just be careful. + */ +#define DBUS_ERROR_TIMED_OUT "org.freedesktop.DBus.Error.TimedOut" +/** Tried to remove or modify a match rule that didn't exist. */ +#define DBUS_ERROR_MATCH_RULE_NOT_FOUND "org.freedesktop.DBus.Error.MatchRuleNotFound" +/** The match rule isn't syntactically valid. */ +#define DBUS_ERROR_MATCH_RULE_INVALID "org.freedesktop.DBus.Error.MatchRuleInvalid" +/** While starting a new process, the exec() call failed. */ +#define DBUS_ERROR_SPAWN_EXEC_FAILED "org.freedesktop.DBus.Error.Spawn.ExecFailed" +/** While starting a new process, the fork() call failed. */ +#define DBUS_ERROR_SPAWN_FORK_FAILED "org.freedesktop.DBus.Error.Spawn.ForkFailed" +/** While starting a new process, the child exited with a status code. */ +#define DBUS_ERROR_SPAWN_CHILD_EXITED "org.freedesktop.DBus.Error.Spawn.ChildExited" +/** While starting a new process, the child exited on a signal. */ +#define DBUS_ERROR_SPAWN_CHILD_SIGNALED "org.freedesktop.DBus.Error.Spawn.ChildSignaled" +/** While starting a new process, something went wrong. */ +#define DBUS_ERROR_SPAWN_FAILED "org.freedesktop.DBus.Error.Spawn.Failed" +/** We failed to setup the environment correctly. */ +#define DBUS_ERROR_SPAWN_SETUP_FAILED "org.freedesktop.DBus.Error.Spawn.FailedToSetup" +/** We failed to setup the config parser correctly. */ +#define DBUS_ERROR_SPAWN_CONFIG_INVALID "org.freedesktop.DBus.Error.Spawn.ConfigInvalid" +/** Bus name was not valid. */ +#define DBUS_ERROR_SPAWN_SERVICE_INVALID "org.freedesktop.DBus.Error.Spawn.ServiceNotValid" +/** Service file not found in system-services directory. */ +#define DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND "org.freedesktop.DBus.Error.Spawn.ServiceNotFound" +/** Permissions are incorrect on the setuid helper. */ +#define DBUS_ERROR_SPAWN_PERMISSIONS_INVALID "org.freedesktop.DBus.Error.Spawn.PermissionsInvalid" +/** Service file invalid (Name, User or Exec missing). */ +#define DBUS_ERROR_SPAWN_FILE_INVALID "org.freedesktop.DBus.Error.Spawn.FileInvalid" +/** Tried to get a UNIX process ID and it wasn't available. */ +#define DBUS_ERROR_SPAWN_NO_MEMORY "org.freedesktop.DBus.Error.Spawn.NoMemory" +/** Tried to get a UNIX process ID and it wasn't available. */ +#define DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN "org.freedesktop.DBus.Error.UnixProcessIdUnknown" +/** A type signature is not valid. */ +#define DBUS_ERROR_INVALID_SIGNATURE "org.freedesktop.DBus.Error.InvalidSignature" +/** A file contains invalid syntax or is otherwise broken. */ +#define DBUS_ERROR_INVALID_FILE_CONTENT "org.freedesktop.DBus.Error.InvalidFileContent" +/** Asked for SELinux security context and it wasn't available. */ +#define DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown" +/** Asked for ADT audit data and it wasn't available. */ +#define DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN "org.freedesktop.DBus.Error.AdtAuditDataUnknown" +/** There's already an object with the requested object path. */ +#define DBUS_ERROR_OBJECT_PATH_IN_USE "org.freedesktop.DBus.Error.ObjectPathInUse" + +/* XML introspection format */ + +/** XML namespace of the introspection format version 1.0 */ +#define DBUS_INTROSPECT_1_0_XML_NAMESPACE "http://www.freedesktop.org/standards/dbus" +/** XML public identifier of the introspection format version 1.0 */ +#define DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" +/** XML system identifier of the introspection format version 1.0 */ +#define DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" +/** XML document type declaration of the introspection format version 1.0 */ +#define DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "\n" + +/** @} */ + +#ifdef __cplusplus +#if 0 +{ /* avoids confusing emacs indentation */ +#endif +} +#endif + +#endif /* DBUS_PROTOCOL_H */ diff --git a/dbus/dbus-resources.c b/dbus/dbus-resources.c new file mode 100644 index 00000000..bfe8a089 --- /dev/null +++ b/dbus/dbus-resources.c @@ -0,0 +1,194 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-resources.c Resource tracking/limits + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include +#include + +/** + * @defgroup DBusResources Resource limits related code + * @ingroup DBusInternals + * @brief DBusCounter and other stuff related to resource limits + * + * Types and functions related to tracking resource limits, + * such as the maximum amount of memory a connection can use + * for messages, etc. + */ + +/** + * @defgroup DBusResourcesInternals Resource limits implementation details + * @ingroup DBusInternals + * @brief Resource limits implementation details + * + * Implementation details of resource limits code. + * + * @{ + */ + +/** + * @brief Internals of DBusCounter. + * + * DBusCounter internals. DBusCounter is an opaque object, it must be + * used via accessor functions. + */ +struct DBusCounter +{ + int refcount; /**< reference count */ + + long value; /**< current counter value */ + + long notify_guard_value; /**< call notify function when crossing this value */ + DBusCounterNotifyFunction notify_function; /**< notify function */ + void *notify_data; /**< data for notify function */ +}; + +/** @} */ /* end of resource limits internals docs */ + +/** + * @addtogroup DBusResources + * @{ + */ + +/** + * Creates a new DBusCounter. DBusCounter is used + * to count usage of some resource such as memory. + * + * @returns new counter or #NULL on failure + */ +DBusCounter* +_dbus_counter_new (void) +{ + DBusCounter *counter; + + counter = dbus_new (DBusCounter, 1); + if (counter == NULL) + return NULL; + + counter->refcount = 1; + counter->value = 0; + + counter->notify_guard_value = 0; + counter->notify_function = NULL; + counter->notify_data = NULL; + + return counter; +} + +/** + * Increments refcount of the counter + * + * @param counter the counter + * @returns the counter + */ +DBusCounter * +_dbus_counter_ref (DBusCounter *counter) +{ + _dbus_assert (counter->refcount > 0); + + counter->refcount += 1; + + return counter; +} + +/** + * Decrements refcount of the counter and possibly + * finalizes the counter. + * + * @param counter the counter + */ +void +_dbus_counter_unref (DBusCounter *counter) +{ + _dbus_assert (counter->refcount > 0); + + counter->refcount -= 1; + + if (counter->refcount == 0) + { + + dbus_free (counter); + } +} + +/** + * Adjusts the value of the counter by the given + * delta which may be positive or negative. + * Calls the notify function from _dbus_counter_set_notify() + * if that function has been specified. + * + * @param counter the counter + * @param delta value to add to the counter's current value + */ +void +_dbus_counter_adjust (DBusCounter *counter, + long delta) +{ + long old = counter->value; + + counter->value += delta; + +#if 0 + _dbus_verbose ("Adjusting counter %ld by %ld = %ld\n", + old, delta, counter->value); +#endif + + if (counter->notify_function != NULL && + ((old < counter->notify_guard_value && + counter->value >= counter->notify_guard_value) || + (old >= counter->notify_guard_value && + counter->value < counter->notify_guard_value))) + (* counter->notify_function) (counter, counter->notify_data); +} + +/** + * Gets the current value of the counter. + * + * @param counter the counter + * @returns its current value + */ +long +_dbus_counter_get_value (DBusCounter *counter) +{ + return counter->value; +} + +/** + * Sets the notify function for this counter; the notify function is + * called whenever the counter's value crosses the guard value in + * either direction (moving up, or moving down). + * + * @param counter the counter + * @param guard_value the value we're notified if the counter crosses + * @param function function to call in order to notify + * @param user_data data to pass to the function + */ +void +_dbus_counter_set_notify (DBusCounter *counter, + long guard_value, + DBusCounterNotifyFunction function, + void *user_data) +{ + counter->notify_guard_value = guard_value; + counter->notify_function = function; + counter->notify_data = user_data; +} + +/** @} */ /* end of resource limits exported API */ diff --git a/dbus/dbus-resources.h b/dbus/dbus-resources.h new file mode 100644 index 00000000..f87a56a3 --- /dev/null +++ b/dbus/dbus-resources.h @@ -0,0 +1,52 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-resources.h Resource tracking/limits + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_RESOURCES_H +#define DBUS_RESOURCES_H + +#include +#include +#include + +DBUS_BEGIN_DECLS + +typedef struct DBusCounter DBusCounter; + +typedef void (* DBusCounterNotifyFunction) (DBusCounter *counter, + void *user_data); + +DBusCounter* _dbus_counter_new (void); +DBusCounter* _dbus_counter_ref (DBusCounter *counter); +void _dbus_counter_unref (DBusCounter *counter); +void _dbus_counter_adjust (DBusCounter *counter, + long delta); +long _dbus_counter_get_value (DBusCounter *counter); + +void _dbus_counter_set_notify (DBusCounter *counter, + long guard_value, + DBusCounterNotifyFunction function, + void *user_data); + + +DBUS_END_DECLS + +#endif /* DBUS_RESOURCES_H */ diff --git a/dbus/dbus-server-debug-pipe.c b/dbus/dbus-server-debug-pipe.c new file mode 100644 index 00000000..fe7c970b --- /dev/null +++ b/dbus/dbus-server-debug-pipe.c @@ -0,0 +1,432 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-server-debug-pipe.c In-proc debug server implementation + * + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2003, 2004 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-server-debug-pipe.h" +#include "dbus-transport-socket.h" +#include "dbus-connection-internal.h" +#include "dbus-hash.h" +#include "dbus-string.h" +#include "dbus-protocol.h" + +#ifdef DBUS_BUILD_TESTS + +/** + * @defgroup DBusServerDebugPipe DBusServerDebugPipe + * @ingroup DBusInternals + * @brief In-process pipe debug server used in unit tests. + * + * Types and functions related to DBusServerDebugPipe. + * This is used for unit testing. + * + * @{ + */ + +/** + * Opaque object representing a debug server implementation. + */ +typedef struct DBusServerDebugPipe DBusServerDebugPipe; + +/** + * Implementation details of DBusServerDebugPipe. All members + * are private. + */ +struct DBusServerDebugPipe +{ + DBusServer base; /**< Parent class members. */ + + char *name; /**< Server name. */ + + dbus_bool_t disconnected; /**< TRUE if disconnect has been called */ +}; + +/* FIXME not threadsafe (right now the test suite doesn't use threads anyhow ) */ +static DBusHashTable *server_pipe_hash; +static int server_pipe_hash_refcount = 0; + +static dbus_bool_t +pipe_hash_ref (void) +{ + if (!server_pipe_hash) + { + _dbus_assert (server_pipe_hash_refcount == 0); + + server_pipe_hash = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, NULL); + + if (!server_pipe_hash) + return FALSE; + } + + server_pipe_hash_refcount = 1; + + return TRUE; +} + +static void +pipe_hash_unref (void) +{ + _dbus_assert (server_pipe_hash != NULL); + _dbus_assert (server_pipe_hash_refcount > 0); + + server_pipe_hash_refcount -= 1; + if (server_pipe_hash_refcount == 0) + { + _dbus_hash_table_unref (server_pipe_hash); + server_pipe_hash = NULL; + } +} + +static void +debug_finalize (DBusServer *server) +{ + DBusServerDebugPipe *debug_server = (DBusServerDebugPipe*) server; + + pipe_hash_unref (); + + _dbus_server_finalize_base (server); + + dbus_free (debug_server->name); + dbus_free (server); +} + +static void +debug_disconnect (DBusServer *server) +{ + ((DBusServerDebugPipe*)server)->disconnected = TRUE; +} + +static DBusServerVTable debug_vtable = { + debug_finalize, + debug_disconnect +}; + +/** + * Creates a new debug server using an in-process pipe + * + * @param server_name the name of the server. + * @param error address where an error can be returned. + * @returns a new server, or #NULL on failure. + */ +DBusServer* +_dbus_server_debug_pipe_new (const char *server_name, + DBusError *error) +{ + DBusServerDebugPipe *debug_server; + DBusString address; + DBusString name_str; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!pipe_hash_ref ()) + return NULL; + + if (_dbus_hash_table_lookup_string (server_pipe_hash, server_name) != NULL) + { + dbus_set_error (error, DBUS_ERROR_ADDRESS_IN_USE, NULL); + pipe_hash_unref (); + return NULL; + } + + debug_server = dbus_new0 (DBusServerDebugPipe, 1); + if (debug_server == NULL) + goto nomem_0; + + if (!_dbus_string_init (&address)) + goto nomem_1; + + _dbus_string_init_const (&name_str, server_name); + if (!_dbus_string_append (&address, "debug-pipe:name=") || + !_dbus_address_append_escaped (&address, &name_str)) + goto nomem_2; + + debug_server->name = _dbus_strdup (server_name); + if (debug_server->name == NULL) + goto nomem_2; + + if (!_dbus_server_init_base (&debug_server->base, + &debug_vtable, &address)) + goto nomem_3; + + if (!_dbus_hash_table_insert_string (server_pipe_hash, + debug_server->name, + debug_server)) + goto nomem_4; + + _dbus_string_free (&address); + + /* server keeps the pipe hash ref */ + + return (DBusServer *)debug_server; + + nomem_4: + _dbus_server_finalize_base (&debug_server->base); + nomem_3: + dbus_free (debug_server->name); + nomem_2: + _dbus_string_free (&address); + nomem_1: + dbus_free (debug_server); + nomem_0: + pipe_hash_unref (); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; +} + +/** + * Creates the client-side transport for + * a debug-pipe connection connected to the + * given debug-pipe server name. + * + * @param server_name name of server to connect to + * @param error address where an error can be returned. + * @returns #NULL on no memory or transport + */ +DBusTransport* +_dbus_transport_debug_pipe_new (const char *server_name, + DBusError *error) +{ + DBusTransport *client_transport; + DBusTransport *server_transport; + DBusConnection *connection; + int client_fd, server_fd; + DBusServer *server; + DBusString address; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (server_pipe_hash == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL); + return NULL; + } + + server = _dbus_hash_table_lookup_string (server_pipe_hash, + server_name); + if (server == NULL || + ((DBusServerDebugPipe*)server)->disconnected) + { + dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL); + return NULL; + } + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (!_dbus_string_append (&address, "debug-pipe:name=") || + !_dbus_string_append (&address, server_name)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (&address); + return NULL; + } + + if (!_dbus_full_duplex_pipe (&client_fd, &server_fd, FALSE, + NULL)) + { + _dbus_verbose ("failed to create full duplex pipe\n"); + dbus_set_error (error, DBUS_ERROR_FAILED, "Could not create full-duplex pipe"); + _dbus_string_free (&address); + return NULL; + } + + _dbus_fd_set_close_on_exec (client_fd); + _dbus_fd_set_close_on_exec (server_fd); + + client_transport = _dbus_transport_new_for_socket (client_fd, + NULL, &address); + if (client_transport == NULL) + { + _dbus_close_socket (client_fd, NULL); + _dbus_close_socket (server_fd, NULL); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (&address); + return NULL; + } + + _dbus_string_free (&address); + + client_fd = -1; + + server_transport = _dbus_transport_new_for_socket (server_fd, + &server->guid_hex, NULL); + if (server_transport == NULL) + { + _dbus_transport_unref (client_transport); + _dbus_close_socket (server_fd, NULL); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + server_fd = -1; + + if (!_dbus_transport_set_auth_mechanisms (server_transport, + (const char**) server->auth_mechanisms)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_transport_unref (server_transport); + _dbus_transport_unref (client_transport); + return NULL; + } + + connection = _dbus_connection_new_for_transport (server_transport); + _dbus_transport_unref (server_transport); + server_transport = NULL; + + if (connection == NULL) + { + _dbus_transport_unref (client_transport); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + /* See if someone wants to handle this new connection, + * self-referencing for paranoia + */ + if (server->new_connection_function) + { + dbus_server_ref (server); + (* server->new_connection_function) (server, connection, + server->new_connection_data); + dbus_server_unref (server); + } + + /* If no one grabbed a reference, the connection will die, + * and the client transport will get an immediate disconnect + */ + _dbus_connection_close_if_only_one_ref (connection); + dbus_connection_unref (connection); + + return client_transport; +} + +/** + * Tries to interpret the address entry as a debug pipe entry. + * + * Sets error if the result is not OK. + * + * @param entry an address entry + * @param server_p location to store a new DBusServer, or #NULL on failure. + * @param error location to store rationale for failure on bad address + * @returns the outcome + * + */ +DBusServerListenResult +_dbus_server_listen_debug_pipe (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error) +{ + const char *method; + + *server_p = NULL; + + method = dbus_address_entry_get_method (entry); + + if (strcmp (method, "debug-pipe") == 0) + { + const char *name = dbus_address_entry_get_value (entry, "name"); + + if (name == NULL) + { + _dbus_set_bad_address(error, "debug-pipe", "name", + NULL); + return DBUS_SERVER_LISTEN_BAD_ADDRESS; + } + + *server_p = _dbus_server_debug_pipe_new (name, error); + + if (*server_p) + { + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_OK; + } + else + { + _DBUS_ASSERT_ERROR_IS_SET(error); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_NOT_HANDLED; + } +} + +/** + * Opens a debug pipe transport, used in the test suite. + * + * @param entry the address entry to try opening as debug-pipe + * @param transport_p return location for the opened transport + * @param error error to be set + * @returns result of the attempt + */ +DBusTransportOpenResult +_dbus_transport_open_debug_pipe (DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error) +{ + const char *method; + + method = dbus_address_entry_get_method (entry); + _dbus_assert (method != NULL); + + if (strcmp (method, "debug-pipe") == 0) + { + const char *name = dbus_address_entry_get_value (entry, "name"); + + if (name == NULL) + { + _dbus_set_bad_address (error, "debug-pipe", "name", + NULL); + return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; + } + + *transport_p = _dbus_transport_debug_pipe_new (name, error); + + if (*transport_p == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return DBUS_TRANSPORT_OPEN_OK; + } + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return DBUS_TRANSPORT_OPEN_NOT_HANDLED; + } +} + + +/** @} */ + +#endif /* DBUS_BUILD_TESTS */ + diff --git a/dbus/dbus-server-debug-pipe.h b/dbus/dbus-server-debug-pipe.h new file mode 100644 index 00000000..4574311d --- /dev/null +++ b/dbus/dbus-server-debug-pipe.h @@ -0,0 +1,47 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-server-debug-pipe.h In-proc debug server implementation + * + * Copyright (C) 2003 CodeFactory AB + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_SERVER_DEBUG_PIPE_H +#define DBUS_SERVER_DEBUG_PIPE_H + +#include +#include +#include + +DBUS_BEGIN_DECLS + +DBusServer* _dbus_server_debug_pipe_new (const char *server_name, + DBusError *error); +DBusTransport* _dbus_transport_debug_pipe_new (const char *server_name, + DBusError *error); +DBusServerListenResult _dbus_server_listen_debug_pipe (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error); +DBusTransportOpenResult _dbus_transport_open_debug_pipe (DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error); + + +DBUS_END_DECLS + +#endif /* DBUS_SERVER_DEBUG_PIPE_H */ diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h new file mode 100644 index 00000000..c05d2779 --- /dev/null +++ b/dbus/dbus-server-protected.h @@ -0,0 +1,160 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-server-protected.h Used by subclasses of DBusServer object (internal to D-Bus implementation) + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_SERVER_PROTECTED_H +#define DBUS_SERVER_PROTECTED_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +typedef struct DBusServerVTable DBusServerVTable; + +/** + * Virtual table to be implemented by all server "subclasses" + */ +struct DBusServerVTable +{ + void (* finalize) (DBusServer *server); + /**< The finalize method must free the server. */ + + void (* disconnect) (DBusServer *server); + /**< Disconnect this server. */ +}; + +/** + * Internals of DBusServer object + */ +struct DBusServer +{ + DBusAtomic refcount; /**< Reference count. */ + const DBusServerVTable *vtable; /**< Virtual methods for this instance. */ + DBusMutex *mutex; /**< Lock on the server object */ + + DBusGUID guid; /**< Globally unique ID of server */ + + DBusString guid_hex; /**< Hex-encoded version of GUID */ + + DBusWatchList *watches; /**< Our watches */ + DBusTimeoutList *timeouts; /**< Our timeouts */ + + char *address; /**< Address this server is listening on. */ + + int max_connections; /**< Max number of connections allowed at once. */ + + DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */ + + DBusNewConnectionFunction new_connection_function; + /**< Callback to invoke when a new connection is created. */ + void *new_connection_data; + /**< Data for new connection callback */ + DBusFreeFunction new_connection_free_data_function; + /**< Callback to invoke to free new_connection_data + * when server is finalized or data is replaced. + */ + + char **auth_mechanisms; /**< Array of allowed authentication mechanisms */ + + unsigned int disconnected : 1; /**< TRUE if we are disconnected. */ + +#ifndef DBUS_DISABLE_CHECKS + unsigned int have_server_lock : 1; /**< Does someone have the server mutex locked */ +#endif +}; + +dbus_bool_t _dbus_server_init_base (DBusServer *server, + const DBusServerVTable *vtable, + const DBusString *address); +void _dbus_server_finalize_base (DBusServer *server); +dbus_bool_t _dbus_server_add_watch (DBusServer *server, + DBusWatch *watch); +void _dbus_server_remove_watch (DBusServer *server, + DBusWatch *watch); +void _dbus_server_toggle_watch (DBusServer *server, + DBusWatch *watch, + dbus_bool_t enabled); +dbus_bool_t _dbus_server_add_timeout (DBusServer *server, + DBusTimeout *timeout); +void _dbus_server_remove_timeout (DBusServer *server, + DBusTimeout *timeout); +void _dbus_server_toggle_timeout (DBusServer *server, + DBusTimeout *timeout, + dbus_bool_t enabled); + +void _dbus_server_ref_unlocked (DBusServer *server); +void _dbus_server_unref_unlocked (DBusServer *server); + +typedef enum +{ + DBUS_SERVER_LISTEN_NOT_HANDLED, /**< we aren't in charge of this address type */ + DBUS_SERVER_LISTEN_OK, /**< we set up the listen */ + DBUS_SERVER_LISTEN_BAD_ADDRESS, /**< malformed address */ + DBUS_SERVER_LISTEN_DID_NOT_CONNECT /**< well-formed address but failed to set it up */ +} DBusServerListenResult; + +DBusServerListenResult _dbus_server_listen_platform_specific (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error); + +#ifdef DBUS_DISABLE_CHECKS +#define TOOK_LOCK_CHECK(server) +#define RELEASING_LOCK_CHECK(server) +#define HAVE_LOCK_CHECK(server) +#else +#define TOOK_LOCK_CHECK(server) do { \ + _dbus_assert (!(server)->have_server_lock); \ + (server)->have_server_lock = TRUE; \ + } while (0) +#define RELEASING_LOCK_CHECK(server) do { \ + _dbus_assert ((server)->have_server_lock); \ + (server)->have_server_lock = FALSE; \ + } while (0) +#define HAVE_LOCK_CHECK(server) _dbus_assert ((server)->have_server_lock) +/* A "DO_NOT_HAVE_LOCK_CHECK" is impossible since we need the lock to check the flag */ +#endif + +#define TRACE_LOCKS 0 + +#define SERVER_LOCK(server) do { \ + if (TRACE_LOCKS) { _dbus_verbose (" LOCK: %s\n", _DBUS_FUNCTION_NAME); } \ + _dbus_mutex_lock ((server)->mutex); \ + TOOK_LOCK_CHECK (server); \ + } while (0) + +#define SERVER_UNLOCK(server) do { \ + if (TRACE_LOCKS) { _dbus_verbose (" UNLOCK: %s\n", _DBUS_FUNCTION_NAME); } \ + RELEASING_LOCK_CHECK (server); \ + _dbus_mutex_unlock ((server)->mutex); \ + } while (0) + +DBUS_END_DECLS + +#endif /* DBUS_SERVER_PROTECTED_H */ diff --git a/dbus/dbus-server-socket.c b/dbus/dbus-server-socket.c new file mode 100644 index 00000000..bd38ce6a --- /dev/null +++ b/dbus/dbus-server-socket.c @@ -0,0 +1,539 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-server-socket.c Server implementation for sockets + * + * Copyright (C) 2002, 2003, 2004, 2006 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-server-socket.h" +#include "dbus-transport-socket.h" +#include "dbus-connection-internal.h" +#include "dbus-string.h" + +/** + * @defgroup DBusServerSocket DBusServer implementations for SOCKET + * @ingroup DBusInternals + * @brief Implementation details of DBusServer on SOCKET + * + * @{ + */ +/** + * + * Opaque object representing a Socket server implementation. + */ +typedef struct DBusServerSocket DBusServerSocket; + +/** + * Implementation details of DBusServerSocket. All members + * are private. + */ +struct DBusServerSocket +{ + DBusServer base; /**< Parent class members. */ + int n_fds; /**< Number of active file handles */ + int *fds; /**< File descriptor or -1 if disconnected. */ + DBusWatch **watch; /**< File descriptor watch. */ + char *socket_name; /**< Name of domain socket, to unlink if appropriate */ +}; + +static void +socket_finalize (DBusServer *server) +{ + DBusServerSocket *socket_server = (DBusServerSocket*) server; + int i; + + _dbus_server_finalize_base (server); + + for (i = 0 ; i < socket_server->n_fds ; i++) + if (socket_server->watch[i]) + { + _dbus_watch_unref (socket_server->watch[i]); + socket_server->watch[i] = NULL; + } + + dbus_free (socket_server->fds); + dbus_free (socket_server->watch); + dbus_free (socket_server->socket_name); + dbus_free (server); +} + +/* Return value is just for memory, not other failures. */ +static dbus_bool_t +handle_new_client_fd_and_unlock (DBusServer *server, + int client_fd) +{ + DBusConnection *connection; + DBusTransport *transport; + DBusNewConnectionFunction new_connection_function; + void *new_connection_data; + + _dbus_verbose ("Creating new client connection with fd %d\n", client_fd); + + HAVE_LOCK_CHECK (server); + + if (!_dbus_set_fd_nonblocking (client_fd, NULL)) + { + SERVER_UNLOCK (server); + return TRUE; + } + + transport = _dbus_transport_new_for_socket (client_fd, &server->guid_hex, NULL); + if (transport == NULL) + { + _dbus_close_socket (client_fd, NULL); + SERVER_UNLOCK (server); + return FALSE; + } + + if (!_dbus_transport_set_auth_mechanisms (transport, + (const char **) server->auth_mechanisms)) + { + _dbus_transport_unref (transport); + SERVER_UNLOCK (server); + return FALSE; + } + + /* note that client_fd is now owned by the transport, and will be + * closed on transport disconnection/finalization + */ + + connection = _dbus_connection_new_for_transport (transport); + _dbus_transport_unref (transport); + transport = NULL; /* now under the connection lock */ + + if (connection == NULL) + { + SERVER_UNLOCK (server); + return FALSE; + } + + /* See if someone wants to handle this new connection, self-referencing + * for paranoia. + */ + new_connection_function = server->new_connection_function; + new_connection_data = server->new_connection_data; + + _dbus_server_ref_unlocked (server); + SERVER_UNLOCK (server); + + if (new_connection_function) + { + (* new_connection_function) (server, connection, + new_connection_data); + } + dbus_server_unref (server); + + /* If no one grabbed a reference, the connection will die. */ + _dbus_connection_close_if_only_one_ref (connection); + dbus_connection_unref (connection); + + return TRUE; +} + +static dbus_bool_t +socket_handle_watch (DBusWatch *watch, + unsigned int flags, + void *data) +{ + DBusServer *server = data; +#ifndef DBUS_DISABLE_ASSERT + DBusServerSocket *socket_server = data; + int i; + dbus_bool_t found = FALSE; +#endif + + SERVER_LOCK (server); + +#ifndef DBUS_DISABLE_ASSERT + for (i = 0 ; i < socket_server->n_fds ; i++) + { + if (socket_server->watch[i] == watch) + found = TRUE; + } + _dbus_assert (found); +#endif + + _dbus_verbose ("Handling client connection, flags 0x%x\n", flags); + + if (flags & DBUS_WATCH_READABLE) + { + int client_fd; + int listen_fd; + + listen_fd = dbus_watch_get_socket (watch); + + client_fd = _dbus_accept (listen_fd); + + if (client_fd < 0) + { + /* EINTR handled for us */ + + if (_dbus_get_is_errno_eagain_or_ewouldblock ()) + _dbus_verbose ("No client available to accept after all\n"); + else + _dbus_verbose ("Failed to accept a client connection: %s\n", + _dbus_strerror_from_errno ()); + + SERVER_UNLOCK (server); + } + else + { + _dbus_fd_set_close_on_exec (client_fd); + + if (!handle_new_client_fd_and_unlock (server, client_fd)) + _dbus_verbose ("Rejected client connection due to lack of memory\n"); + } + } + + if (flags & DBUS_WATCH_ERROR) + _dbus_verbose ("Error on server listening socket\n"); + + if (flags & DBUS_WATCH_HANGUP) + _dbus_verbose ("Hangup on server listening socket\n"); + + return TRUE; +} + +static void +socket_disconnect (DBusServer *server) +{ + DBusServerSocket *socket_server = (DBusServerSocket*) server; + int i; + + HAVE_LOCK_CHECK (server); + + for (i = 0 ; i < socket_server->n_fds ; i++) + { + if (socket_server->watch[i]) + { + _dbus_server_remove_watch (server, + socket_server->watch[i]); + _dbus_watch_unref (socket_server->watch[i]); + socket_server->watch[i] = NULL; + } + + _dbus_close_socket (socket_server->fds[i], NULL); + socket_server->fds[i] = -1; + } + + if (socket_server->socket_name != NULL) + { + DBusString tmp; + _dbus_string_init_const (&tmp, socket_server->socket_name); + _dbus_delete_file (&tmp, NULL); + } + + HAVE_LOCK_CHECK (server); +} + +static const DBusServerVTable socket_vtable = { + socket_finalize, + socket_disconnect +}; + +/** + * Creates a new server listening on the given file descriptor. The + * file descriptor should be nonblocking (use + * _dbus_set_fd_nonblocking() to make it so). The file descriptor + * should be listening for connections, that is, listen() should have + * been successfully invoked on it. The server will use accept() to + * accept new client connections. + * + * @param fds list of file descriptors. + * @param n_fds number of file descriptors + * @param address the server's address + * @returns the new server, or #NULL if no memory. + * + */ +DBusServer* +_dbus_server_new_for_socket (int *fds, + int n_fds, + const DBusString *address) +{ + DBusServerSocket *socket_server; + DBusServer *server; + int i; + + socket_server = dbus_new0 (DBusServerSocket, 1); + if (socket_server == NULL) + return NULL; + + socket_server->fds = dbus_new (int, n_fds); + if (!socket_server->fds) + goto failed_0; + + socket_server->watch = dbus_new0 (DBusWatch *, n_fds); + if (!socket_server->watch) + goto failed_1; + + for (i = 0 ; i < n_fds ; i++) + { + DBusWatch *watch; + + watch = _dbus_watch_new (fds[i], + DBUS_WATCH_READABLE, + TRUE, + socket_handle_watch, socket_server, + NULL); + if (watch == NULL) + goto failed_2; + + socket_server->n_fds++; + socket_server->fds[i] = fds[i]; + socket_server->watch[i] = watch; + } + + if (!_dbus_server_init_base (&socket_server->base, + &socket_vtable, address)) + goto failed_2; + + server = (DBusServer*)socket_server; + + SERVER_LOCK (server); + + for (i = 0 ; i < n_fds ; i++) + { + if (!_dbus_server_add_watch (&socket_server->base, + socket_server->watch[i])) + { + int j; + for (j = 0 ; j < i ; j++) + _dbus_server_remove_watch (server, + socket_server->watch[j]); + + SERVER_UNLOCK (server); + _dbus_server_finalize_base (&socket_server->base); + goto failed_2; + } + } + + SERVER_UNLOCK (server); + + return (DBusServer*) socket_server; + + failed_2: + for (i = 0 ; i < n_fds ; i++) + { + if (socket_server->watch[i] != NULL) + { + _dbus_watch_unref (socket_server->watch[i]); + socket_server->watch[i] = NULL; + } + } + dbus_free (socket_server->watch); + + failed_1: + dbus_free (socket_server->fds); + + failed_0: + dbus_free (socket_server); + return NULL; +} + +/** + * Creates a new server listening on TCP. + * If host is NULL, it will default to localhost. + * If bind is NULL, it will default to the value for the host + * parameter, and if that is NULL, then localhost + * If bind is a hostname, it will be resolved and will listen + * on all returned addresses. + * If family is NULL, hostname resolution will try all address + * families, otherwise it can be ipv4 or ipv6 to restrict the + * addresses considered. + * + * @param host the hostname to report for the listen address + * @param bind the hostname to listen on + * @param port the port to listen on or 0 to let the OS choose + * @param family + * @param error location to store reason for failure. + * @returns the new server, or #NULL on failure. + */ +DBusServer* +_dbus_server_new_for_tcp_socket (const char *host, + const char *bind, + const char *port, + const char *family, + DBusError *error) +{ + DBusServer *server; + int *listen_fds = NULL; + int nlisten_fds = 0, i; + DBusString address; + DBusString host_str; + DBusString port_str; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (!_dbus_string_init (&port_str)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed_0; + } + + if (host == NULL) + host = "localhost"; + + if (port == NULL) + port = "0"; + + if (bind == NULL) + bind = host; + else if (strcmp (bind, "*") == 0) + bind = NULL; + + nlisten_fds =_dbus_listen_tcp_socket (bind, port, family, + &port_str, + &listen_fds, error); + if (nlisten_fds <= 0) + { + _DBUS_ASSERT_ERROR_IS_SET(error); + goto failed_1; + } + + for (i = 0 ; i < nlisten_fds ; i++) + _dbus_fd_set_close_on_exec (listen_fds[i]); + + _dbus_string_init_const (&host_str, host); + if (!_dbus_string_append (&address, "tcp:host=") || + !_dbus_address_append_escaped (&address, &host_str) || + !_dbus_string_append (&address, ",port=") || + !_dbus_string_append (&address, _dbus_string_get_const_data(&port_str))) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed_2; + } + if (family && + (!_dbus_string_append (&address, ",family=") || + !_dbus_string_append (&address, family))) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed_2; + } + + server = _dbus_server_new_for_socket (listen_fds, nlisten_fds, &address); + if (server == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed_2; + } + + _dbus_string_free (&port_str); + _dbus_string_free (&address); + dbus_free(listen_fds); + + return server; + + failed_2: + for (i = 0 ; i < nlisten_fds ; i++) + _dbus_close_socket (listen_fds[i], NULL); + dbus_free(listen_fds); + + failed_1: + _dbus_string_free (&port_str); + + failed_0: + _dbus_string_free (&address); + + return NULL; +} + +/** + * Tries to interpret the address entry for various socket-related + * addresses (well, currently only tcp). + * + * Sets error if the result is not OK. + * + * @param entry an address entry + * @param server_p a new DBusServer, or #NULL on failure. + * @param error location to store rationale for failure on bad address + * @returns the outcome + * + */ +DBusServerListenResult +_dbus_server_listen_socket (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error) +{ + const char *method; + + *server_p = NULL; + + method = dbus_address_entry_get_method (entry); + + if (strcmp (method, "tcp") == 0) + { + const char *host; + const char *port; + const char *bind; + const char *family; + + host = dbus_address_entry_get_value (entry, "host"); + bind = dbus_address_entry_get_value (entry, "bind"); + port = dbus_address_entry_get_value (entry, "port"); + family = dbus_address_entry_get_value (entry, "family"); + + *server_p = _dbus_server_new_for_tcp_socket (host, bind, port, + family, error); + + if (*server_p) + { + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_OK; + } + else + { + _DBUS_ASSERT_ERROR_IS_SET(error); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_NOT_HANDLED; + } +} + +/** + * This is a bad hack since it's really unix domain socket + * specific. Also, the function weirdly adopts ownership + * of the passed-in string. + * + * @param server a socket server + * @param filename socket filename to report/delete + * + */ +void +_dbus_server_socket_own_filename (DBusServer *server, + char *filename) +{ + DBusServerSocket *socket_server = (DBusServerSocket*) server; + + socket_server->socket_name = filename; +} + + +/** @} */ + diff --git a/dbus/dbus-server-socket.h b/dbus/dbus-server-socket.h new file mode 100644 index 00000000..5918658e --- /dev/null +++ b/dbus/dbus-server-socket.h @@ -0,0 +1,49 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-server-socket.h Server implementation for sockets + * + * Copyright (C) 2002, 2006 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_SERVER_SOCKET_H +#define DBUS_SERVER_SOCKET_H + +#include +#include + +DBUS_BEGIN_DECLS + +DBusServer* _dbus_server_new_for_socket (int *fds, + int n_fds, + const DBusString *address); +DBusServer* _dbus_server_new_for_tcp_socket (const char *host, + const char *bind, + const char *port, + const char *family, + DBusError *error); +DBusServerListenResult _dbus_server_listen_socket (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error); + + +void _dbus_server_socket_own_filename (DBusServer *server, + char *filename); + +DBUS_END_DECLS + +#endif /* DBUS_SERVER_SOCKET_H */ diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c new file mode 100644 index 00000000..fba9e9d2 --- /dev/null +++ b/dbus/dbus-server-unix.c @@ -0,0 +1,236 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-server-unix.c Server implementation for Unix network protocols. + * + * Copyright (C) 2002, 2003, 2004 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-server-unix.h" +#include "dbus-server-socket.h" +#include "dbus-transport-unix.h" +#include "dbus-connection-internal.h" +#include "dbus-sysdeps-unix.h" +#include "dbus-string.h" + +/** + * @defgroup DBusServerUnix DBusServer implementations for UNIX + * @ingroup DBusInternals + * @brief Implementation details of DBusServer on UNIX + * + * @{ + */ + +/** + * Tries to interpret the address entry in a platform-specific + * way, creating a platform-specific server type if appropriate. + * Sets error if the result is not OK. + * + * @param entry an address entry + * @param server_p location to store a new DBusServer, or #NULL on failure. + * @param error location to store rationale for failure on bad address + * @returns the outcome + * + */ +DBusServerListenResult +_dbus_server_listen_platform_specific (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error) +{ + const char *method; + + *server_p = NULL; + + method = dbus_address_entry_get_method (entry); + + if (strcmp (method, "unix") == 0) + { + const char *path = dbus_address_entry_get_value (entry, "path"); + const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); + const char *abstract = dbus_address_entry_get_value (entry, "abstract"); + + if (path == NULL && tmpdir == NULL && abstract == NULL) + { + _dbus_set_bad_address(error, "unix", + "path or tmpdir or abstract", + NULL); + return DBUS_SERVER_LISTEN_BAD_ADDRESS; + } + + if ((path && tmpdir) || + (path && abstract) || + (tmpdir && abstract)) + { + _dbus_set_bad_address(error, NULL, NULL, + "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time"); + return DBUS_SERVER_LISTEN_BAD_ADDRESS; + } + + if (tmpdir != NULL) + { + DBusString full_path; + DBusString filename; + + if (!_dbus_string_init (&full_path)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + + if (!_dbus_string_init (&filename)) + { + _dbus_string_free (&full_path); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + + if (!_dbus_string_append (&filename, + "dbus-") || + !_dbus_generate_random_ascii (&filename, 10) || + !_dbus_string_append (&full_path, tmpdir) || + !_dbus_concat_dir_and_file (&full_path, &filename)) + { + _dbus_string_free (&full_path); + _dbus_string_free (&filename); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + + /* Always use abstract namespace if possible with tmpdir */ + + *server_p = + _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), +#ifdef HAVE_ABSTRACT_SOCKETS + TRUE, +#else + FALSE, +#endif + error); + + _dbus_string_free (&full_path); + _dbus_string_free (&filename); + } + else + { + if (path) + *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error); + else + *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error); + } + + if (*server_p != NULL) + { + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_OK; + } + else + { + _DBUS_ASSERT_ERROR_IS_SET(error); + return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; + } + } + else + { + /* If we don't handle the method, we return NULL with the + * error unset + */ + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + return DBUS_SERVER_LISTEN_NOT_HANDLED; + } +} + +/** + * Creates a new server listening on the given Unix domain socket. + * + * @param path the path for the domain socket. + * @param abstract #TRUE to use abstract socket namespace + * @param error location to store reason for failure. + * @returns the new server, or #NULL on failure. + */ +DBusServer* +_dbus_server_new_for_domain_socket (const char *path, + dbus_bool_t abstract, + DBusError *error) +{ + DBusServer *server; + int listen_fd; + DBusString address; + char *path_copy; + DBusString path_str; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + _dbus_string_init_const (&path_str, path); + if ((abstract && + !_dbus_string_append (&address, "unix:abstract=")) || + (!abstract && + !_dbus_string_append (&address, "unix:path=")) || + !_dbus_address_append_escaped (&address, &path_str)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed_0; + } + + path_copy = _dbus_strdup (path); + if (path_copy == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed_0; + } + + listen_fd = _dbus_listen_unix_socket (path, abstract, error); + _dbus_fd_set_close_on_exec (listen_fd); + + if (listen_fd < 0) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed_1; + } + + server = _dbus_server_new_for_socket (&listen_fd, 1, &address); + if (server == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed_2; + } + + _dbus_server_socket_own_filename(server, path_copy); + + _dbus_string_free (&address); + + return server; + + failed_2: + _dbus_close_socket (listen_fd, NULL); + failed_1: + dbus_free (path_copy); + failed_0: + _dbus_string_free (&address); + + return NULL; +} + +/** @} */ + diff --git a/dbus/dbus-server-unix.h b/dbus/dbus-server-unix.h new file mode 100644 index 00000000..92b996ca --- /dev/null +++ b/dbus/dbus-server-unix.h @@ -0,0 +1,37 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-server-unix.h Server implementation for Unix network protocols. + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_SERVER_UNIX_H +#define DBUS_SERVER_UNIX_H + +#include +#include + +DBUS_BEGIN_DECLS + +DBusServer* _dbus_server_new_for_domain_socket (const char *path, + dbus_bool_t abstract, + DBusError *error); + +DBUS_END_DECLS + +#endif /* DBUS_SERVER_UNIX_H */ diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c new file mode 100644 index 00000000..974503bb --- /dev/null +++ b/dbus/dbus-server.c @@ -0,0 +1,1202 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-server.c DBusServer object + * + * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-server.h" +#include "dbus-server-unix.h" +#include "dbus-server-socket.h" +#include "dbus-string.h" +#ifdef DBUS_BUILD_TESTS +#include "dbus-server-debug-pipe.h" +#endif +#include "dbus-address.h" +#include "dbus-protocol.h" + +/** + * @defgroup DBusServer DBusServer + * @ingroup DBus + * @brief Server that listens for new connections. + * + * A DBusServer represents a server that other applications + * can connect to. Each connection from another application + * is represented by a #DBusConnection. + * + * @todo Thread safety hasn't been tested much for #DBusServer + * @todo Need notification to apps of disconnection, may matter for some transports + */ + +/** + * @defgroup DBusServerInternals DBusServer implementation details + * @ingroup DBusInternals + * @brief Implementation details of DBusServer + * + * @{ + */ + +/* this is a little fragile since it assumes the address doesn't + * already have a guid, but it shouldn't + */ +static char* +copy_address_with_guid_appended (const DBusString *address, + const DBusString *guid_hex) +{ + DBusString with_guid; + char *retval; + + if (!_dbus_string_init (&with_guid)) + return NULL; + + if (!_dbus_string_copy (address, 0, &with_guid, + _dbus_string_get_length (&with_guid)) || + !_dbus_string_append (&with_guid, ",guid=") || + !_dbus_string_copy (guid_hex, 0, + &with_guid, _dbus_string_get_length (&with_guid))) + { + _dbus_string_free (&with_guid); + return NULL; + } + + retval = NULL; + _dbus_string_steal_data (&with_guid, &retval); + + _dbus_string_free (&with_guid); + + return retval; /* may be NULL if steal_data failed */ +} + +/** + * Initializes the members of the DBusServer base class. + * Chained up to by subclass constructors. + * + * @param server the server. + * @param vtable the vtable for the subclass. + * @param address the server's address + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_server_init_base (DBusServer *server, + const DBusServerVTable *vtable, + const DBusString *address) +{ + server->vtable = vtable; + server->refcount.value = 1; + + server->address = NULL; + server->watches = NULL; + server->timeouts = NULL; + + if (!_dbus_string_init (&server->guid_hex)) + return FALSE; + + _dbus_generate_uuid (&server->guid); + + if (!_dbus_uuid_encode (&server->guid, &server->guid_hex)) + goto failed; + + server->address = copy_address_with_guid_appended (address, + &server->guid_hex); + if (server->address == NULL) + goto failed; + + _dbus_mutex_new_at_location (&server->mutex); + if (server->mutex == NULL) + goto failed; + + server->watches = _dbus_watch_list_new (); + if (server->watches == NULL) + goto failed; + + server->timeouts = _dbus_timeout_list_new (); + if (server->timeouts == NULL) + goto failed; + + _dbus_data_slot_list_init (&server->slot_list); + + _dbus_verbose ("Initialized server on address %s\n", server->address); + + return TRUE; + + failed: + _dbus_mutex_free_at_location (&server->mutex); + server->mutex = NULL; + if (server->watches) + { + _dbus_watch_list_free (server->watches); + server->watches = NULL; + } + if (server->timeouts) + { + _dbus_timeout_list_free (server->timeouts); + server->timeouts = NULL; + } + if (server->address) + { + dbus_free (server->address); + server->address = NULL; + } + _dbus_string_free (&server->guid_hex); + + return FALSE; +} + +/** + * Finalizes the members of the DBusServer base class. + * Chained up to by subclass finalizers. + * + * @param server the server. + */ +void +_dbus_server_finalize_base (DBusServer *server) +{ + /* We don't have the lock, but nobody should be accessing + * concurrently since they don't have a ref + */ +#ifndef DBUS_DISABLE_CHECKS + _dbus_assert (!server->have_server_lock); +#endif + _dbus_assert (server->disconnected); + + /* calls out to application code... */ + _dbus_data_slot_list_free (&server->slot_list); + + dbus_server_set_new_connection_function (server, NULL, NULL, NULL); + + _dbus_watch_list_free (server->watches); + _dbus_timeout_list_free (server->timeouts); + + _dbus_mutex_free_at_location (&server->mutex); + + dbus_free (server->address); + + dbus_free_string_array (server->auth_mechanisms); + + _dbus_string_free (&server->guid_hex); +} + + +/** Function to be called in protected_change_watch() with refcount held */ +typedef dbus_bool_t (* DBusWatchAddFunction) (DBusWatchList *list, + DBusWatch *watch); +/** Function to be called in protected_change_watch() with refcount held */ +typedef void (* DBusWatchRemoveFunction) (DBusWatchList *list, + DBusWatch *watch); +/** Function to be called in protected_change_watch() with refcount held */ +typedef void (* DBusWatchToggleFunction) (DBusWatchList *list, + DBusWatch *watch, + dbus_bool_t enabled); + +static dbus_bool_t +protected_change_watch (DBusServer *server, + DBusWatch *watch, + DBusWatchAddFunction add_function, + DBusWatchRemoveFunction remove_function, + DBusWatchToggleFunction toggle_function, + dbus_bool_t enabled) +{ + DBusWatchList *watches; + dbus_bool_t retval; + + HAVE_LOCK_CHECK (server); + + /* This isn't really safe or reasonable; a better pattern is the "do + * everything, then drop lock and call out" one; but it has to be + * propagated up through all callers + */ + + watches = server->watches; + if (watches) + { + server->watches = NULL; + _dbus_server_ref_unlocked (server); + SERVER_UNLOCK (server); + + if (add_function) + retval = (* add_function) (watches, watch); + else if (remove_function) + { + retval = TRUE; + (* remove_function) (watches, watch); + } + else + { + retval = TRUE; + (* toggle_function) (watches, watch, enabled); + } + + SERVER_LOCK (server); + server->watches = watches; + _dbus_server_unref_unlocked (server); + + return retval; + } + else + return FALSE; +} + +/** + * Adds a watch for this server, chaining out to application-provided + * watch handlers. + * + * @param server the server. + * @param watch the watch to add. + */ +dbus_bool_t +_dbus_server_add_watch (DBusServer *server, + DBusWatch *watch) +{ + HAVE_LOCK_CHECK (server); + return protected_change_watch (server, watch, + _dbus_watch_list_add_watch, + NULL, NULL, FALSE); +} + +/** + * Removes a watch previously added with _dbus_server_remove_watch(). + * + * @param server the server. + * @param watch the watch to remove. + */ +void +_dbus_server_remove_watch (DBusServer *server, + DBusWatch *watch) +{ + HAVE_LOCK_CHECK (server); + protected_change_watch (server, watch, + NULL, + _dbus_watch_list_remove_watch, + NULL, FALSE); +} + +/** + * Toggles a watch and notifies app via server's + * DBusWatchToggledFunction if available. It's an error to call this + * function on a watch that was not previously added. + * + * @param server the server. + * @param watch the watch to toggle. + * @param enabled whether to enable or disable + */ +void +_dbus_server_toggle_watch (DBusServer *server, + DBusWatch *watch, + dbus_bool_t enabled) +{ + _dbus_assert (watch != NULL); + + HAVE_LOCK_CHECK (server); + protected_change_watch (server, watch, + NULL, NULL, + _dbus_watch_list_toggle_watch, + enabled); +} + +/** Function to be called in protected_change_timeout() with refcount held */ +typedef dbus_bool_t (* DBusTimeoutAddFunction) (DBusTimeoutList *list, + DBusTimeout *timeout); +/** Function to be called in protected_change_timeout() with refcount held */ +typedef void (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list, + DBusTimeout *timeout); +/** Function to be called in protected_change_timeout() with refcount held */ +typedef void (* DBusTimeoutToggleFunction) (DBusTimeoutList *list, + DBusTimeout *timeout, + dbus_bool_t enabled); + + +static dbus_bool_t +protected_change_timeout (DBusServer *server, + DBusTimeout *timeout, + DBusTimeoutAddFunction add_function, + DBusTimeoutRemoveFunction remove_function, + DBusTimeoutToggleFunction toggle_function, + dbus_bool_t enabled) +{ + DBusTimeoutList *timeouts; + dbus_bool_t retval; + + HAVE_LOCK_CHECK (server); + + /* This isn't really safe or reasonable; a better pattern is the "do everything, then + * drop lock and call out" one; but it has to be propagated up through all callers + */ + + timeouts = server->timeouts; + if (timeouts) + { + server->timeouts = NULL; + _dbus_server_ref_unlocked (server); + SERVER_UNLOCK (server); + + if (add_function) + retval = (* add_function) (timeouts, timeout); + else if (remove_function) + { + retval = TRUE; + (* remove_function) (timeouts, timeout); + } + else + { + retval = TRUE; + (* toggle_function) (timeouts, timeout, enabled); + } + + SERVER_LOCK (server); + server->timeouts = timeouts; + _dbus_server_unref_unlocked (server); + + return retval; + } + else + return FALSE; +} + +/** + * Adds a timeout for this server, chaining out to + * application-provided timeout handlers. The timeout should be + * repeatedly handled with dbus_timeout_handle() at its given interval + * until it is removed. + * + * @param server the server. + * @param timeout the timeout to add. + */ +dbus_bool_t +_dbus_server_add_timeout (DBusServer *server, + DBusTimeout *timeout) +{ + return protected_change_timeout (server, timeout, + _dbus_timeout_list_add_timeout, + NULL, NULL, FALSE); +} + +/** + * Removes a timeout previously added with _dbus_server_add_timeout(). + * + * @param server the server. + * @param timeout the timeout to remove. + */ +void +_dbus_server_remove_timeout (DBusServer *server, + DBusTimeout *timeout) +{ + protected_change_timeout (server, timeout, + NULL, + _dbus_timeout_list_remove_timeout, + NULL, FALSE); +} + +/** + * Toggles a timeout and notifies app via server's + * DBusTimeoutToggledFunction if available. It's an error to call this + * function on a timeout that was not previously added. + * + * @param server the server. + * @param timeout the timeout to toggle. + * @param enabled whether to enable or disable + */ +void +_dbus_server_toggle_timeout (DBusServer *server, + DBusTimeout *timeout, + dbus_bool_t enabled) +{ + protected_change_timeout (server, timeout, + NULL, NULL, + _dbus_timeout_list_toggle_timeout, + enabled); +} + + +/** + * Like dbus_server_ref() but does not acquire the lock (must already be held) + * + * @param server the server. + */ +void +_dbus_server_ref_unlocked (DBusServer *server) +{ + _dbus_assert (server != NULL); + _dbus_assert (server->refcount.value > 0); + + HAVE_LOCK_CHECK (server); + +#ifdef DBUS_HAVE_ATOMIC_INT + _dbus_atomic_inc (&server->refcount); +#else + _dbus_assert (server->refcount.value > 0); + + server->refcount.value += 1; +#endif +} + +/** + * Like dbus_server_unref() but does not acquire the lock (must already be held) + * + * @param server the server. + */ +void +_dbus_server_unref_unlocked (DBusServer *server) +{ + dbus_bool_t last_unref; + + /* Keep this in sync with dbus_server_unref */ + + _dbus_assert (server != NULL); + _dbus_assert (server->refcount.value > 0); + + HAVE_LOCK_CHECK (server); + +#ifdef DBUS_HAVE_ATOMIC_INT + last_unref = (_dbus_atomic_dec (&server->refcount) == 1); +#else + _dbus_assert (server->refcount.value > 0); + + server->refcount.value -= 1; + last_unref = (server->refcount.value == 0); +#endif + + if (last_unref) + { + _dbus_assert (server->disconnected); + + SERVER_UNLOCK (server); + + _dbus_assert (server->vtable->finalize != NULL); + + (* server->vtable->finalize) (server); + } +} + +/** @} */ + +/** + * @addtogroup DBusServer + * + * @{ + */ + + +/** + * @typedef DBusServer + * + * An opaque object representing a server that listens for + * connections from other applications. Each time a connection + * is made, a new DBusConnection is created and made available + * via an application-provided DBusNewConnectionFunction. + * The DBusNewConnectionFunction is provided with + * dbus_server_set_new_connection_function(). + * + */ + +static const struct { + DBusServerListenResult (* func) (DBusAddressEntry *entry, + DBusServer **server_p, + DBusError *error); +} listen_funcs[] = { + { _dbus_server_listen_socket } + , { _dbus_server_listen_platform_specific } +#ifdef DBUS_BUILD_TESTS + , { _dbus_server_listen_debug_pipe } +#endif +}; + +/** + * Listens for new connections on the given address. If there are + * multiple semicolon-separated address entries in the address, tries + * each one and listens on the first one that works. + * + * Returns #NULL and sets error if listening fails for any reason. + * Otherwise returns a new #DBusServer. + * dbus_server_set_new_connection_function(), + * dbus_server_set_watch_functions(), and + * dbus_server_set_timeout_functions() should be called immediately to + * render the server fully functional. + * + * To free the server, applications must call first + * dbus_server_disconnect() and then dbus_server_unref(). + * + * @param address the address of this server. + * @param error location to store reason for failure. + * @returns a new #DBusServer, or #NULL on failure. + * + */ +DBusServer* +dbus_server_listen (const char *address, + DBusError *error) +{ + DBusServer *server; + DBusAddressEntry **entries; + int len, i; + DBusError first_connect_error = DBUS_ERROR_INIT; + dbus_bool_t handled_once; + + _dbus_return_val_if_fail (address != NULL, NULL); + _dbus_return_val_if_error_is_set (error, NULL); + + if (!dbus_parse_address (address, &entries, &len, error)) + return NULL; + + server = NULL; + handled_once = FALSE; + + for (i = 0; i < len; i++) + { + int j; + + for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j) + { + DBusServerListenResult result; + DBusError tmp_error = DBUS_ERROR_INIT; + + result = (* listen_funcs[j].func) (entries[i], + &server, + &tmp_error); + + if (result == DBUS_SERVER_LISTEN_OK) + { + _dbus_assert (server != NULL); + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); + handled_once = TRUE; + goto out; + } + else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS) + { + _dbus_assert (server == NULL); + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + dbus_move_error (&tmp_error, error); + handled_once = TRUE; + goto out; + } + else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED) + { + _dbus_assert (server == NULL); + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); + + /* keep trying addresses */ + } + else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT) + { + _dbus_assert (server == NULL); + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + if (!dbus_error_is_set (&first_connect_error)) + dbus_move_error (&tmp_error, &first_connect_error); + else + dbus_error_free (&tmp_error); + + handled_once = TRUE; + + /* keep trying addresses */ + } + } + + _dbus_assert (server == NULL); + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + } + + out: + + if (!handled_once) + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + if (len > 0) + dbus_set_error (error, + DBUS_ERROR_BAD_ADDRESS, + "Unknown address type '%s'", + dbus_address_entry_get_method (entries[0])); + else + dbus_set_error (error, + DBUS_ERROR_BAD_ADDRESS, + "Empty address '%s'", + address); + } + + dbus_address_entries_free (entries); + + if (server == NULL) + { + _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) || + dbus_error_is_set (error)); + + if (error && dbus_error_is_set (error)) + { + /* already set the error */ + } + else + { + /* didn't set the error but either error should be + * NULL or first_connect_error should be set. + */ + _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error)); + dbus_move_error (&first_connect_error, error); + } + + _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */ + _DBUS_ASSERT_ERROR_IS_SET (error); + + return NULL; + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return server; + } +} + +/** + * Increments the reference count of a DBusServer. + * + * @param server the server. + * @returns the server + */ +DBusServer * +dbus_server_ref (DBusServer *server) +{ + _dbus_return_val_if_fail (server != NULL, NULL); + _dbus_return_val_if_fail (server->refcount.value > 0, NULL); + +#ifdef DBUS_HAVE_ATOMIC_INT + _dbus_atomic_inc (&server->refcount); +#else + SERVER_LOCK (server); + _dbus_assert (server->refcount.value > 0); + + server->refcount.value += 1; + SERVER_UNLOCK (server); +#endif + + return server; +} + +/** + * Decrements the reference count of a DBusServer. Finalizes the + * server if the reference count reaches zero. + * + * The server must be disconnected before the refcount reaches zero. + * + * @param server the server. + */ +void +dbus_server_unref (DBusServer *server) +{ + dbus_bool_t last_unref; + + /* keep this in sync with unref_unlocked */ + + _dbus_return_if_fail (server != NULL); + _dbus_return_if_fail (server->refcount.value > 0); + +#ifdef DBUS_HAVE_ATOMIC_INT + last_unref = (_dbus_atomic_dec (&server->refcount) == 1); +#else + SERVER_LOCK (server); + + _dbus_assert (server->refcount.value > 0); + + server->refcount.value -= 1; + last_unref = (server->refcount.value == 0); + + SERVER_UNLOCK (server); +#endif + + if (last_unref) + { + /* lock not held! */ + _dbus_assert (server->disconnected); + + _dbus_assert (server->vtable->finalize != NULL); + + (* server->vtable->finalize) (server); + } +} + +/** + * Releases the server's address and stops listening for + * new clients. If called more than once, only the first + * call has an effect. Does not modify the server's + * reference count. + * + * @param server the server. + */ +void +dbus_server_disconnect (DBusServer *server) +{ + _dbus_return_if_fail (server != NULL); + _dbus_return_if_fail (server->refcount.value > 0); + + SERVER_LOCK (server); + _dbus_server_ref_unlocked (server); + + _dbus_assert (server->vtable->disconnect != NULL); + + if (!server->disconnected) + { + /* this has to be first so recursive calls to disconnect don't happen */ + server->disconnected = TRUE; + + (* server->vtable->disconnect) (server); + } + + SERVER_UNLOCK (server); + dbus_server_unref (server); +} + +/** + * Returns #TRUE if the server is still listening for new connections. + * + * @param server the server. + */ +dbus_bool_t +dbus_server_get_is_connected (DBusServer *server) +{ + dbus_bool_t retval; + + _dbus_return_val_if_fail (server != NULL, FALSE); + + SERVER_LOCK (server); + retval = !server->disconnected; + SERVER_UNLOCK (server); + + return retval; +} + +/** + * Returns the address of the server, as a newly-allocated + * string which must be freed by the caller. + * + * @param server the server + * @returns the address or #NULL if no memory + */ +char* +dbus_server_get_address (DBusServer *server) +{ + char *retval; + + _dbus_return_val_if_fail (server != NULL, NULL); + + SERVER_LOCK (server); + retval = _dbus_strdup (server->address); + SERVER_UNLOCK (server); + + return retval; +} + +/** + * Returns the unique ID of the server, as a newly-allocated + * string which must be freed by the caller. This ID is + * normally used by clients to tell when two #DBusConnection + * would be equivalent (because the server address passed + * to dbus_connection_open() will have the same guid in the + * two cases). dbus_connection_open() can re-use an existing + * connection with the same ID instead of opening a new + * connection. + * + * This is an ID unique to each #DBusServer. Remember that + * a #DBusServer represents only one mode of connecting, + * so e.g. a bus daemon can listen on multiple addresses + * which will mean it has multiple #DBusServer each with + * their own ID. + * + * The ID is not a UUID in the sense of RFC4122; the details + * are explained in the D-Bus specification. + * + * @param server the server + * @returns the id of the server or #NULL if no memory + */ +char* +dbus_server_get_id (DBusServer *server) +{ + char *retval; + + _dbus_return_val_if_fail (server != NULL, NULL); + + SERVER_LOCK (server); + retval = NULL; + _dbus_string_copy_data (&server->guid_hex, &retval); + SERVER_UNLOCK (server); + + return retval; +} + +/** + * Sets a function to be used for handling new connections. The given + * function is passed each new connection as the connection is + * created. If the new connection function increments the connection's + * reference count, the connection will stay alive. Otherwise, the + * connection will be unreferenced and closed. The new connection + * function may also close the connection itself, which is considered + * good form if the connection is not wanted. + * + * The connection here is private in the sense of + * dbus_connection_open_private(), so if the new connection function + * keeps a reference it must arrange for the connection to be closed. + * i.e. libdbus does not own this connection once the new connection + * function takes a reference. + * + * @param server the server. + * @param function a function to handle new connections. + * @param data data to pass to the new connection handler. + * @param free_data_function function to free the data. + */ +void +dbus_server_set_new_connection_function (DBusServer *server, + DBusNewConnectionFunction function, + void *data, + DBusFreeFunction free_data_function) +{ + DBusFreeFunction old_free_function; + void *old_data; + + _dbus_return_if_fail (server != NULL); + + SERVER_LOCK (server); + old_free_function = server->new_connection_free_data_function; + old_data = server->new_connection_data; + + server->new_connection_function = function; + server->new_connection_data = data; + server->new_connection_free_data_function = free_data_function; + SERVER_UNLOCK (server); + + if (old_free_function != NULL) + (* old_free_function) (old_data); +} + +/** + * Sets the watch functions for the server. These functions are + * responsible for making the application's main loop aware of file + * descriptors that need to be monitored for events. + * + * This function behaves exactly like dbus_connection_set_watch_functions(); + * see the documentation for that routine. + * + * @param server the server. + * @param add_function function to begin monitoring a new descriptor. + * @param remove_function function to stop monitoring a descriptor. + * @param toggled_function function to notify when the watch is enabled/disabled + * @param data data to pass to add_function and remove_function. + * @param free_data_function function to be called to free the data. + * @returns #FALSE on failure (no memory) + */ +dbus_bool_t +dbus_server_set_watch_functions (DBusServer *server, + DBusAddWatchFunction add_function, + DBusRemoveWatchFunction remove_function, + DBusWatchToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function) +{ + dbus_bool_t result; + DBusWatchList *watches; + + _dbus_return_val_if_fail (server != NULL, FALSE); + + SERVER_LOCK (server); + watches = server->watches; + server->watches = NULL; + if (watches) + { + SERVER_UNLOCK (server); + result = _dbus_watch_list_set_functions (watches, + add_function, + remove_function, + toggled_function, + data, + free_data_function); + SERVER_LOCK (server); + } + else + { + _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME); + result = FALSE; + } + server->watches = watches; + SERVER_UNLOCK (server); + + return result; +} + +/** + * Sets the timeout functions for the server. These functions are + * responsible for making the application's main loop aware of timeouts. + * + * This function behaves exactly like dbus_connection_set_timeout_functions(); + * see the documentation for that routine. + * + * @param server the server. + * @param add_function function to add a timeout. + * @param remove_function function to remove a timeout. + * @param toggled_function function to notify when the timeout is enabled/disabled + * @param data data to pass to add_function and remove_function. + * @param free_data_function function to be called to free the data. + * @returns #FALSE on failure (no memory) + */ +dbus_bool_t +dbus_server_set_timeout_functions (DBusServer *server, + DBusAddTimeoutFunction add_function, + DBusRemoveTimeoutFunction remove_function, + DBusTimeoutToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function) +{ + dbus_bool_t result; + DBusTimeoutList *timeouts; + + _dbus_return_val_if_fail (server != NULL, FALSE); + + SERVER_LOCK (server); + timeouts = server->timeouts; + server->timeouts = NULL; + if (timeouts) + { + SERVER_UNLOCK (server); + result = _dbus_timeout_list_set_functions (timeouts, + add_function, + remove_function, + toggled_function, + data, + free_data_function); + SERVER_LOCK (server); + } + else + { + _dbus_warn_check_failed ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME); + result = FALSE; + } + server->timeouts = timeouts; + SERVER_UNLOCK (server); + + return result; +} + +/** + * Sets the authentication mechanisms that this server offers to + * clients, as a #NULL-terminated array of mechanism names. This + * function only affects connections created after it is + * called. Pass #NULL instead of an array to use all available + * mechanisms (this is the default behavior). + * + * The D-Bus specification describes some of the supported mechanisms. + * + * @param server the server + * @param mechanisms #NULL-terminated array of mechanisms + * @returns #FALSE if no memory + */ +dbus_bool_t +dbus_server_set_auth_mechanisms (DBusServer *server, + const char **mechanisms) +{ + char **copy; + + _dbus_return_val_if_fail (server != NULL, FALSE); + + SERVER_LOCK (server); + + if (mechanisms != NULL) + { + copy = _dbus_dup_string_array (mechanisms); + if (copy == NULL) + return FALSE; + } + else + copy = NULL; + + dbus_free_string_array (server->auth_mechanisms); + server->auth_mechanisms = copy; + + SERVER_UNLOCK (server); + + return TRUE; +} + + +static DBusDataSlotAllocator slot_allocator; +_DBUS_DEFINE_GLOBAL_LOCK (server_slots); + +/** + * Allocates an integer ID to be used for storing application-specific + * data on any DBusServer. The allocated ID may then be used + * with dbus_server_set_data() and dbus_server_get_data(). + * The slot must be initialized with -1. If a nonnegative + * slot is passed in, the refcount is incremented on that + * slot, rather than creating a new slot. + * + * The allocated slot is global, i.e. all DBusServer objects will have + * a slot with the given integer ID reserved. + * + * @param slot_p address of global variable storing the slot ID + * @returns #FALSE on no memory + */ +dbus_bool_t +dbus_server_allocate_data_slot (dbus_int32_t *slot_p) +{ + return _dbus_data_slot_allocator_alloc (&slot_allocator, + (DBusMutex **)&_DBUS_LOCK_NAME (server_slots), + slot_p); +} + +/** + * Deallocates a global ID for server data slots. + * dbus_server_get_data() and dbus_server_set_data() + * may no longer be used with this slot. + * Existing data stored on existing DBusServer objects + * will be freed when the server is finalized, + * but may not be retrieved (and may only be replaced + * if someone else reallocates the slot). + * + * @param slot_p address of the slot to deallocate + */ +void +dbus_server_free_data_slot (dbus_int32_t *slot_p) +{ + _dbus_return_if_fail (*slot_p >= 0); + + _dbus_data_slot_allocator_free (&slot_allocator, slot_p); +} + +/** + * Stores a pointer on a DBusServer, along + * with an optional function to be used for freeing + * the data when the data is set again, or when + * the server is finalized. The slot number + * must have been allocated with dbus_server_allocate_data_slot(). + * + * @param server the server + * @param slot the slot number + * @param data the data to store + * @param free_data_func finalizer function for the data + * @returns #TRUE if there was enough memory to store the data + */ +dbus_bool_t +dbus_server_set_data (DBusServer *server, + int slot, + void *data, + DBusFreeFunction free_data_func) +{ + DBusFreeFunction old_free_func; + void *old_data; + dbus_bool_t retval; + + _dbus_return_val_if_fail (server != NULL, FALSE); + + SERVER_LOCK (server); + + retval = _dbus_data_slot_list_set (&slot_allocator, + &server->slot_list, + slot, data, free_data_func, + &old_free_func, &old_data); + + + SERVER_UNLOCK (server); + + if (retval) + { + /* Do the actual free outside the server lock */ + if (old_free_func) + (* old_free_func) (old_data); + } + + return retval; +} + +/** + * Retrieves data previously set with dbus_server_set_data(). + * The slot must still be allocated (must not have been freed). + * + * @param server the server + * @param slot the slot to get data from + * @returns the data, or #NULL if not found + */ +void* +dbus_server_get_data (DBusServer *server, + int slot) +{ + void *res; + + _dbus_return_val_if_fail (server != NULL, NULL); + + SERVER_LOCK (server); + + res = _dbus_data_slot_list_get (&slot_allocator, + &server->slot_list, + slot); + + SERVER_UNLOCK (server); + + return res; +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +dbus_bool_t +_dbus_server_test (void) +{ + const char *valid_addresses[] = { + "tcp:port=1234", + "tcp:host=localhost,port=1234", + "tcp:host=localhost,port=1234;tcp:port=5678", +#ifdef DBUS_UNIX + "unix:path=./boogie", + "tcp:port=1234;unix:path=./boogie", +#endif + }; + + DBusServer *server; + int i; + + for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++) + { + DBusError error = DBUS_ERROR_INIT; + char *address; + char *id; + + server = dbus_server_listen (valid_addresses[i], &error); + if (server == NULL) + { + _dbus_warn ("server listen error: %s: %s\n", error.name, error.message); + dbus_error_free (&error); + _dbus_assert_not_reached ("Failed to listen for valid address."); + } + + id = dbus_server_get_id (server); + _dbus_assert (id != NULL); + address = dbus_server_get_address (server); + _dbus_assert (address != NULL); + + if (strstr (address, id) == NULL) + { + _dbus_warn ("server id '%s' is not in the server address '%s'\n", + id, address); + _dbus_assert_not_reached ("bad server id or address"); + } + + dbus_free (id); + dbus_free (address); + + dbus_server_disconnect (server); + dbus_server_unref (server); + } + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-server.h b/dbus/dbus-server.h new file mode 100644 index 00000000..6d7d2fa2 --- /dev/null +++ b/dbus/dbus-server.h @@ -0,0 +1,91 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-server.h DBusServer object + * + * Copyright (C) 2002, 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_SERVER_H +#define DBUS_SERVER_H + +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusServer + * @{ + */ + +typedef struct DBusServer DBusServer; + +/** Called when a new connection to the server is available. Must reference and save the new + * connection, or close the new connection. Set with dbus_server_set_new_connection_function(). + */ +typedef void (* DBusNewConnectionFunction) (DBusServer *server, + DBusConnection *new_connection, + void *data); + +DBusServer* dbus_server_listen (const char *address, + DBusError *error); +DBusServer* dbus_server_ref (DBusServer *server); +void dbus_server_unref (DBusServer *server); +void dbus_server_disconnect (DBusServer *server); +dbus_bool_t dbus_server_get_is_connected (DBusServer *server); +char* dbus_server_get_address (DBusServer *server); +char* dbus_server_get_id (DBusServer *server); +void dbus_server_set_new_connection_function (DBusServer *server, + DBusNewConnectionFunction function, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t dbus_server_set_watch_functions (DBusServer *server, + DBusAddWatchFunction add_function, + DBusRemoveWatchFunction remove_function, + DBusWatchToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t dbus_server_set_timeout_functions (DBusServer *server, + DBusAddTimeoutFunction add_function, + DBusRemoveTimeoutFunction remove_function, + DBusTimeoutToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t dbus_server_set_auth_mechanisms (DBusServer *server, + const char **mechanisms); + +dbus_bool_t dbus_server_allocate_data_slot (dbus_int32_t *slot_p); +void dbus_server_free_data_slot (dbus_int32_t *slot_p); +dbus_bool_t dbus_server_set_data (DBusServer *server, + int slot, + void *data, + DBusFreeFunction free_data_func); +void* dbus_server_get_data (DBusServer *server, + int slot); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_SERVER_H */ diff --git a/dbus/dbus-sha.c b/dbus/dbus-sha.c new file mode 100644 index 00000000..df34cc8c --- /dev/null +++ b/dbus/dbus-sha.c @@ -0,0 +1,968 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-sha.c SHA-1 implementation + * + * Copyright (C) 2003 Red Hat Inc. + * Copyright (C) 1995 A. M. Kuchling + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-sha.h" +#include "dbus-marshal-basic.h" /* for byteswap routines */ +#include + +/* The following comments have the history of where this code + * comes from. I actually copied it from GNet in GNOME CVS. + * - hp@redhat.com + */ + +/* + * sha.h : Implementation of the Secure Hash Algorithm + * + * Part of the Python Cryptography Toolkit, version 1.0.0 + * + * Copyright (C) 1995, A.M. Kuchling + * + * Distribute and use freely; there are no restrictions on further + * dissemination and usage except those imposed by the laws of your + * country of residence. + * + */ + +/* SHA: NIST's Secure Hash Algorithm */ + +/* Based on SHA code originally posted to sci.crypt by Peter Gutmann + in message <30ajo5$oe8@ccu2.auckland.ac.nz>. + Modified to test for endianness on creation of SHA objects by AMK. + Also, the original specification of SHA was found to have a weakness + by NSA/NIST. This code implements the fixed version of SHA. +*/ + +/* Here's the first paragraph of Peter Gutmann's posting: + +The following is my SHA (FIPS 180) code updated to allow use of the "fixed" +SHA, thanks to Jim Gillogly and an anonymous contributor for the information on +what's changed in the new version. The fix is a simple change which involves +adding a single rotate in the initial expansion function. It is unknown +whether this is an optimal solution to the problem which was discovered in the +SHA or whether it's simply a bandaid which fixes the problem with a minimum of +effort (for example the reengineering of a great many Capstone chips). +*/ + +/** + * @defgroup DBusSHA SHA implementation + * @ingroup DBusInternals + * @brief SHA-1 hash + * + * Types and functions related to computing SHA-1 hash. + */ + +/** + * @defgroup DBusSHAInternals SHA implementation details + * @ingroup DBusInternals + * @brief Internals of SHA implementation. + * + * The implementation of SHA-1 (see http://www.itl.nist.gov/fipspubs/fip180-1.htm). + * This SHA implementation was written by A.M. Kuchling + * + * @{ + */ + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +/* The SHA block size and message digest sizes, in bytes */ + +#define SHA_DATASIZE 64 +#define SHA_DIGESTSIZE 20 + +/* The SHA f()-functions. The f1 and f3 functions can be optimized to + save one boolean operation each - thanks to Rich Schroeppel, + rcs@cs.arizona.edu for discovering this */ + +/*#define f1(x,y,z) ( ( x & y ) | ( ~x & z ) ) // Rounds 0-19 */ +#define f1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) /* Rounds 0-19 */ +#define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */ +/*#define f3(x,y,z) ( ( x & y ) | ( x & z ) | ( y & z ) ) // Rounds 40-59 */ +#define f3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) /* Rounds 40-59 */ +#define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */ + +/* The SHA Mysterious Constants */ + +#define K1 0x5A827999L /* Rounds 0-19 */ +#define K2 0x6ED9EBA1L /* Rounds 20-39 */ +#define K3 0x8F1BBCDCL /* Rounds 40-59 */ +#define K4 0xCA62C1D6L /* Rounds 60-79 */ + +/* SHA initial values */ + +#define h0init 0x67452301L +#define h1init 0xEFCDAB89L +#define h2init 0x98BADCFEL +#define h3init 0x10325476L +#define h4init 0xC3D2E1F0L + +/* Note that it may be necessary to add parentheses to these macros if they + are to be called with expressions as arguments */ +/* 32-bit rotate left - kludged with shifts */ + +#define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) ) + +/* The initial expanding function. The hash function is defined over an + 80-word expanded input array W, where the first 16 are copies of the input + data, and the remaining 64 are defined by + + W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ] + + This implementation generates these values on the fly in a circular + buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this + optimization. + + The updated SHA changes the expanding function by adding a rotate of 1 + bit. Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor + for this information */ + +#define expand(W,i) ( W[ i & 15 ] = ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \ + W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) ) ) + + +/* The prototype SHA sub-round. The fundamental sub-round is: + + a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data; + b' = a; + c' = ROTL( 30, b ); + d' = c; + e' = d; + + but this is implemented by unrolling the loop 5 times and renaming the + variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration. + This code is then replicated 20 times for each of the 4 functions, using + the next 20 values from the W[] array each time */ + +#define subRound(a, b, c, d, e, f, k, data) \ + ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) ) + +#endif /* !DOXYGEN_SHOULD_SKIP_THIS */ + +/* Perform the SHA transformation. Note that this code, like MD5, seems to + break some optimizing compilers due to the complexity of the expressions + and the size of the basic block. It may be necessary to split it into + sections, e.g. based on the four subrounds + + Note that this corrupts the context->data area */ + +static void +SHATransform(dbus_uint32_t *digest, dbus_uint32_t *data) +{ + dbus_uint32_t A, B, C, D, E; /* Local vars */ + dbus_uint32_t eData[16]; /* Expanded data */ + + /* Set up first buffer and local data buffer */ + A = digest[0]; + B = digest[1]; + C = digest[2]; + D = digest[3]; + E = digest[4]; + memmove (eData, data, SHA_DATASIZE); + + /* Heavy mangling, in 4 sub-rounds of 20 interations each. */ + subRound (A, B, C, D, E, f1, K1, eData[0]); + subRound (E, A, B, C, D, f1, K1, eData[1]); + subRound (D, E, A, B, C, f1, K1, eData[2]); + subRound (C, D, E, A, B, f1, K1, eData[3]); + subRound (B, C, D, E, A, f1, K1, eData[4]); + subRound (A, B, C, D, E, f1, K1, eData[5]); + subRound (E, A, B, C, D, f1, K1, eData[6]); + subRound (D, E, A, B, C, f1, K1, eData[7]); + subRound (C, D, E, A, B, f1, K1, eData[8]); + subRound (B, C, D, E, A, f1, K1, eData[9]); + subRound (A, B, C, D, E, f1, K1, eData[10]); + subRound (E, A, B, C, D, f1, K1, eData[11]); + subRound (D, E, A, B, C, f1, K1, eData[12]); + subRound (C, D, E, A, B, f1, K1, eData[13]); + subRound (B, C, D, E, A, f1, K1, eData[14]); + subRound (A, B, C, D, E, f1, K1, eData[15]); + subRound (E, A, B, C, D, f1, K1, expand ( eData, 16) ); + subRound (D, E, A, B, C, f1, K1, expand ( eData, 17) ); + subRound (C, D, E, A, B, f1, K1, expand ( eData, 18) ); + subRound (B, C, D, E, A, f1, K1, expand ( eData, 19) ); + + subRound (A, B, C, D, E, f2, K2, expand ( eData, 20) ); + subRound (E, A, B, C, D, f2, K2, expand ( eData, 21) ); + subRound (D, E, A, B, C, f2, K2, expand ( eData, 22) ); + subRound (C, D, E, A, B, f2, K2, expand ( eData, 23) ); + subRound (B, C, D, E, A, f2, K2, expand ( eData, 24) ); + subRound (A, B, C, D, E, f2, K2, expand ( eData, 25) ); + subRound (E, A, B, C, D, f2, K2, expand ( eData, 26) ); + subRound (D, E, A, B, C, f2, K2, expand ( eData, 27) ); + subRound (C, D, E, A, B, f2, K2, expand ( eData, 28) ); + subRound (B, C, D, E, A, f2, K2, expand ( eData, 29) ); + subRound (A, B, C, D, E, f2, K2, expand ( eData, 30) ); + subRound (E, A, B, C, D, f2, K2, expand ( eData, 31) ); + subRound (D, E, A, B, C, f2, K2, expand ( eData, 32) ); + subRound (C, D, E, A, B, f2, K2, expand ( eData, 33) ); + subRound (B, C, D, E, A, f2, K2, expand ( eData, 34) ); + subRound (A, B, C, D, E, f2, K2, expand ( eData, 35) ); + subRound (E, A, B, C, D, f2, K2, expand ( eData, 36) ); + subRound (D, E, A, B, C, f2, K2, expand ( eData, 37) ); + subRound (C, D, E, A, B, f2, K2, expand ( eData, 38) ); + subRound (B, C, D, E, A, f2, K2, expand ( eData, 39) ); + + subRound (A, B, C, D, E, f3, K3, expand ( eData, 40) ); + subRound (E, A, B, C, D, f3, K3, expand ( eData, 41) ); + subRound (D, E, A, B, C, f3, K3, expand ( eData, 42) ); + subRound (C, D, E, A, B, f3, K3, expand ( eData, 43) ); + subRound (B, C, D, E, A, f3, K3, expand ( eData, 44) ); + subRound (A, B, C, D, E, f3, K3, expand ( eData, 45) ); + subRound (E, A, B, C, D, f3, K3, expand ( eData, 46) ); + subRound (D, E, A, B, C, f3, K3, expand ( eData, 47) ); + subRound (C, D, E, A, B, f3, K3, expand ( eData, 48) ); + subRound (B, C, D, E, A, f3, K3, expand ( eData, 49) ); + subRound (A, B, C, D, E, f3, K3, expand ( eData, 50) ); + subRound (E, A, B, C, D, f3, K3, expand ( eData, 51) ); + subRound (D, E, A, B, C, f3, K3, expand ( eData, 52) ); + subRound (C, D, E, A, B, f3, K3, expand ( eData, 53) ); + subRound (B, C, D, E, A, f3, K3, expand ( eData, 54) ); + subRound (A, B, C, D, E, f3, K3, expand ( eData, 55) ); + subRound (E, A, B, C, D, f3, K3, expand ( eData, 56) ); + subRound (D, E, A, B, C, f3, K3, expand ( eData, 57) ); + subRound (C, D, E, A, B, f3, K3, expand ( eData, 58) ); + subRound (B, C, D, E, A, f3, K3, expand ( eData, 59) ); + + subRound (A, B, C, D, E, f4, K4, expand ( eData, 60) ); + subRound (E, A, B, C, D, f4, K4, expand ( eData, 61) ); + subRound (D, E, A, B, C, f4, K4, expand ( eData, 62) ); + subRound (C, D, E, A, B, f4, K4, expand ( eData, 63) ); + subRound (B, C, D, E, A, f4, K4, expand ( eData, 64) ); + subRound (A, B, C, D, E, f4, K4, expand ( eData, 65) ); + subRound (E, A, B, C, D, f4, K4, expand ( eData, 66) ); + subRound (D, E, A, B, C, f4, K4, expand ( eData, 67) ); + subRound (C, D, E, A, B, f4, K4, expand ( eData, 68) ); + subRound (B, C, D, E, A, f4, K4, expand ( eData, 69) ); + subRound (A, B, C, D, E, f4, K4, expand ( eData, 70) ); + subRound (E, A, B, C, D, f4, K4, expand ( eData, 71) ); + subRound (D, E, A, B, C, f4, K4, expand ( eData, 72) ); + subRound (C, D, E, A, B, f4, K4, expand ( eData, 73) ); + subRound (B, C, D, E, A, f4, K4, expand ( eData, 74) ); + subRound (A, B, C, D, E, f4, K4, expand ( eData, 75) ); + subRound (E, A, B, C, D, f4, K4, expand ( eData, 76) ); + subRound (D, E, A, B, C, f4, K4, expand ( eData, 77) ); + subRound (C, D, E, A, B, f4, K4, expand ( eData, 78) ); + subRound (B, C, D, E, A, f4, K4, expand ( eData, 79) ); + + /* Build message digest */ + digest[0] += A; + digest[1] += B; + digest[2] += C; + digest[3] += D; + digest[4] += E; +} + +/* When run on a little-endian CPU we need to perform byte reversal on an + array of longwords. */ + +#ifdef WORDS_BIGENDIAN +#define swap_words(buffer, byte_count) +#else +static void +swap_words (dbus_uint32_t *buffer, + int byte_count) +{ + byte_count /= sizeof (dbus_uint32_t); + while (byte_count--) + { + *buffer = DBUS_UINT32_SWAP_LE_BE (*buffer); + ++buffer; + } +} +#endif + +static void +sha_init (DBusSHAContext *context) +{ + /* Set the h-vars to their initial values */ + context->digest[0] = h0init; + context->digest[1] = h1init; + context->digest[2] = h2init; + context->digest[3] = h3init; + context->digest[4] = h4init; + + /* Initialise bit count */ + context->count_lo = context->count_hi = 0; +} + +static void +sha_append (DBusSHAContext *context, + const unsigned char *buffer, + unsigned int count) +{ + dbus_uint32_t tmp; + unsigned int dataCount; + + /* Update bitcount */ + tmp = context->count_lo; + if (( context->count_lo = tmp + ( ( dbus_uint32_t) count << 3) ) < tmp) + context->count_hi++; /* Carry from low to high */ + context->count_hi += count >> 29; + + /* Get count of bytes already in data */ + dataCount = (int) (tmp >> 3) & 0x3F; + + /* Handle any leading odd-sized chunks */ + if (dataCount) + { + unsigned char *p = (unsigned char *) context->data + dataCount; + + dataCount = SHA_DATASIZE - dataCount; + if (count < dataCount) + { + memmove (p, buffer, count); + return; + } + memmove (p, buffer, dataCount); + swap_words (context->data, SHA_DATASIZE); + SHATransform (context->digest, context->data); + buffer += dataCount; + count -= dataCount; + } + + /* Process data in SHA_DATASIZE chunks */ + while (count >= SHA_DATASIZE) + { + memmove (context->data, buffer, SHA_DATASIZE); + swap_words (context->data, SHA_DATASIZE); + SHATransform (context->digest, context->data); + buffer += SHA_DATASIZE; + count -= SHA_DATASIZE; + } + + /* Handle any remaining bytes of data. */ + memmove (context->data, buffer, count); +} + + +/* Final wrapup - pad to SHA_DATASIZE-byte boundary with the bit pattern + 1 0* (64-bit count of bits processed, MSB-first) */ + +static void +sha_finish (DBusSHAContext *context, unsigned char digest[20]) +{ + int count; + unsigned char *data_p; + + /* Compute number of bytes mod 64 */ + count = (int) context->count_lo; + count = (count >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + data_p = (unsigned char *) context->data + count; + *data_p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = SHA_DATASIZE - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) + { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset (data_p, 0, count); + swap_words (context->data, SHA_DATASIZE); + SHATransform (context->digest, context->data); + + /* Now fill the next block with 56 bytes */ + memset (context->data, 0, SHA_DATASIZE - 8); + } + else + /* Pad block to 56 bytes */ + memset (data_p, 0, count - 8); + + /* Append length in bits and transform */ + context->data[14] = context->count_hi; + context->data[15] = context->count_lo; + + swap_words (context->data, SHA_DATASIZE - 8); + SHATransform (context->digest, context->data); + swap_words (context->digest, SHA_DIGESTSIZE); + memmove (digest, context->digest, SHA_DIGESTSIZE); +} + +/** @} */ /* End of internals */ + +/** + * @addtogroup DBusSHA + * + * @{ + */ + +/** + * Initializes the SHA context. + * + * @param context an uninitialized context, typically on the stack. + */ +void +_dbus_sha_init (DBusSHAContext *context) +{ + sha_init (context); +} + +/** + * Feeds more data into an existing shasum computation. + * + * @param context the SHA context + * @param data the additional data to hash + */ +void +_dbus_sha_update (DBusSHAContext *context, + const DBusString *data) +{ + unsigned int inputLen; + const unsigned char *input; + + input = (const unsigned char*) _dbus_string_get_const_data (data); + inputLen = _dbus_string_get_length (data); + + sha_append (context, input, inputLen); +} + +/** + * SHA finalization. Ends an SHA message-digest operation, writing the + * the message digest and zeroing the context. The results are + * returned as a raw 20-byte digest, not as the ascii-hex-digits + * string form of the digest. + * + * @param context the SHA context + * @param results string to append the 20-byte SHA digest to + * @returns #FALSE if not enough memory to append the digest + * + */ +dbus_bool_t +_dbus_sha_final (DBusSHAContext *context, + DBusString *results) +{ + unsigned char digest[20]; + + sha_finish (context, digest); + + if (!_dbus_string_append_len (results, digest, 20)) + return FALSE; + + /* some kind of security paranoia, though it seems pointless + * to me given the nonzeroed stuff flying around + */ + memset ((void*)context, '\0', sizeof (DBusSHAContext)); + + return TRUE; +} + +/** + * Computes the ASCII hex-encoded shasum of the given data and + * appends it to the output string. + * + * @param data input data to be hashed + * @param ascii_output string to append ASCII shasum to + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_sha_compute (const DBusString *data, + DBusString *ascii_output) +{ + DBusSHAContext context; + DBusString digest; + + _dbus_sha_init (&context); + + _dbus_sha_update (&context, data); + + if (!_dbus_string_init (&digest)) + return FALSE; + + if (!_dbus_sha_final (&context, &digest)) + goto error; + + if (!_dbus_string_hex_encode (&digest, 0, ascii_output, + _dbus_string_get_length (ascii_output))) + goto error; + + _dbus_string_free (&digest); + + return TRUE; + + error: + _dbus_string_free (&digest); + return FALSE; +} + +/** @} */ /* end of exported functions */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +static dbus_bool_t +check_sha_binary (const unsigned char *input, + int input_len, + const char *expected) +{ + DBusString input_str; + DBusString expected_str; + DBusString results; + + _dbus_string_init_const_len (&input_str, input, input_len); + _dbus_string_init_const (&expected_str, expected); + + if (!_dbus_string_init (&results)) + _dbus_assert_not_reached ("no memory for SHA-1 results"); + + if (!_dbus_sha_compute (&input_str, &results)) + _dbus_assert_not_reached ("no memory for SHA-1 results"); + + if (!_dbus_string_equal (&expected_str, &results)) + { + _dbus_warn ("Expected hash %s got %s for SHA-1 sum\n", + expected, + _dbus_string_get_const_data (&results)); + _dbus_string_free (&results); + return FALSE; + } + + _dbus_string_free (&results); + return TRUE; +} + +static dbus_bool_t +check_sha_str (const char *input, + const char *expected) +{ + return check_sha_binary (input, strlen (input), expected); +} + +static dbus_bool_t +decode_compact_string (const DBusString *line, + DBusString *decoded) +{ + int n_bits; + dbus_bool_t current_b; + int offset; + int next; + long val; + int length_bytes; + + offset = 0; + next = 0; + + if (!_dbus_string_parse_int (line, offset, &val, &next)) + { + fprintf (stderr, "could not parse length at start of compact string: %s\n", + _dbus_string_get_const_data (line)); + return FALSE; + } + + _dbus_string_skip_blank (line, next, &next); + + offset = next; + if (!_dbus_string_parse_int (line, offset, &val, &next)) + { + fprintf (stderr, "could not parse start bit 'b' in compact string: %s\n", + _dbus_string_get_const_data (line)); + return FALSE; + } + + if (!(val == 0 || val == 1)) + { + fprintf (stderr, "the value 'b' must be 0 or 1, see sha-1/Readme.txt\n"); + return FALSE; + } + + _dbus_string_skip_blank (line, next, &next); + + current_b = val; + n_bits = 0; + + while (next < _dbus_string_get_length (line)) + { + int total_bits; + + offset = next; + + if (_dbus_string_get_byte (line, offset) == '^') + break; + + if (!_dbus_string_parse_int (line, offset, &val, &next)) + { + fprintf (stderr, "could not parse bit count in compact string\n"); + return FALSE; + } + + /* We now append "val" copies of "current_b" bits to the string */ + total_bits = n_bits + val; + while (n_bits < total_bits) + { + int byte_containing_next_bit = n_bits / 8; + int bit_containing_next_bit = 7 - (n_bits % 8); + unsigned char old_byte; + + if (byte_containing_next_bit >= _dbus_string_get_length (decoded)) + { + if (!_dbus_string_set_length (decoded, byte_containing_next_bit + 1)) + _dbus_assert_not_reached ("no memory to extend to next byte"); + } + + old_byte = _dbus_string_get_byte (decoded, byte_containing_next_bit); + old_byte |= current_b << bit_containing_next_bit; + +#if 0 + printf ("Appending bit %d to byte %d at bit %d resulting in byte 0x%x\n", + current_b, byte_containing_next_bit, + bit_containing_next_bit, old_byte); +#endif + + _dbus_string_set_byte (decoded, byte_containing_next_bit, old_byte); + + ++n_bits; + } + + _dbus_string_skip_blank (line, next, &next); + + current_b = !current_b; + } + + length_bytes = (n_bits / 8 + ((n_bits % 8) ? 1 : 0)); + + if (_dbus_string_get_length (decoded) != length_bytes) + { + fprintf (stderr, "Expected length %d bytes %d bits for compact string, got %d bytes\n", + length_bytes, n_bits, _dbus_string_get_length (decoded)); + return FALSE; + } + else + return TRUE; +} + +static dbus_bool_t +get_next_expected_result (DBusString *results, + DBusString *result) +{ + DBusString line; + dbus_bool_t retval; + + retval = FALSE; + + if (!_dbus_string_init (&line)) + _dbus_assert_not_reached ("no memory"); + + next_iteration: + while (_dbus_string_pop_line (results, &line)) + { + _dbus_string_delete_leading_blanks (&line); + + if (_dbus_string_get_length (&line) == 0) + goto next_iteration; + else if (_dbus_string_starts_with_c_str (&line, "#")) + goto next_iteration; + else if (_dbus_string_starts_with_c_str (&line, "H>")) + { + /* don't print */ + } + else if (_dbus_string_starts_with_c_str (&line, "D>") || + _dbus_string_starts_with_c_str (&line, "")) + { + printf ("SHA-1: %s\n", _dbus_string_get_const_data (&line)); + + if (_dbus_string_find (&line, 0, "Type 3", NULL)) + { + /* See sha-1/Readme.txt - the "Type 3" tests are + * random seeds, rather than data to be hashed. + * we'd have to do a little bit more implementation + * to use those tests. + */ + + printf (" (ending tests due to Type 3 tests seen - this is normal)\n"); + break; + } + } + else if (_dbus_string_starts_with_c_str (&line, "D>") || + _dbus_string_starts_with_c_str (&line, " +#include +#include + +DBUS_BEGIN_DECLS + +typedef struct DBusSHAContext DBusSHAContext; + +/** + * Struct storing state of the SHA algorithm + */ +struct DBusSHAContext +{ + dbus_uint32_t digest[5]; /**< Message digest */ + dbus_uint32_t count_lo; /**< 64-bit bit count */ + dbus_uint32_t count_hi; /**< No clue */ + dbus_uint32_t data[16]; /**< SHA data buffer */ +}; + +void _dbus_sha_init (DBusSHAContext *context); +void _dbus_sha_update (DBusSHAContext *context, + const DBusString *data); +dbus_bool_t _dbus_sha_final (DBusSHAContext *context, + DBusString *results); +dbus_bool_t _dbus_sha_compute (const DBusString *data, + DBusString *ascii_output); + +DBUS_END_DECLS + +#endif /* DBUS_SHA_H */ diff --git a/dbus/dbus-shared.h b/dbus/dbus-shared.h new file mode 100644 index 00000000..6a576704 --- /dev/null +++ b/dbus/dbus-shared.h @@ -0,0 +1,131 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-shared.h Stuff used by both dbus/dbus.h low-level and C/C++ binding APIs + * + * Copyright (C) 2004 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_SHARED_H +#define DBUS_SHARED_H + +/* Don't include anything in here from anywhere else. It's + * intended for use by any random library. + */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* avoids confusing emacs indentation */ +#endif +#endif + +/* Normally docs are in .c files, but there isn't a .c file for this. */ +/** + * @defgroup DBusShared Shared constants + * @ingroup DBus + * + * @brief Shared header included by both libdbus and C/C++ bindings such as the GLib bindings. + * + * Usually a C/C++ binding such as the GLib or Qt binding won't want to include dbus.h in its + * public headers. However, a few constants and macros may be useful to include; those are + * found here and in dbus-protocol.h + * + * @{ + */ + + +/** + * Well-known bus types. See dbus_bus_get(). + */ +typedef enum +{ + DBUS_BUS_SESSION, /**< The login session bus */ + DBUS_BUS_SYSTEM, /**< The systemwide bus */ + DBUS_BUS_STARTER /**< The bus that started us, if any */ +} DBusBusType; + +/** + * Results that a message handler can return. + */ +typedef enum +{ + DBUS_HANDLER_RESULT_HANDLED, /**< Message has had its effect - no need to run more handlers. */ + DBUS_HANDLER_RESULT_NOT_YET_HANDLED, /**< Message has not had any effect - see if other handlers want it. */ + DBUS_HANDLER_RESULT_NEED_MEMORY /**< Need more memory in order to return #DBUS_HANDLER_RESULT_HANDLED or #DBUS_HANDLER_RESULT_NOT_YET_HANDLED. Please try again later with more memory. */ +} DBusHandlerResult; + +/* Bus names */ + +/** The bus name used to talk to the bus itself. */ +#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" + +/* Paths */ +/** The object path used to talk to the bus itself. */ +#define DBUS_PATH_DBUS "/org/freedesktop/DBus" +/** The object path used in local/in-process-generated messages. */ +#define DBUS_PATH_LOCAL "/org/freedesktop/DBus/Local" + +/* Interfaces, these #define don't do much other than + * catch typos at compile time + */ +/** The interface exported by the object with #DBUS_SERVICE_DBUS and #DBUS_PATH_DBUS */ +#define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" +/** The interface supported by introspectable objects */ +#define DBUS_INTERFACE_INTROSPECTABLE "org.freedesktop.DBus.Introspectable" +/** The interface supported by objects with properties */ +#define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" +/** The interface supported by most dbus peers */ +#define DBUS_INTERFACE_PEER "org.freedesktop.DBus.Peer" + +/** This is a special interface whose methods can only be invoked + * by the local implementation (messages from remote apps aren't + * allowed to specify this interface). + */ +#define DBUS_INTERFACE_LOCAL "org.freedesktop.DBus.Local" + +/* Owner flags */ +#define DBUS_NAME_FLAG_ALLOW_REPLACEMENT 0x1 /**< Allow another service to become the primary owner if requested */ +#define DBUS_NAME_FLAG_REPLACE_EXISTING 0x2 /**< Request to replace the current primary owner */ +#define DBUS_NAME_FLAG_DO_NOT_QUEUE 0x4 /**< If we can not become the primary owner do not place us in the queue */ + +/* Replies to request for a name */ +#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 /**< Service has become the primary owner of the requested name */ +#define DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 /**< Service could not become the primary owner and has been placed in the queue */ +#define DBUS_REQUEST_NAME_REPLY_EXISTS 3 /**< Service is already in the queue */ +#define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4 /**< Service is already the primary owner */ + +/* Replies to releasing a name */ +#define DBUS_RELEASE_NAME_REPLY_RELEASED 1 /**< Service was released from the given name */ +#define DBUS_RELEASE_NAME_REPLY_NON_EXISTENT 2 /**< The given name does not exist on the bus */ +#define DBUS_RELEASE_NAME_REPLY_NOT_OWNER 3 /**< Service is not an owner of the given name */ + +/* Replies to service starts */ +#define DBUS_START_REPLY_SUCCESS 1 /**< Service was auto started */ +#define DBUS_START_REPLY_ALREADY_RUNNING 2 /**< Service was already running */ + +/** @} */ + +#ifdef __cplusplus +#if 0 +{ /* avoids confusing emacs indentation */ +#endif +} +#endif + +#endif /* DBUS_SHARED_H */ diff --git a/dbus/dbus-shell.c b/dbus/dbus-shell.c new file mode 100644 index 00000000..57900d88 --- /dev/null +++ b/dbus/dbus-shell.c @@ -0,0 +1,640 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-shell.c Shell command line utility functions. + * + * Copyright (C) 2002, 2003 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include "dbus-internals.h" +#include "dbus-list.h" +#include "dbus-memory.h" +#include "dbus-protocol.h" +#include "dbus-shell.h" +#include "dbus-string.h" + +/* Single quotes preserve the literal string exactly. escape + * sequences are not allowed; not even \' - if you want a ' + * in the quoted text, you have to do something like 'foo'\''bar' + * + * Double quotes allow $ ` " \ and newline to be escaped with backslash. + * Otherwise double quotes preserve things literally. + */ + +static dbus_bool_t +unquote_string_inplace (char* str, char** end) +{ + char* dest; + char* s; + char quote_char; + + dest = s = str; + + quote_char = *s; + + if (!(*s == '"' || *s == '\'')) + { + *end = str; + return FALSE; + } + + /* Skip the initial quote mark */ + ++s; + + if (quote_char == '"') + { + while (*s) + { + _dbus_assert(s > dest); /* loop invariant */ + + switch (*s) + { + case '"': + /* End of the string, return now */ + *dest = '\0'; + ++s; + *end = s; + return TRUE; + + case '\\': + /* Possible escaped quote or \ */ + ++s; + switch (*s) + { + case '"': + case '\\': + case '`': + case '$': + case '\n': + *dest = *s; + ++s; + ++dest; + break; + + default: + /* not an escaped char */ + *dest = '\\'; + ++dest; + /* ++s already done. */ + break; + } + break; + + default: + *dest = *s; + ++dest; + ++s; + break; + } + + _dbus_assert(s > dest); /* loop invariant */ + } + } + else + { + while (*s) + { + _dbus_assert(s > dest); /* loop invariant */ + + if (*s == '\'') + { + /* End of the string, return now */ + *dest = '\0'; + ++s; + *end = s; + return TRUE; + } + else + { + *dest = *s; + ++dest; + ++s; + } + + _dbus_assert(s > dest); /* loop invariant */ + } + } + + /* If we reach here this means the close quote was never encountered */ + + *dest = '\0'; + + *end = s; + return FALSE; +} + +/** + * Unquotes a string as the shell (/bin/sh) would. Only handles + * quotes; if a string contains file globs, arithmetic operators, + * variables, backticks, redirections, or other special-to-the-shell + * features, the result will be different from the result a real shell + * would produce (the variables, backticks, etc. will be passed + * through literally instead of being expanded). This function is + * guaranteed to succeed if applied to the result of + * _dbus_shell_quote(). If it fails, it returns %NULL. + * The @quoted_string need not actually contain quoted or + * escaped text; _dbus_shell_unquote() simply goes through the string and + * unquotes/unescapes anything that the shell would. Both single and + * double quotes are handled, as are escapes including escaped + * newlines. The return value must be freed with dbus_free(). + * + * Shell quoting rules are a bit strange. Single quotes preserve the + * literal string exactly. escape sequences are not allowed; not even + * \' - if you want a ' in the quoted text, you have to do something + * like 'foo'\''bar'. Double quotes allow $, `, ", \, and newline to + * be escaped with backslash. Otherwise double quotes preserve things + * literally. + * + * @quoted_string: shell-quoted string + **/ +char* +_dbus_shell_unquote (const char *quoted_string) +{ + char *unquoted; + char *end; + char *start; + char *ret; + DBusString retval; + + unquoted = _dbus_strdup (quoted_string); + if (unquoted == NULL) + return NULL; + + start = unquoted; + end = unquoted; + if (!_dbus_string_init (&retval)) + { + dbus_free (unquoted); + return NULL; + } + + /* The loop allows cases such as + * "foo"blah blah'bar'woo foo"baz"la la la\'\''foo' + */ + while (*start) + { + /* Append all non-quoted chars, honoring backslash escape + */ + + while (*start && !(*start == '"' || *start == '\'')) + { + if (*start == '\\') + { + /* all characters can get escaped by backslash, + * except newline, which is removed if it follows + * a backslash outside of quotes + */ + + ++start; + if (*start) + { + if (*start != '\n') + { + if (!_dbus_string_append_byte (&retval, *start)) + goto error; + } + ++start; + } + } + else + { + if (!_dbus_string_append_byte (&retval, *start)) + goto error; + ++start; + } + } + + if (*start) + { + if (!unquote_string_inplace (start, &end)) + goto error; + else + { + if (!_dbus_string_append (&retval, start)) + goto error; + start = end; + } + } + } + + ret = _dbus_strdup (_dbus_string_get_data (&retval)); + if (!ret) + goto error; + + dbus_free (unquoted); + _dbus_string_free (&retval); + + return ret; + + error: + dbus_free (unquoted); + _dbus_string_free (&retval); + return NULL; +} + +/* _dbus_shell_parse_argv() does a semi-arbitrary weird subset of the way + * the shell parses a command line. We don't do variable expansion, + * don't understand that operators are tokens, don't do tilde expansion, + * don't do command substitution, no arithmetic expansion, IFS gets ignored, + * don't do filename globs, don't remove redirection stuff, etc. + * + * READ THE UNIX98 SPEC on "Shell Command Language" before changing + * the behavior of this code. + * + * Steps to parsing the argv string: + * + * - tokenize the string (but since we ignore operators, + * our tokenization may diverge from what the shell would do) + * note that tokenization ignores the internals of a quoted + * word and it always splits on spaces, not on IFS even + * if we used IFS. We also ignore "end of input indicator" + * (I guess this is control-D?) + * + * Tokenization steps, from UNIX98 with operator stuff removed, + * are: + * + * 1) "If the current character is backslash, single-quote or + * double-quote (\, ' or ") and it is not quoted, it will affect + * quoting for subsequent characters up to the end of the quoted + * text. The rules for quoting are as described in Quoting + * . During token recognition no substitutions will be actually + * performed, and the result token will contain exactly the + * characters that appear in the input (except for newline + * character joining), unmodified, including any embedded or + * enclosing quotes or substitution operators, between the quote + * mark and the end of the quoted text. The token will not be + * delimited by the end of the quoted field." + * + * 2) "If the current character is an unquoted newline character, + * the current token will be delimited." + * + * 3) "If the current character is an unquoted blank character, any + * token containing the previous character is delimited and the + * current character will be discarded." + * + * 4) "If the previous character was part of a word, the current + * character will be appended to that word." + * + * 5) "If the current character is a "#", it and all subsequent + * characters up to, but excluding, the next newline character + * will be discarded as a comment. The newline character that + * ends the line is not considered part of the comment. The + * "#" starts a comment only when it is at the beginning of a + * token. Since the search for the end-of-comment does not + * consider an escaped newline character specially, a comment + * cannot be continued to the next line." + * + * 6) "The current character will be used as the start of a new word." + * + * + * - for each token (word), perform portions of word expansion, namely + * field splitting (using default whitespace IFS) and quote + * removal. Field splitting may increase the number of words. + * Quote removal does not increase the number of words. + * + * "If the complete expansion appropriate for a word results in an + * empty field, that empty field will be deleted from the list of + * fields that form the completely expanded command, unless the + * original word contained single-quote or double-quote characters." + * - UNIX98 spec + * + * + */ + +static dbus_bool_t +delimit_token (DBusString *token, + DBusList **retval, + DBusError *error) +{ + char *str; + + str = _dbus_strdup (_dbus_string_get_data (token)); + if (!str) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_list_append (retval, str)) + { + dbus_free (str); + _DBUS_SET_OOM (error); + return FALSE; + } + + return TRUE; +} + +static DBusList* +tokenize_command_line (const char *command_line, DBusError *error) +{ + char current_quote; + const char *p; + DBusString current_token; + DBusList *retval = NULL; + dbus_bool_t quoted;; + + current_quote = '\0'; + quoted = FALSE; + p = command_line; + + if (!_dbus_string_init (¤t_token)) + { + _DBUS_SET_OOM (error); + return NULL; + } + + while (*p) + { + if (current_quote == '\\') + { + if (*p == '\n') + { + /* we append nothing; backslash-newline become nothing */ + } + else + { + if (!_dbus_string_append_byte (¤t_token, '\\') || + !_dbus_string_append_byte (¤t_token, *p)) + { + _DBUS_SET_OOM (error); + goto error; + } + } + + current_quote = '\0'; + } + else if (current_quote == '#') + { + /* Discard up to and including next newline */ + while (*p && *p != '\n') + ++p; + + current_quote = '\0'; + + if (*p == '\0') + break; + } + else if (current_quote) + { + if (*p == current_quote && + /* check that it isn't an escaped double quote */ + !(current_quote == '"' && quoted)) + { + /* close the quote */ + current_quote = '\0'; + } + + /* Everything inside quotes, and the close quote, + * gets appended literally. + */ + + if (!_dbus_string_append_byte (¤t_token, *p)) + { + _DBUS_SET_OOM (error); + goto error; + } + } + else + { + switch (*p) + { + case '\n': + if (!delimit_token (¤t_token, &retval, error)) + goto error; + + _dbus_string_free (¤t_token); + + if (!_dbus_string_init (¤t_token)) + { + _DBUS_SET_OOM (error); + goto init_error; + } + + break; + + case ' ': + case '\t': + /* If the current token contains the previous char, delimit + * the current token. A nonzero length + * token should always contain the previous char. + */ + if (_dbus_string_get_length (¤t_token) > 0) + { + if (!delimit_token (¤t_token, &retval, error)) + goto error; + + _dbus_string_free (¤t_token); + + if (!_dbus_string_init (¤t_token)) + { + _DBUS_SET_OOM (error); + goto init_error; + } + + } + + /* discard all unquoted blanks (don't add them to a token) */ + break; + + + /* single/double quotes are appended to the token, + * escapes are maybe appended next time through the loop, + * comment chars are never appended. + */ + + case '\'': + case '"': + if (!_dbus_string_append_byte (¤t_token, *p)) + { + _DBUS_SET_OOM (error); + goto error; + } + + /* FALL THRU */ + + case '#': + case '\\': + current_quote = *p; + break; + + default: + /* Combines rules 4) and 6) - if we have a token, append to it, + * otherwise create a new token. + */ + if (!_dbus_string_append_byte (¤t_token, *p)) + { + _DBUS_SET_OOM (error); + goto error; + } + break; + } + } + + /* We need to count consecutive backslashes mod 2, + * to detect escaped doublequotes. + */ + if (*p != '\\') + quoted = FALSE; + else + quoted = !quoted; + + ++p; + } + + if (!delimit_token (¤t_token, &retval, error)) + goto error; + + if (current_quote) + { + dbus_set_error_const (error, DBUS_ERROR_INVALID_ARGS, "Unclosed quotes in command line"); + goto error; + } + + if (retval == NULL) + { + dbus_set_error_const (error, DBUS_ERROR_INVALID_ARGS, "No tokens found in command line"); + goto error; + } + + _dbus_string_free (¤t_token); + + return retval; + + error: + _dbus_string_free (¤t_token); + + init_error: + if (retval) + { + _dbus_list_foreach (&retval, (DBusForeachFunction) dbus_free, NULL); + _dbus_list_clear (&retval); + } + + return NULL; +} + +/** + * _dbus_shell_parse_argv: + * + * Parses a command line into an argument vector, in much the same way + * the shell would, but without many of the expansions the shell would + * perform (variable expansion, globs, operators, filename expansion, + * etc. are not supported). The results are defined to be the same as + * those you would get from a UNIX98 /bin/sh, as long as the input + * contains none of the unsupported shell expansions. If the input + * does contain such expansions, they are passed through + * literally. Free the returned vector with dbus_free_string_array(). + * + * @command_line: command line to parse + * @argcp: return location for number of args + * @argvp: return location for array of args + * @error: error information + **/ +dbus_bool_t +_dbus_shell_parse_argv (const char *command_line, + int *argcp, + char ***argvp, + DBusError *error) +{ + /* Code based on poptParseArgvString() from libpopt */ + int argc = 0; + char **argv = NULL; + DBusList *tokens = NULL; + int i; + DBusList *tmp_list; + + if (!command_line) + { + _dbus_verbose ("Command line is NULL\n"); + return FALSE; + } + + tokens = tokenize_command_line (command_line, error); + if (tokens == NULL) + { + _dbus_verbose ("No tokens for command line '%s'\n", command_line); + return FALSE; + } + + /* Because we can't have introduced any new blank space into the + * tokens (we didn't do any new expansions), we don't need to + * perform field splitting. If we were going to honor IFS or do any + * expansions, we would have to do field splitting on each word + * here. Also, if we were going to do any expansion we would need to + * remove any zero-length words that didn't contain quotes + * originally; but since there's no expansion we know all words have + * nonzero length, unless they contain quotes. + * + * So, we simply remove quotes, and don't do any field splitting or + * empty word removal, since we know there was no way to introduce + * such things. + */ + + argc = _dbus_list_get_length (&tokens); + argv = dbus_new (char *, argc + 1); + if (!argv) + { + _DBUS_SET_OOM (error); + goto error; + } + + i = 0; + tmp_list = tokens; + while (tmp_list) + { + argv[i] = _dbus_shell_unquote (tmp_list->data); + + if (!argv[i]) + { + int j; + for (j = 0; j < i; j++) + dbus_free(argv[j]); + + dbus_free (argv); + _DBUS_SET_OOM (error); + goto error; + } + + tmp_list = _dbus_list_get_next_link (&tokens, tmp_list); + ++i; + } + argv[argc] = NULL; + + _dbus_list_foreach (&tokens, (DBusForeachFunction) dbus_free, NULL); + _dbus_list_clear (&tokens); + + if (argcp) + *argcp = argc; + + if (argvp) + *argvp = argv; + else + dbus_free_string_array (argv); + + return TRUE; + + error: + _dbus_list_foreach (&tokens, (DBusForeachFunction) dbus_free, NULL); + _dbus_list_clear (&tokens); + + return FALSE; + +} diff --git a/dbus/dbus-shell.h b/dbus/dbus-shell.h new file mode 100644 index 00000000..06da274e --- /dev/null +++ b/dbus/dbus-shell.h @@ -0,0 +1,41 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-shell.h Shell command line utility functions. + * + * Copyright (C) 2002, 2003 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#ifndef DBUS_SHELL_H +#define DBUS_SHELL_H + +DBUS_BEGIN_DECLS + +char* _dbus_shell_unquote (const char *quoted_string); +dbus_bool_t _dbus_shell_parse_argv (const char *command_line, + int *argcp, + char ***argvp, + DBusError *error); + +DBUS_END_DECLS + +#endif /* DBUS_SHELL_H */ + + diff --git a/dbus/dbus-signature.c b/dbus/dbus-signature.c new file mode 100644 index 00000000..5c152580 --- /dev/null +++ b/dbus/dbus-signature.c @@ -0,0 +1,542 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-signature.c Routines for reading recursive type signatures + * + * Copyright (C) 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-signature.h" +#include "dbus-marshal-recursive.h" +#include "dbus-marshal-basic.h" +#include "dbus-internals.h" +#include "dbus-test.h" + +/** + * Implementation details of #DBusSignatureIter, all fields are private + */ +typedef struct +{ + const char *pos; /**< current position in the signature string */ + unsigned int finished : 1; /**< true if we are at the end iter */ + unsigned int in_array : 1; /**< true if we are a subiterator pointing to an array's element type */ +} DBusSignatureRealIter; + +/** macro that checks whether a typecode is a container type */ +#define TYPE_IS_CONTAINER(typecode) \ + ((typecode) == DBUS_TYPE_STRUCT || \ + (typecode) == DBUS_TYPE_DICT_ENTRY || \ + (typecode) == DBUS_TYPE_VARIANT || \ + (typecode) == DBUS_TYPE_ARRAY) + + +/** + * @defgroup DBusSignature Type signature parsing + * @ingroup DBus + * @brief Parsing D-Bus type signatures + * @{ + */ + +/** + * Initializes a #DBusSignatureIter for reading a type signature. This + * function is not safe to use on invalid signatures; be sure to + * validate potentially invalid signatures with dbus_signature_validate + * before using this function. + * + * @param iter pointer to an iterator to initialize + * @param signature the type signature + */ +void +dbus_signature_iter_init (DBusSignatureIter *iter, + const char *signature) +{ + DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter; + + real_iter->pos = signature; + real_iter->finished = FALSE; + real_iter->in_array = FALSE; +} + +/** + * Returns the current type pointed to by the iterator. + * If the iterator is pointing at a type code such as 's', then + * it will be returned directly. + * + * However, when the parser encounters a container type start + * character such as '(' for a structure, the corresponding type for + * the container will be returned, e.g. DBUS_TYPE_STRUCT, not '('. + * In this case, you should initialize a sub-iterator with + * dbus_signature_iter_recurse() to parse the container type. + * + * @param iter pointer to an iterator + * @returns current type (e.g. #DBUS_TYPE_STRING, #DBUS_TYPE_ARRAY) + */ +int +dbus_signature_iter_get_current_type (const DBusSignatureIter *iter) +{ + DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter; + + return _dbus_first_type_in_signature_c_str (real_iter->pos, 0); +} + +/** + * Returns the signature of the single complete type starting at the + * given iterator. + * + * For example, if the iterator is pointing at the start of "(ii)ii" + * (which is "a struct of two ints, followed by an int, followed by an + * int"), then "(ii)" would be returned. If the iterator is pointing at + * one of the "i" then just that "i" would be returned. + * + * @param iter pointer to an iterator + * @returns current signature; or #NULL if no memory. Should be freed with dbus_free() + */ +char * +dbus_signature_iter_get_signature (const DBusSignatureIter *iter) +{ + DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter; + DBusString str; + char *ret; + int pos; + + if (!_dbus_string_init (&str)) + return NULL; + + pos = 0; + _dbus_type_signature_next (real_iter->pos, &pos); + + if (!_dbus_string_append_len (&str, real_iter->pos, pos)) + return NULL; + if (!_dbus_string_steal_data (&str, &ret)) + ret = NULL; + _dbus_string_free (&str); + + return ret; +} + +/** + * Convenience function for returning the element type of an array; + * This function allows you to avoid initializing a sub-iterator and + * getting its current type. + * + * Undefined behavior results if you invoke this function when the + * current type of the iterator is not #DBUS_TYPE_ARRAY. + * + * @param iter pointer to an iterator + * @returns current array element type + */ +int +dbus_signature_iter_get_element_type (const DBusSignatureIter *iter) +{ + DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter; + + _dbus_return_val_if_fail (dbus_signature_iter_get_current_type (iter) == DBUS_TYPE_ARRAY, DBUS_TYPE_INVALID); + + return _dbus_first_type_in_signature_c_str (real_iter->pos, 1); +} + +/** + * Skip to the next value on this "level". e.g. the next field in a + * struct, the next value in an array. Returns #FALSE at the end of the + * current container. + * + * @param iter the iterator + * @returns FALSE if nothing more to read at or below this level + */ +dbus_bool_t +dbus_signature_iter_next (DBusSignatureIter *iter) +{ + DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter; + + if (real_iter->finished) + return FALSE; + else + { + int pos; + + if (real_iter->in_array) + { + real_iter->finished = TRUE; + return FALSE; + } + + pos = 0; + _dbus_type_signature_next (real_iter->pos, &pos); + real_iter->pos += pos; + + if (*real_iter->pos == DBUS_STRUCT_END_CHAR + || *real_iter->pos == DBUS_DICT_ENTRY_END_CHAR) + { + real_iter->finished = TRUE; + return FALSE; + } + + return *real_iter->pos != DBUS_TYPE_INVALID; + } +} + +/** + * Initialize a new iterator pointing to the first type in the current + * container. + * + * The results are undefined when calling this if the current type is + * a non-container (i.e. if dbus_type_is_container() returns #FALSE + * for the result of dbus_signature_iter_get_current_type()). + * + * @param iter the current interator + * @param subiter an iterator to initialize pointing to the first child + */ +void +dbus_signature_iter_recurse (const DBusSignatureIter *iter, + DBusSignatureIter *subiter) +{ + DBusSignatureRealIter *real_iter = (DBusSignatureRealIter *) iter; + DBusSignatureRealIter *real_sub_iter = (DBusSignatureRealIter *) subiter; + + _dbus_return_if_fail (dbus_type_is_container (dbus_signature_iter_get_current_type (iter))); + + *real_sub_iter = *real_iter; + real_sub_iter->in_array = FALSE; + real_sub_iter->pos++; + + if (dbus_signature_iter_get_current_type (iter) == DBUS_TYPE_ARRAY) + real_sub_iter->in_array = TRUE; +} + +/** + * Check a type signature for validity. Remember that #NULL can always + * be passed instead of a DBusError*, if you don't care about having + * an error name and message. + * + * @param signature a potentially invalid type signature + * @param error error return + * @returns #TRUE if signature is valid or #FALSE if an error is set + */ +dbus_bool_t +dbus_signature_validate (const char *signature, + DBusError *error) + +{ + DBusString str; + DBusValidity reason; + + _dbus_string_init_const (&str, signature); + reason = _dbus_validate_signature_with_reason (&str, 0, _dbus_string_get_length (&str)); + + if (reason == DBUS_VALID) + return TRUE; + else + { + dbus_set_error (error, DBUS_ERROR_INVALID_SIGNATURE, _dbus_validity_to_error_message (reason)); + return FALSE; + } +} + +/** + * Check that a type signature is both valid and contains exactly one + * complete type. "One complete type" means a single basic type, + * array, struct, or dictionary, though the struct or array may be + * arbitrarily recursive and complex. More than one complete type + * would mean for example "ii" or two integers in sequence. + * + * @param signature a potentially invalid type signature + * @param error error return + * @returns #TRUE if signature is valid and has exactly one complete type + */ +dbus_bool_t +dbus_signature_validate_single (const char *signature, + DBusError *error) +{ + DBusSignatureIter iter; + + if (!dbus_signature_validate (signature, error)) + return FALSE; + + dbus_signature_iter_init (&iter, signature); + if (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_INVALID) + goto lose; + if (!dbus_signature_iter_next (&iter)) + return TRUE; + lose: + dbus_set_error (error, DBUS_ERROR_INVALID_SIGNATURE, "Exactly one complete type required in signature"); + return FALSE; +} + +/** + * A "container type" can contain basic types, or nested + * container types. #DBUS_TYPE_INVALID is not a container type. + * + * This function will crash if passed a typecode that isn't + * in dbus-protocol.h + * + * @returns #TRUE if type is a container + */ +dbus_bool_t +dbus_type_is_container (int typecode) +{ + /* only reasonable (non-line-noise) typecodes are allowed */ + _dbus_return_val_if_fail (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID, + FALSE); + return TYPE_IS_CONTAINER (typecode); +} + +/** + * A "basic type" is a somewhat arbitrary concept, but the intent is + * to include those types that are fully-specified by a single + * typecode, with no additional type information or nested values. So + * all numbers and strings are basic types and structs, arrays, and + * variants are not basic types. #DBUS_TYPE_INVALID is not a basic + * type. + * + * This function will crash if passed a typecode that isn't + * in dbus-protocol.h + * + * @returns #TRUE if type is basic + */ +dbus_bool_t +dbus_type_is_basic (int typecode) +{ + /* only reasonable (non-line-noise) typecodes are allowed */ + _dbus_return_val_if_fail (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID, + FALSE); + + /* everything that isn't invalid or a container */ + return !(typecode == DBUS_TYPE_INVALID || TYPE_IS_CONTAINER (typecode)); +} + +/** + * Tells you whether values of this type can change length if you set + * them to some other value. For this purpose, you assume that the + * first byte of the old and new value would be in the same location, + * so alignment padding is not a factor. + * + * This function is useful to determine whether + * dbus_message_iter_get_fixed_array() may be used. + * + * Some structs are fixed-size (if they contain only fixed-size types) + * but struct is not considered a fixed type for purposes of this + * function. + * + * This function will crash if passed a typecode that isn't + * in dbus-protocol.h + * + * @returns #FALSE if the type can occupy different lengths + */ +dbus_bool_t +dbus_type_is_fixed (int typecode) +{ + /* only reasonable (non-line-noise) typecodes are allowed */ + _dbus_return_val_if_fail (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID, + FALSE); + + switch (typecode) + { + case DBUS_TYPE_BYTE: + case DBUS_TYPE_BOOLEAN: + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + case DBUS_TYPE_DOUBLE: + return TRUE; + default: + return FALSE; + } +} + +/** @} */ /* end of DBusSignature group */ + +#ifdef DBUS_BUILD_TESTS + +/** + * @ingroup DBusSignatureInternals + * Unit test for DBusSignature. + * + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_signature_test (void) +{ + DBusSignatureIter iter; + DBusSignatureIter subiter; + DBusSignatureIter subsubiter; + DBusSignatureIter subsubsubiter; + const char *sig; + dbus_bool_t boolres; + + _dbus_assert (sizeof (DBusSignatureIter) >= sizeof (DBusSignatureRealIter)); + + sig = ""; + _dbus_assert (dbus_signature_validate (sig, NULL)); + _dbus_assert (!dbus_signature_validate_single (sig, NULL)); + dbus_signature_iter_init (&iter, sig); + _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_INVALID); + + sig = DBUS_TYPE_STRING_AS_STRING; + _dbus_assert (dbus_signature_validate (sig, NULL)); + _dbus_assert (dbus_signature_validate_single (sig, NULL)); + dbus_signature_iter_init (&iter, sig); + _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRING); + + sig = DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_BYTE_AS_STRING; + _dbus_assert (dbus_signature_validate (sig, NULL)); + dbus_signature_iter_init (&iter, sig); + _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRING); + boolres = dbus_signature_iter_next (&iter); + _dbus_assert (boolres); + _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_BYTE); + + sig = DBUS_TYPE_UINT16_AS_STRING + DBUS_STRUCT_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_UINT32_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_TYPE_DOUBLE_AS_STRING + DBUS_STRUCT_END_CHAR_AS_STRING; + _dbus_assert (dbus_signature_validate (sig, NULL)); + dbus_signature_iter_init (&iter, sig); + _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_UINT16); + boolres = dbus_signature_iter_next (&iter); + _dbus_assert (boolres); + _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRUCT); + dbus_signature_iter_recurse (&iter, &subiter); + _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_STRING); + boolres = dbus_signature_iter_next (&subiter); + _dbus_assert (boolres); + _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_UINT32); + boolres = dbus_signature_iter_next (&subiter); + _dbus_assert (boolres); + _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_VARIANT); + boolres = dbus_signature_iter_next (&subiter); + _dbus_assert (boolres); + _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_DOUBLE); + + sig = DBUS_TYPE_UINT16_AS_STRING + DBUS_STRUCT_BEGIN_CHAR_AS_STRING + DBUS_TYPE_UINT32_AS_STRING + DBUS_TYPE_BYTE_AS_STRING + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_DOUBLE_AS_STRING + DBUS_STRUCT_BEGIN_CHAR_AS_STRING + DBUS_TYPE_BYTE_AS_STRING + DBUS_STRUCT_END_CHAR_AS_STRING + DBUS_STRUCT_END_CHAR_AS_STRING; + _dbus_assert (dbus_signature_validate (sig, NULL)); + dbus_signature_iter_init (&iter, sig); + _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_UINT16); + boolres = dbus_signature_iter_next (&iter); + _dbus_assert (boolres); + _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_STRUCT); + dbus_signature_iter_recurse (&iter, &subiter); + _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_UINT32); + boolres = dbus_signature_iter_next (&subiter); + _dbus_assert (boolres); + _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_BYTE); + boolres = dbus_signature_iter_next (&subiter); + _dbus_assert (boolres); + _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_ARRAY); + _dbus_assert (dbus_signature_iter_get_element_type (&subiter) == DBUS_TYPE_ARRAY); + + dbus_signature_iter_recurse (&subiter, &subsubiter); + _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_ARRAY); + _dbus_assert (dbus_signature_iter_get_element_type (&subsubiter) == DBUS_TYPE_DOUBLE); + + dbus_signature_iter_recurse (&subsubiter, &subsubsubiter); + _dbus_assert (dbus_signature_iter_get_current_type (&subsubsubiter) == DBUS_TYPE_DOUBLE); + boolres = dbus_signature_iter_next (&subiter); + _dbus_assert (boolres); + _dbus_assert (dbus_signature_iter_get_current_type (&subiter) == DBUS_TYPE_STRUCT); + dbus_signature_iter_recurse (&subiter, &subsubiter); + _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_BYTE); + + sig = DBUS_TYPE_ARRAY_AS_STRING + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_INT16_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING; + _dbus_assert (dbus_signature_validate (sig, NULL)); + _dbus_assert (!dbus_signature_validate_single (sig, NULL)); + dbus_signature_iter_init (&iter, sig); + _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_ARRAY); + _dbus_assert (dbus_signature_iter_get_element_type (&iter) == DBUS_TYPE_DICT_ENTRY); + + dbus_signature_iter_recurse (&iter, &subiter); + dbus_signature_iter_recurse (&subiter, &subsubiter); + _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_INT16); + boolres = dbus_signature_iter_next (&subsubiter); + _dbus_assert (boolres); + _dbus_assert (dbus_signature_iter_get_current_type (&subsubiter) == DBUS_TYPE_STRING); + boolres = dbus_signature_iter_next (&subsubiter); + _dbus_assert (!boolres); + + boolres = dbus_signature_iter_next (&iter); + _dbus_assert (boolres); + _dbus_assert (dbus_signature_iter_get_current_type (&iter) == DBUS_TYPE_VARIANT); + boolres = dbus_signature_iter_next (&iter); + _dbus_assert (!boolres); + + sig = DBUS_TYPE_DICT_ENTRY_AS_STRING; + _dbus_assert (!dbus_signature_validate (sig, NULL)); + + sig = DBUS_TYPE_ARRAY_AS_STRING; + _dbus_assert (!dbus_signature_validate (sig, NULL)); + + sig = DBUS_TYPE_UINT32_AS_STRING + DBUS_TYPE_ARRAY_AS_STRING; + _dbus_assert (!dbus_signature_validate (sig, NULL)); + + sig = DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_DICT_ENTRY_AS_STRING; + _dbus_assert (!dbus_signature_validate (sig, NULL)); + + sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING; + _dbus_assert (!dbus_signature_validate (sig, NULL)); + + sig = DBUS_DICT_ENTRY_END_CHAR_AS_STRING; + _dbus_assert (!dbus_signature_validate (sig, NULL)); + + sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_INT32_AS_STRING; + _dbus_assert (!dbus_signature_validate (sig, NULL)); + + sig = DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_INT32_AS_STRING + DBUS_TYPE_STRING_AS_STRING; + _dbus_assert (!dbus_signature_validate (sig, NULL)); + + sig = DBUS_STRUCT_END_CHAR_AS_STRING + DBUS_STRUCT_BEGIN_CHAR_AS_STRING; + _dbus_assert (!dbus_signature_validate (sig, NULL)); + + sig = DBUS_STRUCT_BEGIN_CHAR_AS_STRING + DBUS_TYPE_BOOLEAN_AS_STRING; + _dbus_assert (!dbus_signature_validate (sig, NULL)); + return TRUE; +#if 0 + oom: + _dbus_assert_not_reached ("out of memory"); + return FALSE; +#endif +} + +#endif + diff --git a/dbus/dbus-signature.h b/dbus/dbus-signature.h new file mode 100644 index 00000000..ef3c6f99 --- /dev/null +++ b/dbus/dbus-signature.h @@ -0,0 +1,81 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-signatures.h utility functions for D-Bus types + * + * Copyright (C) 2005 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_SIGNATURES_H +#define DBUS_SIGNATURES_H + +#include +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusSignature + * @{ + */ + +/** + * DBusSignatureIter struct; contains no public fields + */ +typedef struct +{ + void *dummy1; /**< Don't use this */ + void *dummy2; /**< Don't use this */ + dbus_uint32_t dummy8; /**< Don't use this */ + int dummy12; /**< Don't use this */ + int dummy17; /**< Don't use this */ +} DBusSignatureIter; + +void dbus_signature_iter_init (DBusSignatureIter *iter, + const char *signature); + +int dbus_signature_iter_get_current_type (const DBusSignatureIter *iter); + +char * dbus_signature_iter_get_signature (const DBusSignatureIter *iter); + +int dbus_signature_iter_get_element_type (const DBusSignatureIter *iter); + +dbus_bool_t dbus_signature_iter_next (DBusSignatureIter *iter); + +void dbus_signature_iter_recurse (const DBusSignatureIter *iter, + DBusSignatureIter *subiter); + +dbus_bool_t dbus_signature_validate (const char *signature, + DBusError *error); + +dbus_bool_t dbus_signature_validate_single (const char *signature, + DBusError *error); + +dbus_bool_t dbus_type_is_basic (int typecode); +dbus_bool_t dbus_type_is_container (int typecode); +dbus_bool_t dbus_type_is_fixed (int typecode); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_SIGNATURE_H */ diff --git a/dbus/dbus-spawn.c b/dbus/dbus-spawn.c new file mode 100644 index 00000000..91054154 --- /dev/null +++ b/dbus/dbus-spawn.c @@ -0,0 +1,1457 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-spawn.c Wrapper around fork/exec + * + * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-spawn.h" +#include "dbus-sysdeps-unix.h" +#include "dbus-internals.h" +#include "dbus-test.h" +#include "dbus-protocol.h" + +#include +#include +#include +#include +#include +#ifdef HAVE_ERRNO_H +#include +#endif + +extern char **environ; + +/** + * @addtogroup DBusInternalsUtils + * @{ + */ + +/* + * I'm pretty sure this whole spawn file could be made simpler, + * if you thought about it a bit. + */ + +/** + * Enumeration for status of a read() + */ +typedef enum +{ + READ_STATUS_OK, /**< Read succeeded */ + READ_STATUS_ERROR, /**< Some kind of error */ + READ_STATUS_EOF /**< EOF returned */ +} ReadStatus; + +static ReadStatus +read_ints (int fd, + int *buf, + int n_ints_in_buf, + int *n_ints_read, + DBusError *error) +{ + size_t bytes = 0; + ReadStatus retval; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + retval = READ_STATUS_OK; + + while (TRUE) + { + ssize_t chunk; + size_t to_read; + + to_read = sizeof (int) * n_ints_in_buf - bytes; + + if (to_read == 0) + break; + + again: + + chunk = read (fd, + ((char*)buf) + bytes, + to_read); + + if (chunk < 0 && errno == EINTR) + goto again; + + if (chunk < 0) + { + dbus_set_error (error, + DBUS_ERROR_SPAWN_FAILED, + "Failed to read from child pipe (%s)", + _dbus_strerror (errno)); + + retval = READ_STATUS_ERROR; + break; + } + else if (chunk == 0) + { + retval = READ_STATUS_EOF; + break; /* EOF */ + } + else /* chunk > 0 */ + bytes += chunk; + } + + *n_ints_read = (int)(bytes / sizeof(int)); + + return retval; +} + +static ReadStatus +read_pid (int fd, + pid_t *buf, + DBusError *error) +{ + size_t bytes = 0; + ReadStatus retval; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + retval = READ_STATUS_OK; + + while (TRUE) + { + ssize_t chunk; + size_t to_read; + + to_read = sizeof (pid_t) - bytes; + + if (to_read == 0) + break; + + again: + + chunk = read (fd, + ((char*)buf) + bytes, + to_read); + if (chunk < 0 && errno == EINTR) + goto again; + + if (chunk < 0) + { + dbus_set_error (error, + DBUS_ERROR_SPAWN_FAILED, + "Failed to read from child pipe (%s)", + _dbus_strerror (errno)); + + retval = READ_STATUS_ERROR; + break; + } + else if (chunk == 0) + { + retval = READ_STATUS_EOF; + break; /* EOF */ + } + else /* chunk > 0 */ + bytes += chunk; + } + + return retval; +} + +/* The implementation uses an intermediate child between the main process + * and the grandchild. The grandchild is our spawned process. The intermediate + * child is a babysitter process; it keeps track of when the grandchild + * exits/crashes, and reaps the grandchild. + */ + +/* Messages from children to parents */ +enum +{ + CHILD_EXITED, /* This message is followed by the exit status int */ + CHILD_FORK_FAILED, /* Followed by errno */ + CHILD_EXEC_FAILED, /* Followed by errno */ + CHILD_PID /* Followed by pid_t */ +}; + +/** + * Babysitter implementation details + */ +struct DBusBabysitter +{ + int refcount; /**< Reference count */ + + char *executable; /**< executable name to use in error messages */ + + int socket_to_babysitter; /**< Connection to the babysitter process */ + int error_pipe_from_child; /**< Connection to the process that does the exec() */ + + pid_t sitter_pid; /**< PID Of the babysitter */ + pid_t grandchild_pid; /**< PID of the grandchild */ + + DBusWatchList *watches; /**< Watches */ + + DBusWatch *error_watch; /**< Error pipe watch */ + DBusWatch *sitter_watch; /**< Sitter pipe watch */ + + int errnum; /**< Error number */ + int status; /**< Exit status code */ + unsigned int have_child_status : 1; /**< True if child status has been reaped */ + unsigned int have_fork_errnum : 1; /**< True if we have an error code from fork() */ + unsigned int have_exec_errnum : 1; /**< True if we have an error code from exec() */ +}; + +static DBusBabysitter* +_dbus_babysitter_new (void) +{ + DBusBabysitter *sitter; + + sitter = dbus_new0 (DBusBabysitter, 1); + if (sitter == NULL) + return NULL; + + sitter->refcount = 1; + + sitter->socket_to_babysitter = -1; + sitter->error_pipe_from_child = -1; + + sitter->sitter_pid = -1; + sitter->grandchild_pid = -1; + + sitter->watches = _dbus_watch_list_new (); + if (sitter->watches == NULL) + goto failed; + + return sitter; + + failed: + _dbus_babysitter_unref (sitter); + return NULL; +} + +/** + * Increment the reference count on the babysitter object. + * + * @param sitter the babysitter + * @returns the babysitter + */ +DBusBabysitter * +_dbus_babysitter_ref (DBusBabysitter *sitter) +{ + _dbus_assert (sitter != NULL); + _dbus_assert (sitter->refcount > 0); + + sitter->refcount += 1; + + return sitter; +} + +/** + * Decrement the reference count on the babysitter object. + * When the reference count of the babysitter object reaches + * zero, the babysitter is killed and the child that was being + * babysat gets emancipated. + * + * @param sitter the babysitter + */ +void +_dbus_babysitter_unref (DBusBabysitter *sitter) +{ + _dbus_assert (sitter != NULL); + _dbus_assert (sitter->refcount > 0); + + sitter->refcount -= 1; + if (sitter->refcount == 0) + { + if (sitter->socket_to_babysitter >= 0) + { + /* If we haven't forked other babysitters + * since this babysitter and socket were + * created then this close will cause the + * babysitter to wake up from poll with + * a hangup and then the babysitter will + * quit itself. + */ + _dbus_close_socket (sitter->socket_to_babysitter, NULL); + sitter->socket_to_babysitter = -1; + } + + if (sitter->error_pipe_from_child >= 0) + { + _dbus_close_socket (sitter->error_pipe_from_child, NULL); + sitter->error_pipe_from_child = -1; + } + + if (sitter->sitter_pid > 0) + { + int status; + int ret; + + /* It's possible the babysitter died on its own above + * from the close, or was killed randomly + * by some other process, so first try to reap it + */ + ret = waitpid (sitter->sitter_pid, &status, WNOHANG); + + /* If we couldn't reap the child then kill it, and + * try again + */ + if (ret == 0) + kill (sitter->sitter_pid, SIGKILL); + + again: + if (ret == 0) + ret = waitpid (sitter->sitter_pid, &status, 0); + + if (ret < 0) + { + if (errno == EINTR) + goto again; + else if (errno == ECHILD) + _dbus_warn ("Babysitter process not available to be reaped; should not happen\n"); + else + _dbus_warn ("Unexpected error %d in waitpid() for babysitter: %s\n", + errno, _dbus_strerror (errno)); + } + else + { + _dbus_verbose ("Reaped %ld, waiting for babysitter %ld\n", + (long) ret, (long) sitter->sitter_pid); + + if (WIFEXITED (sitter->status)) + _dbus_verbose ("Babysitter exited with status %d\n", + WEXITSTATUS (sitter->status)); + else if (WIFSIGNALED (sitter->status)) + _dbus_verbose ("Babysitter received signal %d\n", + WTERMSIG (sitter->status)); + else + _dbus_verbose ("Babysitter exited abnormally\n"); + } + + sitter->sitter_pid = -1; + } + + if (sitter->error_watch) + { + _dbus_watch_invalidate (sitter->error_watch); + _dbus_watch_unref (sitter->error_watch); + sitter->error_watch = NULL; + } + + if (sitter->sitter_watch) + { + _dbus_watch_invalidate (sitter->sitter_watch); + _dbus_watch_unref (sitter->sitter_watch); + sitter->sitter_watch = NULL; + } + + if (sitter->watches) + _dbus_watch_list_free (sitter->watches); + + dbus_free (sitter->executable); + + dbus_free (sitter); + } +} + +static ReadStatus +read_data (DBusBabysitter *sitter, + int fd) +{ + int what; + int got; + DBusError error = DBUS_ERROR_INIT; + ReadStatus r; + + r = read_ints (fd, &what, 1, &got, &error); + + switch (r) + { + case READ_STATUS_ERROR: + _dbus_warn ("Failed to read data from fd %d: %s\n", fd, error.message); + dbus_error_free (&error); + return r; + + case READ_STATUS_EOF: + return r; + + case READ_STATUS_OK: + break; + } + + if (got == 1) + { + switch (what) + { + case CHILD_EXITED: + case CHILD_FORK_FAILED: + case CHILD_EXEC_FAILED: + { + int arg; + + r = read_ints (fd, &arg, 1, &got, &error); + + switch (r) + { + case READ_STATUS_ERROR: + _dbus_warn ("Failed to read arg from fd %d: %s\n", fd, error.message); + dbus_error_free (&error); + return r; + case READ_STATUS_EOF: + return r; + case READ_STATUS_OK: + break; + } + + if (got == 1) + { + if (what == CHILD_EXITED) + { + sitter->have_child_status = TRUE; + sitter->status = arg; + sitter->errnum = 0; + _dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n", + WIFEXITED (sitter->status), WIFSIGNALED (sitter->status), + WEXITSTATUS (sitter->status), WTERMSIG (sitter->status)); + } + else if (what == CHILD_FORK_FAILED) + { + sitter->have_fork_errnum = TRUE; + sitter->errnum = arg; + _dbus_verbose ("recorded fork errnum %d\n", sitter->errnum); + } + else if (what == CHILD_EXEC_FAILED) + { + sitter->have_exec_errnum = TRUE; + sitter->errnum = arg; + _dbus_verbose ("recorded exec errnum %d\n", sitter->errnum); + } + } + } + break; + case CHILD_PID: + { + pid_t pid = -1; + + r = read_pid (fd, &pid, &error); + + switch (r) + { + case READ_STATUS_ERROR: + _dbus_warn ("Failed to read PID from fd %d: %s\n", fd, error.message); + dbus_error_free (&error); + return r; + case READ_STATUS_EOF: + return r; + case READ_STATUS_OK: + break; + } + + sitter->grandchild_pid = pid; + + _dbus_verbose ("recorded grandchild pid %d\n", sitter->grandchild_pid); + } + break; + default: + _dbus_warn ("Unknown message received from babysitter process\n"); + break; + } + } + + return r; +} + +static void +close_socket_to_babysitter (DBusBabysitter *sitter) +{ + _dbus_verbose ("Closing babysitter\n"); + _dbus_close_socket (sitter->socket_to_babysitter, NULL); + sitter->socket_to_babysitter = -1; +} + +static void +close_error_pipe_from_child (DBusBabysitter *sitter) +{ + _dbus_verbose ("Closing child error\n"); + _dbus_close_socket (sitter->error_pipe_from_child, NULL); + sitter->error_pipe_from_child = -1; +} + +static void +handle_babysitter_socket (DBusBabysitter *sitter, + int revents) +{ + /* Even if we have POLLHUP, we want to keep reading + * data until POLLIN goes away; so this function only + * looks at HUP/ERR if no IN is set. + */ + if (revents & _DBUS_POLLIN) + { + _dbus_verbose ("Reading data from babysitter\n"); + if (read_data (sitter, sitter->socket_to_babysitter) != READ_STATUS_OK) + close_socket_to_babysitter (sitter); + } + else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP)) + { + close_socket_to_babysitter (sitter); + } +} + +static void +handle_error_pipe (DBusBabysitter *sitter, + int revents) +{ + if (revents & _DBUS_POLLIN) + { + _dbus_verbose ("Reading data from child error\n"); + if (read_data (sitter, sitter->error_pipe_from_child) != READ_STATUS_OK) + close_error_pipe_from_child (sitter); + } + else if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP)) + { + close_error_pipe_from_child (sitter); + } +} + +/* returns whether there were any poll events handled */ +static dbus_bool_t +babysitter_iteration (DBusBabysitter *sitter, + dbus_bool_t block) +{ + DBusPollFD fds[2]; + int i; + dbus_bool_t descriptors_ready; + + descriptors_ready = FALSE; + + i = 0; + + if (sitter->error_pipe_from_child >= 0) + { + fds[i].fd = sitter->error_pipe_from_child; + fds[i].events = _DBUS_POLLIN; + fds[i].revents = 0; + ++i; + } + + if (sitter->socket_to_babysitter >= 0) + { + fds[i].fd = sitter->socket_to_babysitter; + fds[i].events = _DBUS_POLLIN; + fds[i].revents = 0; + ++i; + } + + if (i > 0) + { + int ret; + + do + { + ret = _dbus_poll (fds, i, 0); + } + while (ret < 0 && errno == EINTR); + + if (ret == 0 && block) + { + do + { + ret = _dbus_poll (fds, i, -1); + } + while (ret < 0 && errno == EINTR); + } + + if (ret > 0) + { + descriptors_ready = TRUE; + + while (i > 0) + { + --i; + if (fds[i].fd == sitter->error_pipe_from_child) + handle_error_pipe (sitter, fds[i].revents); + else if (fds[i].fd == sitter->socket_to_babysitter) + handle_babysitter_socket (sitter, fds[i].revents); + } + } + } + + return descriptors_ready; +} + +/** + * Macro returns #TRUE if the babysitter still has live sockets open to the + * babysitter child or the grandchild. + */ +#define LIVE_CHILDREN(sitter) ((sitter)->socket_to_babysitter >= 0 || (sitter)->error_pipe_from_child >= 0) + +/** + * Blocks until the babysitter process gives us the PID of the spawned grandchild, + * then kills the spawned grandchild. + * + * @param sitter the babysitter object + */ +void +_dbus_babysitter_kill_child (DBusBabysitter *sitter) +{ + /* be sure we have the PID of the child */ + while (LIVE_CHILDREN (sitter) && + sitter->grandchild_pid == -1) + babysitter_iteration (sitter, TRUE); + + _dbus_verbose ("Got child PID %ld for killing\n", + (long) sitter->grandchild_pid); + + if (sitter->grandchild_pid == -1) + return; /* child is already dead, or we're so hosed we'll never recover */ + + kill (sitter->grandchild_pid, SIGKILL); +} + +/** + * Checks whether the child has exited, without blocking. + * + * @param sitter the babysitter + */ +dbus_bool_t +_dbus_babysitter_get_child_exited (DBusBabysitter *sitter) +{ + + /* Be sure we're up-to-date */ + while (LIVE_CHILDREN (sitter) && + babysitter_iteration (sitter, FALSE)) + ; + + /* We will have exited the babysitter when the child has exited */ + return sitter->socket_to_babysitter < 0; +} + +/** + * Gets the exit status of the child. We do this so implementation specific + * detail is not cluttering up dbus, for example the system launcher code. + * This can only be called if the child has exited, i.e. call + * _dbus_babysitter_get_child_exited(). It returns FALSE if the child + * did not return a status code, e.g. because the child was signaled + * or we failed to ever launch the child in the first place. + * + * @param sitter the babysitter + * @param status the returned status code + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter, + int *status) +{ + if (!_dbus_babysitter_get_child_exited (sitter)) + _dbus_assert_not_reached ("Child has not exited"); + + if (!sitter->have_child_status || + !(WIFEXITED (sitter->status))) + return FALSE; + + *status = WEXITSTATUS (sitter->status); + return TRUE; +} + +/** + * Sets the #DBusError with an explanation of why the spawned + * child process exited (on a signal, or whatever). If + * the child process has not exited, does nothing (error + * will remain unset). + * + * @param sitter the babysitter + * @param error an error to fill in + */ +void +_dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter, + DBusError *error) +{ + if (!_dbus_babysitter_get_child_exited (sitter)) + return; + + /* Note that if exec fails, we will also get a child status + * from the babysitter saying the child exited, + * so we need to give priority to the exec error + */ + if (sitter->have_exec_errnum) + { + dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, + "Failed to execute program %s: %s", + sitter->executable, _dbus_strerror (sitter->errnum)); + } + else if (sitter->have_fork_errnum) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "Failed to fork a new process %s: %s", + sitter->executable, _dbus_strerror (sitter->errnum)); + } + else if (sitter->have_child_status) + { + if (WIFEXITED (sitter->status)) + dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED, + "Process %s exited with status %d", + sitter->executable, WEXITSTATUS (sitter->status)); + else if (WIFSIGNALED (sitter->status)) + dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_SIGNALED, + "Process %s received signal %d", + sitter->executable, WTERMSIG (sitter->status)); + else + dbus_set_error (error, DBUS_ERROR_FAILED, + "Process %s exited abnormally", + sitter->executable); + } + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Process %s exited, reason unknown", + sitter->executable); + } +} + +/** + * Sets watch functions to notify us when the + * babysitter object needs to read/write file descriptors. + * + * @param sitter the babysitter + * @param add_function function to begin monitoring a new descriptor. + * @param remove_function function to stop monitoring a descriptor. + * @param toggled_function function to notify when the watch is enabled/disabled + * @param data data to pass to add_function and remove_function. + * @param free_data_function function to be called to free the data. + * @returns #FALSE on failure (no memory) + */ +dbus_bool_t +_dbus_babysitter_set_watch_functions (DBusBabysitter *sitter, + DBusAddWatchFunction add_function, + DBusRemoveWatchFunction remove_function, + DBusWatchToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function) +{ + return _dbus_watch_list_set_functions (sitter->watches, + add_function, + remove_function, + toggled_function, + data, + free_data_function); +} + +static dbus_bool_t +handle_watch (DBusWatch *watch, + unsigned int condition, + void *data) +{ + DBusBabysitter *sitter = data; + int revents; + int fd; + + revents = 0; + if (condition & DBUS_WATCH_READABLE) + revents |= _DBUS_POLLIN; + if (condition & DBUS_WATCH_ERROR) + revents |= _DBUS_POLLERR; + if (condition & DBUS_WATCH_HANGUP) + revents |= _DBUS_POLLHUP; + + fd = dbus_watch_get_socket (watch); + + if (fd == sitter->error_pipe_from_child) + handle_error_pipe (sitter, revents); + else if (fd == sitter->socket_to_babysitter) + handle_babysitter_socket (sitter, revents); + + while (LIVE_CHILDREN (sitter) && + babysitter_iteration (sitter, FALSE)) + ; + + return TRUE; +} + +/** Helps remember which end of the pipe is which */ +#define READ_END 0 +/** Helps remember which end of the pipe is which */ +#define WRITE_END 1 + + +/* Avoids a danger in threaded situations (calling close() + * on a file descriptor twice, and another thread has + * re-opened it since the first close) + */ +static int +close_and_invalidate (int *fd) +{ + int ret; + + if (*fd < 0) + return -1; + else + { + ret = _dbus_close_socket (*fd, NULL); + *fd = -1; + } + + return ret; +} + +static dbus_bool_t +make_pipe (int p[2], + DBusError *error) +{ + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (pipe (p) < 0) + { + dbus_set_error (error, + DBUS_ERROR_SPAWN_FAILED, + "Failed to create pipe for communicating with child process (%s)", + _dbus_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +static void +do_write (int fd, const void *buf, size_t count) +{ + size_t bytes_written; + int ret; + + bytes_written = 0; + + again: + + ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written); + + if (ret < 0) + { + if (errno == EINTR) + goto again; + else + { + _dbus_warn ("Failed to write data to pipe!\n"); + exit (1); /* give up, we suck */ + } + } + else + bytes_written += ret; + + if (bytes_written < count) + goto again; +} + +static void +write_err_and_exit (int fd, int msg) +{ + int en = errno; + + do_write (fd, &msg, sizeof (msg)); + do_write (fd, &en, sizeof (en)); + + exit (1); +} + +static void +write_pid (int fd, pid_t pid) +{ + int msg = CHILD_PID; + + do_write (fd, &msg, sizeof (msg)); + do_write (fd, &pid, sizeof (pid)); +} + +static void +write_status_and_exit (int fd, int status) +{ + int msg = CHILD_EXITED; + + do_write (fd, &msg, sizeof (msg)); + do_write (fd, &status, sizeof (status)); + + exit (0); +} + +static void +do_exec (int child_err_report_fd, + char **argv, + char **envp, + DBusSpawnChildSetupFunc child_setup, + void *user_data) +{ +#ifdef DBUS_BUILD_TESTS + int i, max_open; +#endif + + _dbus_verbose_reset (); + _dbus_verbose ("Child process has PID " DBUS_PID_FORMAT "\n", + _dbus_getpid ()); + + if (child_setup) + (* child_setup) (user_data); + +#ifdef DBUS_BUILD_TESTS + max_open = sysconf (_SC_OPEN_MAX); + + for (i = 3; i < max_open; i++) + { + int retval; + + if (i == child_err_report_fd) + continue; + + retval = fcntl (i, F_GETFD); + + if (retval != -1 && !(retval & FD_CLOEXEC)) + _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i); + } +#endif + + if (envp == NULL) + { + _dbus_assert (environ != NULL); + + envp = environ; + } + + execve (argv[0], argv, envp); + + /* Exec failed */ + write_err_and_exit (child_err_report_fd, + CHILD_EXEC_FAILED); +} + +static void +check_babysit_events (pid_t grandchild_pid, + int parent_pipe, + int revents) +{ + pid_t ret; + int status; + + do + { + ret = waitpid (grandchild_pid, &status, WNOHANG); + /* The man page says EINTR can't happen with WNOHANG, + * but there are reports of it (maybe only with valgrind?) + */ + } + while (ret < 0 && errno == EINTR); + + if (ret == 0) + { + _dbus_verbose ("no child exited\n"); + + ; /* no child exited */ + } + else if (ret < 0) + { + /* This isn't supposed to happen. */ + _dbus_warn ("unexpected waitpid() failure in check_babysit_events(): %s\n", + _dbus_strerror (errno)); + exit (1); + } + else if (ret == grandchild_pid) + { + /* Child exited */ + _dbus_verbose ("reaped child pid %ld\n", (long) ret); + + write_status_and_exit (parent_pipe, status); + } + else + { + _dbus_warn ("waitpid() reaped pid %d that we've never heard of\n", + (int) ret); + exit (1); + } + + if (revents & _DBUS_POLLIN) + { + _dbus_verbose ("babysitter got POLLIN from parent pipe\n"); + } + + if (revents & (_DBUS_POLLERR | _DBUS_POLLHUP)) + { + /* Parent is gone, so we just exit */ + _dbus_verbose ("babysitter got POLLERR or POLLHUP from parent\n"); + exit (0); + } +} + +static int babysit_sigchld_pipe = -1; + +static void +babysit_signal_handler (int signo) +{ + char b = '\0'; + again: + if (write (babysit_sigchld_pipe, &b, 1) <= 0) + if (errno == EINTR) + goto again; +} + +static void +babysit (pid_t grandchild_pid, + int parent_pipe) +{ + int sigchld_pipe[2]; + + /* We don't exec, so we keep parent state, such as the pid that + * _dbus_verbose() uses. Reset the pid here. + */ + _dbus_verbose_reset (); + + /* I thought SIGCHLD would just wake up the poll, but + * that didn't seem to work, so added this pipe. + * Probably the pipe is more likely to work on busted + * operating systems anyhow. + */ + if (pipe (sigchld_pipe) < 0) + { + _dbus_warn ("Not enough file descriptors to create pipe in babysitter process\n"); + exit (1); + } + + babysit_sigchld_pipe = sigchld_pipe[WRITE_END]; + + _dbus_set_signal_handler (SIGCHLD, babysit_signal_handler); + + write_pid (parent_pipe, grandchild_pid); + + check_babysit_events (grandchild_pid, parent_pipe, 0); + + while (TRUE) + { + DBusPollFD pfds[2]; + + pfds[0].fd = parent_pipe; + pfds[0].events = _DBUS_POLLIN; + pfds[0].revents = 0; + + pfds[1].fd = sigchld_pipe[READ_END]; + pfds[1].events = _DBUS_POLLIN; + pfds[1].revents = 0; + + if (_dbus_poll (pfds, _DBUS_N_ELEMENTS (pfds), -1) < 0 && errno != EINTR) + { + _dbus_warn ("_dbus_poll() error: %s\n", strerror (errno)); + exit (1); + } + + if (pfds[0].revents != 0) + { + check_babysit_events (grandchild_pid, parent_pipe, pfds[0].revents); + } + else if (pfds[1].revents & _DBUS_POLLIN) + { + char b; + read (sigchld_pipe[READ_END], &b, 1); + /* do waitpid check */ + check_babysit_events (grandchild_pid, parent_pipe, 0); + } + } + + exit (1); +} + +/** + * Spawns a new process. The executable name and argv[0] + * are the same, both are provided in argv[0]. The child_setup + * function is passed the given user_data and is run in the child + * just before calling exec(). + * + * Also creates a "babysitter" which tracks the status of the + * child process, advising the parent if the child exits. + * If the spawn fails, no babysitter is created. + * If sitter_p is #NULL, no babysitter is kept. + * + * @param sitter_p return location for babysitter or #NULL + * @param argv the executable and arguments + * @param env the environment (not used on unix yet) + * @param child_setup function to call in child pre-exec() + * @param user_data user data for setup function + * @param error error object to be filled in if function fails + * @returns #TRUE on success, #FALSE if error is filled in + */ +dbus_bool_t +_dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, + char **argv, + char **env, + DBusSpawnChildSetupFunc child_setup, + void *user_data, + DBusError *error) +{ + DBusBabysitter *sitter; + int child_err_report_pipe[2] = { -1, -1 }; + int babysitter_pipe[2] = { -1, -1 }; + pid_t pid; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (sitter_p != NULL) + *sitter_p = NULL; + + sitter = NULL; + + sitter = _dbus_babysitter_new (); + if (sitter == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return FALSE; + } + + sitter->executable = _dbus_strdup (argv[0]); + if (sitter->executable == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto cleanup_and_fail; + } + + if (!make_pipe (child_err_report_pipe, error)) + goto cleanup_and_fail; + + _dbus_fd_set_close_on_exec (child_err_report_pipe[READ_END]); + _dbus_fd_set_close_on_exec (child_err_report_pipe[WRITE_END]); + + if (!_dbus_full_duplex_pipe (&babysitter_pipe[0], &babysitter_pipe[1], TRUE, error)) + goto cleanup_and_fail; + + _dbus_fd_set_close_on_exec (babysitter_pipe[0]); + _dbus_fd_set_close_on_exec (babysitter_pipe[1]); + + /* Setting up the babysitter is only useful in the parent, + * but we don't want to run out of memory and fail + * after we've already forked, since then we'd leak + * child processes everywhere. + */ + sitter->error_watch = _dbus_watch_new (child_err_report_pipe[READ_END], + DBUS_WATCH_READABLE, + TRUE, handle_watch, sitter, NULL); + if (sitter->error_watch == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto cleanup_and_fail; + } + + if (!_dbus_watch_list_add_watch (sitter->watches, sitter->error_watch)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto cleanup_and_fail; + } + + sitter->sitter_watch = _dbus_watch_new (babysitter_pipe[0], + DBUS_WATCH_READABLE, + TRUE, handle_watch, sitter, NULL); + if (sitter->sitter_watch == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto cleanup_and_fail; + } + + if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto cleanup_and_fail; + } + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + pid = fork (); + + if (pid < 0) + { + dbus_set_error (error, + DBUS_ERROR_SPAWN_FORK_FAILED, + "Failed to fork (%s)", + _dbus_strerror (errno)); + goto cleanup_and_fail; + } + else if (pid == 0) + { + /* Immediate child, this is the babysitter process. */ + int grandchild_pid; + + /* Be sure we crash if the parent exits + * and we write to the err_report_pipe + */ + signal (SIGPIPE, SIG_DFL); + + /* Close the parent's end of the pipes. */ + close_and_invalidate (&child_err_report_pipe[READ_END]); + close_and_invalidate (&babysitter_pipe[0]); + + /* Create the child that will exec () */ + grandchild_pid = fork (); + + if (grandchild_pid < 0) + { + write_err_and_exit (babysitter_pipe[1], + CHILD_FORK_FAILED); + _dbus_assert_not_reached ("Got to code after write_err_and_exit()"); + } + else if (grandchild_pid == 0) + { + do_exec (child_err_report_pipe[WRITE_END], + argv, + env, + child_setup, user_data); + _dbus_assert_not_reached ("Got to code after exec() - should have exited on error"); + } + else + { + babysit (grandchild_pid, babysitter_pipe[1]); + _dbus_assert_not_reached ("Got to code after babysit()"); + } + } + else + { + /* Close the uncared-about ends of the pipes */ + close_and_invalidate (&child_err_report_pipe[WRITE_END]); + close_and_invalidate (&babysitter_pipe[1]); + + sitter->socket_to_babysitter = babysitter_pipe[0]; + babysitter_pipe[0] = -1; + + sitter->error_pipe_from_child = child_err_report_pipe[READ_END]; + child_err_report_pipe[READ_END] = -1; + + sitter->sitter_pid = pid; + + if (sitter_p != NULL) + *sitter_p = sitter; + else + _dbus_babysitter_unref (sitter); + + dbus_free_string_array (env); + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + return TRUE; + } + + cleanup_and_fail: + + _DBUS_ASSERT_ERROR_IS_SET (error); + + close_and_invalidate (&child_err_report_pipe[READ_END]); + close_and_invalidate (&child_err_report_pipe[WRITE_END]); + close_and_invalidate (&babysitter_pipe[0]); + close_and_invalidate (&babysitter_pipe[1]); + + if (sitter != NULL) + _dbus_babysitter_unref (sitter); + + return FALSE; +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS + +static void +_dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter) +{ + while (LIVE_CHILDREN (sitter)) + babysitter_iteration (sitter, TRUE); +} + +static dbus_bool_t +check_spawn_nonexistent (void *data) +{ + char *argv[4] = { NULL, NULL, NULL, NULL }; + DBusBabysitter *sitter = NULL; + DBusError error = DBUS_ERROR_INIT; + + /*** Test launching nonexistent binary */ + + argv[0] = "/this/does/not/exist/32542sdgafgafdg"; + if (_dbus_spawn_async_with_babysitter (&sitter, argv, + NULL, NULL, NULL, + &error)) + { + _dbus_babysitter_block_for_child_exit (sitter); + _dbus_babysitter_set_child_exit_error (sitter, &error); + } + + if (sitter) + _dbus_babysitter_unref (sitter); + + if (!dbus_error_is_set (&error)) + { + _dbus_warn ("Did not get an error launching nonexistent executable\n"); + return FALSE; + } + + if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || + dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED))) + { + _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n", + error.name, error.message); + dbus_error_free (&error); + return FALSE; + } + + dbus_error_free (&error); + + return TRUE; +} + +static dbus_bool_t +check_spawn_segfault (void *data) +{ + char *argv[4] = { NULL, NULL, NULL, NULL }; + DBusBabysitter *sitter = NULL; + DBusError error = DBUS_ERROR_INIT; + + /*** Test launching segfault binary */ + + argv[0] = TEST_SEGFAULT_BINARY; + if (_dbus_spawn_async_with_babysitter (&sitter, argv, + NULL, NULL, NULL, + &error)) + { + _dbus_babysitter_block_for_child_exit (sitter); + _dbus_babysitter_set_child_exit_error (sitter, &error); + } + + if (sitter) + _dbus_babysitter_unref (sitter); + + if (!dbus_error_is_set (&error)) + { + _dbus_warn ("Did not get an error launching segfaulting binary\n"); + return FALSE; + } + + if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || + dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED))) + { + _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n", + error.name, error.message); + dbus_error_free (&error); + return FALSE; + } + + dbus_error_free (&error); + + return TRUE; +} + +static dbus_bool_t +check_spawn_exit (void *data) +{ + char *argv[4] = { NULL, NULL, NULL, NULL }; + DBusBabysitter *sitter = NULL; + DBusError error = DBUS_ERROR_INIT; + + /*** Test launching exit failure binary */ + + argv[0] = TEST_EXIT_BINARY; + if (_dbus_spawn_async_with_babysitter (&sitter, argv, + NULL, NULL, NULL, + &error)) + { + _dbus_babysitter_block_for_child_exit (sitter); + _dbus_babysitter_set_child_exit_error (sitter, &error); + } + + if (sitter) + _dbus_babysitter_unref (sitter); + + if (!dbus_error_is_set (&error)) + { + _dbus_warn ("Did not get an error launching binary that exited with failure code\n"); + return FALSE; + } + + if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || + dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) + { + _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n", + error.name, error.message); + dbus_error_free (&error); + return FALSE; + } + + dbus_error_free (&error); + + return TRUE; +} + +static dbus_bool_t +check_spawn_and_kill (void *data) +{ + char *argv[4] = { NULL, NULL, NULL, NULL }; + DBusBabysitter *sitter = NULL; + DBusError error = DBUS_ERROR_INIT; + + /*** Test launching sleeping binary then killing it */ + + argv[0] = TEST_SLEEP_FOREVER_BINARY; + if (_dbus_spawn_async_with_babysitter (&sitter, argv, + NULL, NULL, NULL, + &error)) + { + _dbus_babysitter_kill_child (sitter); + + _dbus_babysitter_block_for_child_exit (sitter); + + _dbus_babysitter_set_child_exit_error (sitter, &error); + } + + if (sitter) + _dbus_babysitter_unref (sitter); + + if (!dbus_error_is_set (&error)) + { + _dbus_warn ("Did not get an error after killing spawned binary\n"); + return FALSE; + } + + if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) || + dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_SIGNALED))) + { + _dbus_warn ("Not expecting error when killing executable: %s: %s\n", + error.name, error.message); + dbus_error_free (&error); + return FALSE; + } + + dbus_error_free (&error); + + return TRUE; +} + +dbus_bool_t +_dbus_spawn_test (const char *test_data_dir) +{ + if (!_dbus_test_oom_handling ("spawn_nonexistent", + check_spawn_nonexistent, + NULL)) + return FALSE; + + if (!_dbus_test_oom_handling ("spawn_segfault", + check_spawn_segfault, + NULL)) + return FALSE; + + if (!_dbus_test_oom_handling ("spawn_exit", + check_spawn_exit, + NULL)) + return FALSE; + + if (!_dbus_test_oom_handling ("spawn_and_kill", + check_spawn_and_kill, + NULL)) + return FALSE; + + return TRUE; +} +#endif diff --git a/dbus/dbus-spawn.h b/dbus/dbus-spawn.h new file mode 100644 index 00000000..5af54b72 --- /dev/null +++ b/dbus/dbus-spawn.h @@ -0,0 +1,61 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-spawn.h Wrapper around fork/exec + * + * Copyright (C) 2002, 2003 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_SPAWN_H +#define DBUS_SPAWN_H + +#include +#include +#include + +DBUS_BEGIN_DECLS + +typedef void (* DBusSpawnChildSetupFunc) (void *user_data); + +typedef struct DBusBabysitter DBusBabysitter; + +dbus_bool_t _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, + char **argv, + char **env, + DBusSpawnChildSetupFunc child_setup, + void *user_data, + DBusError *error); +DBusBabysitter* _dbus_babysitter_ref (DBusBabysitter *sitter); +void _dbus_babysitter_unref (DBusBabysitter *sitter); +void _dbus_babysitter_kill_child (DBusBabysitter *sitter); +dbus_bool_t _dbus_babysitter_get_child_exited (DBusBabysitter *sitter); +void _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter, + DBusError *error); +dbus_bool_t _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter, + int *status); +dbus_bool_t _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter, + DBusAddWatchFunction add_function, + DBusRemoveWatchFunction remove_function, + DBusWatchToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function); + +DBUS_END_DECLS + +#endif /* DBUS_SPAWN_H */ diff --git a/dbus/dbus-string-private.h b/dbus/dbus-string-private.h new file mode 100644 index 00000000..6687a76f --- /dev/null +++ b/dbus/dbus-string-private.h @@ -0,0 +1,126 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-string-private.h String utility class (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_STRING_PRIVATE_H +#define DBUS_STRING_PRIVATE_H + +#include + +#include +#include + +#ifndef DBUS_CAN_USE_DBUS_STRING_PRIVATE +#error "Don't go including dbus-string-private.h for no good reason" +#endif + +DBUS_BEGIN_DECLS + +/** + * @brief Internals of DBusString. + * + * DBusString internals. DBusString is an opaque objects, it must be + * used via accessor functions. + */ +typedef struct +{ + unsigned char *str; /**< String data, plus nul termination */ + int len; /**< Length without nul */ + int allocated; /**< Allocated size of data */ + int max_length; /**< Max length of this string, without nul byte */ + unsigned int constant : 1; /**< String data is not owned by DBusString */ + unsigned int locked : 1; /**< DBusString has been locked and can't be changed */ + unsigned int invalid : 1; /**< DBusString is invalid (e.g. already freed) */ + unsigned int align_offset : 3; /**< str - align_offset is the actual malloc block */ +} DBusRealString; + + +/** + * @defgroup DBusStringInternals DBusString implementation details + * @ingroup DBusInternals + * @brief DBusString implementation details + * + * The guts of DBusString. + * + * @{ + */ + +/** + * This is the maximum max length (and thus also the maximum length) + * of a DBusString + */ +#define _DBUS_STRING_MAX_MAX_LENGTH (_DBUS_INT32_MAX - _DBUS_STRING_ALLOCATION_PADDING) + +/** + * Checks a bunch of assertions about a string object + * + * @param real the DBusRealString + */ +#define DBUS_GENERIC_STRING_PREAMBLE(real) _dbus_assert ((real) != NULL); _dbus_assert (!(real)->invalid); _dbus_assert ((real)->len >= 0); _dbus_assert ((real)->allocated >= 0); _dbus_assert ((real)->max_length >= 0); _dbus_assert ((real)->len <= ((real)->allocated - _DBUS_STRING_ALLOCATION_PADDING)); _dbus_assert ((real)->len <= (real)->max_length) + +/** + * Checks assertions about a string object that needs to be + * modifiable - may not be locked or const. Also declares + * the "real" variable pointing to DBusRealString. + * @param str the string + */ +#define DBUS_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \ + DBUS_GENERIC_STRING_PREAMBLE (real); \ + _dbus_assert (!(real)->constant); \ + _dbus_assert (!(real)->locked) + +/** + * Checks assertions about a string object that may be locked but + * can't be const. i.e. a string object that we can free. Also + * declares the "real" variable pointing to DBusRealString. + * + * @param str the string + */ +#define DBUS_LOCKED_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \ + DBUS_GENERIC_STRING_PREAMBLE (real); \ + _dbus_assert (!(real)->constant) + +/** + * Checks assertions about a string that may be const or locked. Also + * declares the "real" variable pointing to DBusRealString. + * @param str the string. + */ +#define DBUS_CONST_STRING_PREAMBLE(str) const DBusRealString *real = (DBusRealString*) str; \ + DBUS_GENERIC_STRING_PREAMBLE (real) + +/** + * Checks for ASCII blank byte + * @param c the byte + */ +#define DBUS_IS_ASCII_BLANK(c) ((c) == ' ' || (c) == '\t') + +/** + * Checks for ASCII whitespace byte + * @param c the byte + */ +#define DBUS_IS_ASCII_WHITE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r') + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_STRING_PRIVATE_H */ diff --git a/dbus/dbus-string-util.c b/dbus/dbus-string-util.c new file mode 100644 index 00000000..a3e5213e --- /dev/null +++ b/dbus/dbus-string-util.c @@ -0,0 +1,878 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-string-util.c Would be in dbus-string.c, but not used in libdbus + * + * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + * Copyright (C) 2006 Ralf Habacker + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-string.h" +#define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1 +#include "dbus-string-private.h" + +/** + * @addtogroup DBusString + * @{ + */ + +/** + * Returns whether a string ends with the given suffix + * + * @todo memcmp might make this faster. + * + * @param a the string + * @param c_str the C-style string + * @returns #TRUE if the string ends with the suffix + */ +dbus_bool_t +_dbus_string_ends_with_c_str (const DBusString *a, + const char *c_str) +{ + const unsigned char *ap; + const unsigned char *bp; + const unsigned char *a_end; + unsigned long c_str_len; + const DBusRealString *real_a = (const DBusRealString*) a; + DBUS_GENERIC_STRING_PREAMBLE (real_a); + _dbus_assert (c_str != NULL); + + c_str_len = strlen (c_str); + if (((unsigned long)real_a->len) < c_str_len) + return FALSE; + + ap = real_a->str + (real_a->len - c_str_len); + bp = (const unsigned char*) c_str; + a_end = real_a->str + real_a->len; + while (ap != a_end) + { + if (*ap != *bp) + return FALSE; + + ++ap; + ++bp; + } + + _dbus_assert (*ap == '\0'); + _dbus_assert (*bp == '\0'); + + return TRUE; +} + +/** + * Find the given byte scanning backward from the given start. + * Sets *found to -1 if the byte is not found. + * + * @param str the string + * @param start the place to start scanning (will not find the byte at this point) + * @param byte the byte to find + * @param found return location for where it was found + * @returns #TRUE if found + */ +dbus_bool_t +_dbus_string_find_byte_backward (const DBusString *str, + int start, + unsigned char byte, + int *found) +{ + int i; + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start <= real->len); + _dbus_assert (start >= 0); + _dbus_assert (found != NULL); + + i = start - 1; + while (i >= 0) + { + if (real->str[i] == byte) + break; + + --i; + } + + if (found) + *found = i; + + return i >= 0; +} + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include "dbus-test.h" +#include + +static void +test_max_len (DBusString *str, + int max_len) +{ + if (max_len > 0) + { + if (!_dbus_string_set_length (str, max_len - 1)) + _dbus_assert_not_reached ("setting len to one less than max should have worked"); + } + + if (!_dbus_string_set_length (str, max_len)) + _dbus_assert_not_reached ("setting len to max len should have worked"); + + if (_dbus_string_set_length (str, max_len + 1)) + _dbus_assert_not_reached ("setting len to one more than max len should not have worked"); + + if (!_dbus_string_set_length (str, 0)) + _dbus_assert_not_reached ("setting len to zero should have worked"); +} + +static void +test_hex_roundtrip (const unsigned char *data, + int len) +{ + DBusString orig; + DBusString encoded; + DBusString decoded; + int end; + + if (len < 0) + len = strlen (data); + + if (!_dbus_string_init (&orig)) + _dbus_assert_not_reached ("could not init string"); + + if (!_dbus_string_init (&encoded)) + _dbus_assert_not_reached ("could not init string"); + + if (!_dbus_string_init (&decoded)) + _dbus_assert_not_reached ("could not init string"); + + if (!_dbus_string_append_len (&orig, data, len)) + _dbus_assert_not_reached ("couldn't append orig data"); + + if (!_dbus_string_hex_encode (&orig, 0, &encoded, 0)) + _dbus_assert_not_reached ("could not encode"); + + if (!_dbus_string_hex_decode (&encoded, 0, &end, &decoded, 0)) + _dbus_assert_not_reached ("could not decode"); + + _dbus_assert (_dbus_string_get_length (&encoded) == end); + + if (!_dbus_string_equal (&orig, &decoded)) + { + const char *s; + + printf ("Original string %d bytes encoded %d bytes decoded %d bytes\n", + _dbus_string_get_length (&orig), + _dbus_string_get_length (&encoded), + _dbus_string_get_length (&decoded)); + printf ("Original: %s\n", data); + s = _dbus_string_get_const_data (&decoded); + printf ("Decoded: %s\n", s); + _dbus_assert_not_reached ("original string not the same as string decoded from hex"); + } + + _dbus_string_free (&orig); + _dbus_string_free (&encoded); + _dbus_string_free (&decoded); +} + +typedef void (* TestRoundtripFunc) (const unsigned char *data, + int len); +static void +test_roundtrips (TestRoundtripFunc func) +{ + (* func) ("Hello this is a string\n", -1); + (* func) ("Hello this is a string\n1", -1); + (* func) ("Hello this is a string\n12", -1); + (* func) ("Hello this is a string\n123", -1); + (* func) ("Hello this is a string\n1234", -1); + (* func) ("Hello this is a string\n12345", -1); + (* func) ("", 0); + (* func) ("1", 1); + (* func) ("12", 2); + (* func) ("123", 3); + (* func) ("1234", 4); + (* func) ("12345", 5); + (* func) ("", 1); + (* func) ("1", 2); + (* func) ("12", 3); + (* func) ("123", 4); + (* func) ("1234", 5); + (* func) ("12345", 6); + { + unsigned char buf[512]; + int i; + + i = 0; + while (i < _DBUS_N_ELEMENTS (buf)) + { + buf[i] = i; + ++i; + } + i = 0; + while (i < _DBUS_N_ELEMENTS (buf)) + { + (* func) (buf, i); + ++i; + } + } +} + +#ifdef DBUS_BUILD_TESTS +/* The max length thing is sort of a historical artifact + * from a feature that turned out to be dumb; perhaps + * we should purge it entirely. The problem with + * the feature is that it looks like memory allocation + * failure, but is not a transient or resolvable failure. + */ +static void +set_max_length (DBusString *str, + int max_length) +{ + DBusRealString *real; + + real = (DBusRealString*) str; + + real->max_length = max_length; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * @ingroup DBusStringInternals + * Unit test for DBusString. + * + * @todo Need to write tests for _dbus_string_copy() and + * _dbus_string_move() moving to/from each of start/middle/end of a + * string. Also need tests for _dbus_string_move_len () + * + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_string_test (void) +{ + DBusString str; + DBusString other; + int i, end; + long v; + double d; + int lens[] = { 0, 1, 2, 3, 4, 5, 10, 16, 17, 18, 25, 31, 32, 33, 34, 35, 63, 64, 65, 66, 67, 68, 69, 70, 71, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 }; + char *s; + dbus_unichar_t ch; + + i = 0; + while (i < _DBUS_N_ELEMENTS (lens)) + { + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("failed to init string"); + + set_max_length (&str, lens[i]); + + test_max_len (&str, lens[i]); + _dbus_string_free (&str); + + ++i; + } + + /* Test shortening and setting length */ + i = 0; + while (i < _DBUS_N_ELEMENTS (lens)) + { + int j; + + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("failed to init string"); + + set_max_length (&str, lens[i]); + + if (!_dbus_string_set_length (&str, lens[i])) + _dbus_assert_not_reached ("failed to set string length"); + + j = lens[i]; + while (j > 0) + { + _dbus_assert (_dbus_string_get_length (&str) == j); + if (j > 0) + { + _dbus_string_shorten (&str, 1); + _dbus_assert (_dbus_string_get_length (&str) == (j - 1)); + } + --j; + } + + _dbus_string_free (&str); + + ++i; + } + + /* Test equality */ + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("oom"); + + if (!_dbus_string_append (&str, "Hello World")) + _dbus_assert_not_reached ("oom"); + + _dbus_string_init_const (&other, "H"); + _dbus_assert (_dbus_string_equal_substring (&str, 0, 1, &other, 0)); + _dbus_assert (_dbus_string_equal_substring (&str, 1, 0, &other, 1)); + _dbus_string_init_const (&other, "Hello"); + _dbus_assert (_dbus_string_equal_substring (&str, 0, 5, &other, 0)); + _dbus_assert (_dbus_string_equal_substring (&str, 1, 4, &other, 1)); + _dbus_assert (_dbus_string_equal_substring (&str, 2, 3, &other, 2)); + _dbus_assert (_dbus_string_equal_substring (&str, 3, 2, &other, 3)); + _dbus_assert (_dbus_string_equal_substring (&str, 4, 1, &other, 4)); + _dbus_assert (_dbus_string_equal_substring (&str, 5, 0, &other, 5)); + + _dbus_assert (_dbus_string_equal_substring (&other, 0, 5, &str, 0)); + _dbus_assert (_dbus_string_equal_substring (&other, 1, 4, &str, 1)); + _dbus_assert (_dbus_string_equal_substring (&other, 2, 3, &str, 2)); + _dbus_assert (_dbus_string_equal_substring (&other, 3, 2, &str, 3)); + _dbus_assert (_dbus_string_equal_substring (&other, 4, 1, &str, 4)); + _dbus_assert (_dbus_string_equal_substring (&other, 5, 0, &str, 5)); + + + _dbus_string_init_const (&other, "World"); + _dbus_assert (_dbus_string_equal_substring (&str, 6, 5, &other, 0)); + _dbus_assert (_dbus_string_equal_substring (&str, 7, 4, &other, 1)); + _dbus_assert (_dbus_string_equal_substring (&str, 8, 3, &other, 2)); + _dbus_assert (_dbus_string_equal_substring (&str, 9, 2, &other, 3)); + _dbus_assert (_dbus_string_equal_substring (&str, 10, 1, &other, 4)); + _dbus_assert (_dbus_string_equal_substring (&str, 11, 0, &other, 5)); + + _dbus_assert (_dbus_string_equal_substring (&other, 0, 5, &str, 6)); + _dbus_assert (_dbus_string_equal_substring (&other, 1, 4, &str, 7)); + _dbus_assert (_dbus_string_equal_substring (&other, 2, 3, &str, 8)); + _dbus_assert (_dbus_string_equal_substring (&other, 3, 2, &str, 9)); + _dbus_assert (_dbus_string_equal_substring (&other, 4, 1, &str, 10)); + _dbus_assert (_dbus_string_equal_substring (&other, 5, 0, &str, 11)); + + _dbus_string_free (&str); + + /* Test appending data */ + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("failed to init string"); + + i = 0; + while (i < 10) + { + if (!_dbus_string_append (&str, "a")) + _dbus_assert_not_reached ("failed to append string to string\n"); + + _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1); + + if (!_dbus_string_append_byte (&str, 'b')) + _dbus_assert_not_reached ("failed to append byte to string\n"); + + _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2); + + ++i; + } + + _dbus_string_free (&str); + + /* Check steal_data */ + + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("failed to init string"); + + if (!_dbus_string_append (&str, "Hello World")) + _dbus_assert_not_reached ("could not append to string"); + + i = _dbus_string_get_length (&str); + + if (!_dbus_string_steal_data (&str, &s)) + _dbus_assert_not_reached ("failed to steal data"); + + _dbus_assert (_dbus_string_get_length (&str) == 0); + _dbus_assert (((int)strlen (s)) == i); + + dbus_free (s); + + /* Check move */ + + if (!_dbus_string_append (&str, "Hello World")) + _dbus_assert_not_reached ("could not append to string"); + + i = _dbus_string_get_length (&str); + + if (!_dbus_string_init (&other)) + _dbus_assert_not_reached ("could not init string"); + + if (!_dbus_string_move (&str, 0, &other, 0)) + _dbus_assert_not_reached ("could not move"); + + _dbus_assert (_dbus_string_get_length (&str) == 0); + _dbus_assert (_dbus_string_get_length (&other) == i); + + if (!_dbus_string_append (&str, "Hello World")) + _dbus_assert_not_reached ("could not append to string"); + + if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other))) + _dbus_assert_not_reached ("could not move"); + + _dbus_assert (_dbus_string_get_length (&str) == 0); + _dbus_assert (_dbus_string_get_length (&other) == i * 2); + + if (!_dbus_string_append (&str, "Hello World")) + _dbus_assert_not_reached ("could not append to string"); + + if (!_dbus_string_move (&str, 0, &other, _dbus_string_get_length (&other) / 2)) + _dbus_assert_not_reached ("could not move"); + + _dbus_assert (_dbus_string_get_length (&str) == 0); + _dbus_assert (_dbus_string_get_length (&other) == i * 3); + + _dbus_string_free (&other); + + /* Check copy */ + + if (!_dbus_string_append (&str, "Hello World")) + _dbus_assert_not_reached ("could not append to string"); + + i = _dbus_string_get_length (&str); + + if (!_dbus_string_init (&other)) + _dbus_assert_not_reached ("could not init string"); + + if (!_dbus_string_copy (&str, 0, &other, 0)) + _dbus_assert_not_reached ("could not copy"); + + _dbus_assert (_dbus_string_get_length (&str) == i); + _dbus_assert (_dbus_string_get_length (&other) == i); + + if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other))) + _dbus_assert_not_reached ("could not copy"); + + _dbus_assert (_dbus_string_get_length (&str) == i); + _dbus_assert (_dbus_string_get_length (&other) == i * 2); + _dbus_assert (_dbus_string_equal_c_str (&other, + "Hello WorldHello World")); + + if (!_dbus_string_copy (&str, 0, &other, _dbus_string_get_length (&other) / 2)) + _dbus_assert_not_reached ("could not copy"); + + _dbus_assert (_dbus_string_get_length (&str) == i); + _dbus_assert (_dbus_string_get_length (&other) == i * 3); + _dbus_assert (_dbus_string_equal_c_str (&other, + "Hello WorldHello WorldHello World")); + + _dbus_string_free (&str); + _dbus_string_free (&other); + + /* Check replace */ + + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("failed to init string"); + + if (!_dbus_string_append (&str, "Hello World")) + _dbus_assert_not_reached ("could not append to string"); + + i = _dbus_string_get_length (&str); + + if (!_dbus_string_init (&other)) + _dbus_assert_not_reached ("could not init string"); + + if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str), + &other, 0, _dbus_string_get_length (&other))) + _dbus_assert_not_reached ("could not replace"); + + _dbus_assert (_dbus_string_get_length (&str) == i); + _dbus_assert (_dbus_string_get_length (&other) == i); + _dbus_assert (_dbus_string_equal_c_str (&other, "Hello World")); + + if (!_dbus_string_replace_len (&str, 0, _dbus_string_get_length (&str), + &other, 5, 1)) + _dbus_assert_not_reached ("could not replace center space"); + + _dbus_assert (_dbus_string_get_length (&str) == i); + _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1); + _dbus_assert (_dbus_string_equal_c_str (&other, + "HelloHello WorldWorld")); + + + if (!_dbus_string_replace_len (&str, 1, 1, + &other, + _dbus_string_get_length (&other) - 1, + 1)) + _dbus_assert_not_reached ("could not replace end character"); + + _dbus_assert (_dbus_string_get_length (&str) == i); + _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1); + _dbus_assert (_dbus_string_equal_c_str (&other, + "HelloHello WorldWorle")); + + _dbus_string_free (&str); + _dbus_string_free (&other); + + /* Check append/get unichar */ + + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("failed to init string"); + + ch = 0; + if (!_dbus_string_append_unichar (&str, 0xfffc)) + _dbus_assert_not_reached ("failed to append unichar"); + + _dbus_string_get_unichar (&str, 0, &ch, &i); + + _dbus_assert (ch == 0xfffc); + _dbus_assert (i == _dbus_string_get_length (&str)); + + _dbus_string_free (&str); + + /* Check insert/set/get byte */ + + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("failed to init string"); + + if (!_dbus_string_append (&str, "Hello")) + _dbus_assert_not_reached ("failed to append Hello"); + + _dbus_assert (_dbus_string_get_byte (&str, 0) == 'H'); + _dbus_assert (_dbus_string_get_byte (&str, 1) == 'e'); + _dbus_assert (_dbus_string_get_byte (&str, 2) == 'l'); + _dbus_assert (_dbus_string_get_byte (&str, 3) == 'l'); + _dbus_assert (_dbus_string_get_byte (&str, 4) == 'o'); + + _dbus_string_set_byte (&str, 1, 'q'); + _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q'); + + if (!_dbus_string_insert_bytes (&str, 0, 1, 255)) + _dbus_assert_not_reached ("can't insert byte"); + + if (!_dbus_string_insert_bytes (&str, 2, 4, 'Z')) + _dbus_assert_not_reached ("can't insert byte"); + + if (!_dbus_string_insert_bytes (&str, _dbus_string_get_length (&str), 1, 'W')) + _dbus_assert_not_reached ("can't insert byte"); + + _dbus_assert (_dbus_string_get_byte (&str, 0) == 255); + _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H'); + _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z'); + _dbus_assert (_dbus_string_get_byte (&str, 3) == 'Z'); + _dbus_assert (_dbus_string_get_byte (&str, 4) == 'Z'); + _dbus_assert (_dbus_string_get_byte (&str, 5) == 'Z'); + _dbus_assert (_dbus_string_get_byte (&str, 6) == 'q'); + _dbus_assert (_dbus_string_get_byte (&str, 7) == 'l'); + _dbus_assert (_dbus_string_get_byte (&str, 8) == 'l'); + _dbus_assert (_dbus_string_get_byte (&str, 9) == 'o'); + _dbus_assert (_dbus_string_get_byte (&str, 10) == 'W'); + + _dbus_string_free (&str); + + /* Check append/parse int/double */ + + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("failed to init string"); + + if (!_dbus_string_append_int (&str, 27)) + _dbus_assert_not_reached ("failed to append int"); + + i = _dbus_string_get_length (&str); + + if (!_dbus_string_parse_int (&str, 0, &v, &end)) + _dbus_assert_not_reached ("failed to parse int"); + + _dbus_assert (v == 27); + _dbus_assert (end == i); + + _dbus_string_free (&str); + + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("failed to init string"); + + if (!_dbus_string_append_double (&str, 50.3)) + _dbus_assert_not_reached ("failed to append float"); + + i = _dbus_string_get_length (&str); + + if (!_dbus_string_parse_double (&str, 0, &d, &end)) + _dbus_assert_not_reached ("failed to parse float"); + + _dbus_assert (d > (50.3 - 1e-6) && d < (50.3 + 1e-6)); + _dbus_assert (end == i); + + _dbus_string_free (&str); + + /* Test find */ + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("failed to init string"); + + if (!_dbus_string_append (&str, "Hello")) + _dbus_assert_not_reached ("couldn't append to string"); + + if (!_dbus_string_find (&str, 0, "He", &i)) + _dbus_assert_not_reached ("didn't find 'He'"); + _dbus_assert (i == 0); + + if (!_dbus_string_find (&str, 0, "Hello", &i)) + _dbus_assert_not_reached ("didn't find 'Hello'"); + _dbus_assert (i == 0); + + if (!_dbus_string_find (&str, 0, "ello", &i)) + _dbus_assert_not_reached ("didn't find 'ello'"); + _dbus_assert (i == 1); + + if (!_dbus_string_find (&str, 0, "lo", &i)) + _dbus_assert_not_reached ("didn't find 'lo'"); + _dbus_assert (i == 3); + + if (!_dbus_string_find (&str, 2, "lo", &i)) + _dbus_assert_not_reached ("didn't find 'lo'"); + _dbus_assert (i == 3); + + if (_dbus_string_find (&str, 4, "lo", &i)) + _dbus_assert_not_reached ("did find 'lo'"); + + if (!_dbus_string_find (&str, 0, "l", &i)) + _dbus_assert_not_reached ("didn't find 'l'"); + _dbus_assert (i == 2); + + if (!_dbus_string_find (&str, 0, "H", &i)) + _dbus_assert_not_reached ("didn't find 'H'"); + _dbus_assert (i == 0); + + if (!_dbus_string_find (&str, 0, "", &i)) + _dbus_assert_not_reached ("didn't find ''"); + _dbus_assert (i == 0); + + if (_dbus_string_find (&str, 0, "Hello!", NULL)) + _dbus_assert_not_reached ("Did find 'Hello!'"); + + if (_dbus_string_find (&str, 0, "Oh, Hello", NULL)) + _dbus_assert_not_reached ("Did find 'Oh, Hello'"); + + if (_dbus_string_find (&str, 0, "ill", NULL)) + _dbus_assert_not_reached ("Did find 'ill'"); + + if (_dbus_string_find (&str, 0, "q", NULL)) + _dbus_assert_not_reached ("Did find 'q'"); + + if (!_dbus_string_find_to (&str, 0, 2, "He", NULL)) + _dbus_assert_not_reached ("Didn't find 'He'"); + + if (_dbus_string_find_to (&str, 0, 2, "Hello", NULL)) + _dbus_assert_not_reached ("Did find 'Hello'"); + + if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'H', &i)) + _dbus_assert_not_reached ("Did not find 'H'"); + _dbus_assert (i == 0); + + if (!_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str), 'o', &i)) + _dbus_assert_not_reached ("Did not find 'o'"); + _dbus_assert (i == _dbus_string_get_length (&str) - 1); + + if (_dbus_string_find_byte_backward (&str, _dbus_string_get_length (&str) - 1, 'o', &i)) + _dbus_assert_not_reached ("Did find 'o'"); + _dbus_assert (i == -1); + + if (_dbus_string_find_byte_backward (&str, 1, 'e', &i)) + _dbus_assert_not_reached ("Did find 'e'"); + _dbus_assert (i == -1); + + if (!_dbus_string_find_byte_backward (&str, 2, 'e', &i)) + _dbus_assert_not_reached ("Didn't find 'e'"); + _dbus_assert (i == 1); + + _dbus_string_free (&str); + + /* Hex encoding */ + _dbus_string_init_const (&str, "cafebabe, this is a bogus hex string"); + if (!_dbus_string_init (&other)) + _dbus_assert_not_reached ("could not init string"); + + if (!_dbus_string_hex_decode (&str, 0, &end, &other, 0)) + _dbus_assert_not_reached ("deccoded bogus hex string with no error"); + + _dbus_assert (end == 8); + + _dbus_string_free (&other); + + test_roundtrips (test_hex_roundtrip); + + _dbus_string_free (&str); + + { + int found, found_len; + + _dbus_string_init_const (&str, "012\r\n567\n90"); + + if (!_dbus_string_find_eol (&str, 0, &found, &found_len) || found != 3 || found_len != 2) + _dbus_assert_not_reached ("Did not find '\\r\\n'"); + if (found != 3 || found_len != 2) + _dbus_assert_not_reached ("invalid return values"); + + if (!_dbus_string_find_eol (&str, 5, &found, &found_len)) + _dbus_assert_not_reached ("Did not find '\\n'"); + if (found != 8 || found_len != 1) + _dbus_assert_not_reached ("invalid return values"); + + if (_dbus_string_find_eol (&str, 9, &found, &found_len)) + _dbus_assert_not_reached ("Found not expected '\\n'"); + else if (found != 11 || found_len != 0) + _dbus_assert_not_reached ("invalid return values '\\n'"); + + found = -1; + found_len = -1; + _dbus_string_init_const (&str, ""); + if (_dbus_string_find_eol (&str, 0, &found, &found_len)) + _dbus_assert_not_reached ("found an eol in an empty string"); + _dbus_assert (found == 0); + _dbus_assert (found_len == 0); + + found = -1; + found_len = -1; + _dbus_string_init_const (&str, "foobar"); + if (_dbus_string_find_eol (&str, 0, &found, &found_len)) + _dbus_assert_not_reached ("found eol in string that lacks one"); + _dbus_assert (found == 6); + _dbus_assert (found_len == 0); + + found = -1; + found_len = -1; + _dbus_string_init_const (&str, "foobar\n"); + if (!_dbus_string_find_eol (&str, 0, &found, &found_len)) + _dbus_assert_not_reached ("did not find eol in string that has one at end"); + _dbus_assert (found == 6); + _dbus_assert (found_len == 1); + } + + { + DBusString line; + +#define FIRST_LINE "this is a line" +#define SECOND_LINE "this is a second line" + /* third line is empty */ +#define THIRD_LINE "" +#define FOURTH_LINE "this is a fourth line" + + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("no memory"); + + if (!_dbus_string_append (&str, FIRST_LINE "\n" SECOND_LINE "\r\n" THIRD_LINE "\n" FOURTH_LINE)) + _dbus_assert_not_reached ("no memory"); + + if (!_dbus_string_init (&line)) + _dbus_assert_not_reached ("no memory"); + + if (!_dbus_string_pop_line (&str, &line)) + _dbus_assert_not_reached ("failed to pop first line"); + + _dbus_assert (_dbus_string_equal_c_str (&line, FIRST_LINE)); + + if (!_dbus_string_pop_line (&str, &line)) + _dbus_assert_not_reached ("failed to pop second line"); + + _dbus_assert (_dbus_string_equal_c_str (&line, SECOND_LINE)); + + if (!_dbus_string_pop_line (&str, &line)) + _dbus_assert_not_reached ("failed to pop third line"); + + _dbus_assert (_dbus_string_equal_c_str (&line, THIRD_LINE)); + + if (!_dbus_string_pop_line (&str, &line)) + _dbus_assert_not_reached ("failed to pop fourth line"); + + _dbus_assert (_dbus_string_equal_c_str (&line, FOURTH_LINE)); + + _dbus_string_free (&str); + _dbus_string_free (&line); + } + + { + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("no memory"); + + for (i = 0; i < 10000; i++) + if (!_dbus_string_append (&str, "abcdefghijklmnopqrstuvwxyz")) + _dbus_assert_not_reached ("no memory"); + + if (!_dbus_string_set_length (&str, 10)) + _dbus_assert_not_reached ("failed to set length"); + + /* actually compact */ + if (!_dbus_string_compact (&str, 2048)) + _dbus_assert_not_reached ("failed to compact after set_length"); + + /* peek inside to make sure it worked */ + if (((DBusRealString *)&str)->allocated > 30) + _dbus_assert_not_reached ("compacting string didn't do anything"); + + if (!_dbus_string_equal_c_str (&str, "abcdefghij")) + _dbus_assert_not_reached ("unexpected content after compact"); + + /* compact nothing */ + if (!_dbus_string_compact (&str, 2048)) + _dbus_assert_not_reached ("failed to compact 2nd time"); + + if (!_dbus_string_equal_c_str (&str, "abcdefghij")) + _dbus_assert_not_reached ("unexpected content after 2nd compact"); + + /* and make sure it still works...*/ + if (!_dbus_string_append (&str, "123456")) + _dbus_assert_not_reached ("failed to append after compact"); + + if (!_dbus_string_equal_c_str (&str, "abcdefghij123456")) + _dbus_assert_not_reached ("unexpected content after append"); + + /* after growing automatically, this should do nothing */ + if (!_dbus_string_compact (&str, 20000)) + _dbus_assert_not_reached ("failed to compact after grow"); + + /* but this one will do something */ + if (!_dbus_string_compact (&str, 0)) + _dbus_assert_not_reached ("failed to compact after grow"); + + if (!_dbus_string_equal_c_str (&str, "abcdefghij123456")) + _dbus_assert_not_reached ("unexpected content"); + + if (!_dbus_string_append (&str, "!@#$%")) + _dbus_assert_not_reached ("failed to append after compact"); + + if (!_dbus_string_equal_c_str (&str, "abcdefghij123456!@#$%")) + _dbus_assert_not_reached ("unexpected content"); + + _dbus_string_free (&str); + } + + { + const char two_strings[] = "one\ttwo"; + + if (!_dbus_string_init (&str)) + _dbus_assert_not_reached ("no memory"); + + if (!_dbus_string_init (&other)) + _dbus_assert_not_reached ("no memory"); + + if (!_dbus_string_append (&str, two_strings)) + _dbus_assert_not_reached ("no memory"); + + if (!_dbus_string_split_on_byte (&str, '\t', &other)) + _dbus_assert_not_reached ("no memory or delimiter not found"); + + if (strcmp (_dbus_string_get_data (&str), "one") != 0) + _dbus_assert_not_reached ("left side after split on tab is wrong"); + + if (strcmp (_dbus_string_get_data (&other), "two") != 0) + _dbus_assert_not_reached ("right side after split on tab is wrong"); + + _dbus_string_free (&str); + _dbus_string_free (&other); + } + + return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c new file mode 100644 index 00000000..6da46d1a --- /dev/null +++ b/dbus/dbus-string.c @@ -0,0 +1,2918 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-string.c String utility class (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + * Copyright (C) 2006 Ralf Habacker + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-string.h" +/* we allow a system header here, for speed/convenience */ +#include +/* for vsnprintf */ +#include +#define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1 +#include "dbus-string-private.h" +#include "dbus-marshal-basic.h" /* probably should be removed by moving the usage of DBUS_TYPE + * into the marshaling-related files + */ +/* for DBUS_VA_COPY */ +#include "dbus-sysdeps.h" + +/** + * @defgroup DBusString DBusString class + * @ingroup DBusInternals + * @brief DBusString data structure for safer string handling + * + * Types and functions related to DBusString. DBusString is intended + * to be a string class that makes it hard to mess up security issues + * (and just in general harder to write buggy code). It should be + * used (or extended and then used) rather than the libc stuff in + * string.h. The string class is a bit inconvenient at spots because + * it handles out-of-memory failures and tries to be extra-robust. + * + * A DBusString has a maximum length set at initialization time; this + * can be used to ensure that a buffer doesn't get too big. The + * _dbus_string_lengthen() method checks for overflow, and for max + * length being exceeded. + * + * Try to avoid conversion to a plain C string, i.e. add methods on + * the string object instead, only convert to C string when passing + * things out to the public API. In particular, no sprintf, strcpy, + * strcat, any of that should be used. The GString feature of + * accepting negative numbers for "length of string" is also absent, + * because it could keep us from detecting bogus huge lengths. i.e. if + * we passed in some bogus huge length it would be taken to mean + * "current length of string" instead of "broken crack" + * + * @todo #DBusString needs a lot of cleaning up; some of the + * API is no longer used, and the API is pretty inconsistent. + * In particular all the "append" APIs, especially those involving + * alignment but probably lots of them, are no longer used by the + * marshaling code which always does "inserts" now. + */ + +/** + * @addtogroup DBusString + * @{ + */ + +static void +fixup_alignment (DBusRealString *real) +{ + unsigned char *aligned; + unsigned char *real_block; + unsigned int old_align_offset; + + /* we have to have extra space in real->allocated for the align offset and nul byte */ + _dbus_assert (real->len <= real->allocated - _DBUS_STRING_ALLOCATION_PADDING); + + old_align_offset = real->align_offset; + real_block = real->str - old_align_offset; + + aligned = _DBUS_ALIGN_ADDRESS (real_block, 8); + + real->align_offset = aligned - real_block; + real->str = aligned; + + if (old_align_offset != real->align_offset) + { + /* Here comes the suck */ + memmove (real_block + real->align_offset, + real_block + old_align_offset, + real->len + 1); + } + + _dbus_assert (real->align_offset < 8); + _dbus_assert (_DBUS_ALIGN_ADDRESS (real->str, 8) == real->str); +} + +static void +undo_alignment (DBusRealString *real) +{ + if (real->align_offset != 0) + { + memmove (real->str - real->align_offset, + real->str, + real->len + 1); + + real->str = real->str - real->align_offset; + real->align_offset = 0; + } +} + +/** + * Initializes a string that can be up to the given allocation size + * before it has to realloc. The string starts life with zero length. + * The string must eventually be freed with _dbus_string_free(). + * + * @param str memory to hold the string + * @param allocate_size amount to preallocate + * @returns #TRUE on success, #FALSE if no memory + */ +dbus_bool_t +_dbus_string_init_preallocated (DBusString *str, + int allocate_size) +{ + DBusRealString *real; + + _dbus_assert (str != NULL); + + _dbus_assert (sizeof (DBusString) == sizeof (DBusRealString)); + + real = (DBusRealString*) str; + + /* It's very important not to touch anything + * other than real->str if we're going to fail, + * since we also use this function to reset + * an existing string, e.g. in _dbus_string_steal_data() + */ + + real->str = dbus_malloc (_DBUS_STRING_ALLOCATION_PADDING + allocate_size); + if (real->str == NULL) + return FALSE; + + real->allocated = _DBUS_STRING_ALLOCATION_PADDING + allocate_size; + real->len = 0; + real->str[real->len] = '\0'; + + real->max_length = _DBUS_STRING_MAX_MAX_LENGTH; + real->constant = FALSE; + real->locked = FALSE; + real->invalid = FALSE; + real->align_offset = 0; + + fixup_alignment (real); + + return TRUE; +} + +/** + * Initializes a string. The string starts life with zero length. The + * string must eventually be freed with _dbus_string_free(). + * + * @param str memory to hold the string + * @returns #TRUE on success, #FALSE if no memory + */ +dbus_bool_t +_dbus_string_init (DBusString *str) +{ + return _dbus_string_init_preallocated (str, 0); +} + +#ifdef DBUS_BUILD_TESTS +/* The max length thing is sort of a historical artifact + * from a feature that turned out to be dumb; perhaps + * we should purge it entirely. The problem with + * the feature is that it looks like memory allocation + * failure, but is not a transient or resolvable failure. + */ +static void +set_max_length (DBusString *str, + int max_length) +{ + DBusRealString *real; + + real = (DBusRealString*) str; + + real->max_length = max_length; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Initializes a constant string. The value parameter is not copied + * (should be static), and the string may never be modified. + * It is safe but not necessary to call _dbus_string_free() + * on a const string. The string has a length limit of MAXINT - 8. + * + * @param str memory to use for the string + * @param value a string to be stored in str (not copied!!!) + */ +void +_dbus_string_init_const (DBusString *str, + const char *value) +{ + _dbus_assert (value != NULL); + + _dbus_string_init_const_len (str, value, + strlen (value)); +} + +/** + * Initializes a constant string with a length. The value parameter is + * not copied (should be static), and the string may never be + * modified. It is safe but not necessary to call _dbus_string_free() + * on a const string. + * + * @param str memory to use for the string + * @param value a string to be stored in str (not copied!!!) + * @param len the length to use + */ +void +_dbus_string_init_const_len (DBusString *str, + const char *value, + int len) +{ + DBusRealString *real; + + _dbus_assert (str != NULL); + _dbus_assert (len == 0 || value != NULL); + _dbus_assert (len <= _DBUS_STRING_MAX_MAX_LENGTH); + _dbus_assert (len >= 0); + + real = (DBusRealString*) str; + + real->str = (unsigned char*) value; + real->len = len; + real->allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING; /* a lie, just to avoid special-case assertions... */ + real->max_length = real->len + 1; + real->constant = TRUE; + real->locked = TRUE; + real->invalid = FALSE; + real->align_offset = 0; + + /* We don't require const strings to be 8-byte aligned as the + * memory is coming from elsewhere. + */ +} + +/** + * Frees a string created by _dbus_string_init(). + * + * @param str memory where the string is stored. + */ +void +_dbus_string_free (DBusString *str) +{ + DBusRealString *real = (DBusRealString*) str; + DBUS_GENERIC_STRING_PREAMBLE (real); + + if (real->constant) + return; + dbus_free (real->str - real->align_offset); + + real->invalid = TRUE; +} + +static dbus_bool_t +compact (DBusRealString *real, + int max_waste) +{ + unsigned char *new_str; + int new_allocated; + int waste; + + waste = real->allocated - (real->len + _DBUS_STRING_ALLOCATION_PADDING); + + if (waste <= max_waste) + return TRUE; + + new_allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING; + + new_str = dbus_realloc (real->str - real->align_offset, new_allocated); + if (_DBUS_UNLIKELY (new_str == NULL)) + return FALSE; + + real->str = new_str + real->align_offset; + real->allocated = new_allocated; + fixup_alignment (real); + + return TRUE; +} + +#ifdef DBUS_BUILD_TESTS +/* Not using this feature at the moment, + * so marked DBUS_BUILD_TESTS-only + */ +/** + * Locks a string such that any attempts to change the string will + * result in aborting the program. Also, if the string is wasting a + * lot of memory (allocation is sufficiently larger than what the + * string is really using), _dbus_string_lock() will realloc the + * string's data to "compact" it. + * + * @param str the string to lock. + */ +void +_dbus_string_lock (DBusString *str) +{ + DBUS_LOCKED_STRING_PREAMBLE (str); /* can lock multiple times */ + + real->locked = TRUE; + + /* Try to realloc to avoid excess memory usage, since + * we know we won't change the string further + */ +#define MAX_WASTE 48 + compact (real, MAX_WASTE); +} +#endif /* DBUS_BUILD_TESTS */ + +static dbus_bool_t +reallocate_for_length (DBusRealString *real, + int new_length) +{ + int new_allocated; + unsigned char *new_str; + + /* at least double our old allocation to avoid O(n), avoiding + * overflow + */ + if (real->allocated > (_DBUS_STRING_MAX_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING) / 2) + new_allocated = _DBUS_STRING_MAX_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING; + else + new_allocated = real->allocated * 2; + + /* if you change the code just above here, run the tests without + * the following assert-only hack before you commit + */ + /* This is keyed off asserts in addition to tests so when you + * disable asserts to profile, you don't get this destroyer + * of profiles. + */ +#ifdef DBUS_DISABLE_ASSERT +#else +#ifdef DBUS_BUILD_TESTS + new_allocated = 0; /* ensure a realloc every time so that we go + * through all malloc failure codepaths + */ +#endif /* DBUS_BUILD_TESTS */ +#endif /* !DBUS_DISABLE_ASSERT */ + + /* But be sure we always alloc at least space for the new length */ + new_allocated = MAX (new_allocated, + new_length + _DBUS_STRING_ALLOCATION_PADDING); + + _dbus_assert (new_allocated >= real->allocated); /* code relies on this */ + new_str = dbus_realloc (real->str - real->align_offset, new_allocated); + if (_DBUS_UNLIKELY (new_str == NULL)) + return FALSE; + + real->str = new_str + real->align_offset; + real->allocated = new_allocated; + fixup_alignment (real); + + return TRUE; +} + +/** + * Compacts the string to avoid wasted memory. Wasted memory is + * memory that is allocated but not actually required to store the + * current length of the string. The compact is only done if more + * than the given amount of memory is being wasted (otherwise the + * waste is ignored and the call does nothing). + * + * @param str the string + * @param max_waste the maximum amount of waste to ignore + * @returns #FALSE if the compact failed due to realloc failure + */ +dbus_bool_t +_dbus_string_compact (DBusString *str, + int max_waste) +{ + DBUS_STRING_PREAMBLE (str); + + return compact (real, max_waste); +} + +static dbus_bool_t +set_length (DBusRealString *real, + int new_length) +{ + /* Note, we are setting the length not including nul termination */ + + /* exceeding max length is the same as failure to allocate memory */ + if (_DBUS_UNLIKELY (new_length > real->max_length)) + return FALSE; + else if (new_length > (real->allocated - _DBUS_STRING_ALLOCATION_PADDING) && + _DBUS_UNLIKELY (!reallocate_for_length (real, new_length))) + return FALSE; + else + { + real->len = new_length; + real->str[new_length] = '\0'; + return TRUE; + } +} + +static dbus_bool_t +open_gap (int len, + DBusRealString *dest, + int insert_at) +{ + if (len == 0) + return TRUE; + + if (len > dest->max_length - dest->len) + return FALSE; /* detected overflow of dest->len + len below */ + + if (!set_length (dest, dest->len + len)) + return FALSE; + + memmove (dest->str + insert_at + len, + dest->str + insert_at, + dest->len - len - insert_at); + + return TRUE; +} + +#ifndef _dbus_string_get_data +/** + * Gets the raw character buffer from the string. The returned buffer + * will be nul-terminated, but note that strings may contain binary + * data so there may be extra nul characters prior to the termination. + * This function should be little-used, extend DBusString or add + * stuff to dbus-sysdeps.c instead. It's an error to use this + * function on a const string. + * + * @param str the string + * @returns the data + */ +char* +_dbus_string_get_data (DBusString *str) +{ + DBUS_STRING_PREAMBLE (str); + + return (char*) real->str; +} +#endif /* _dbus_string_get_data */ + +/* only do the function if we don't have the macro */ +#ifndef _dbus_string_get_const_data +/** + * Gets the raw character buffer from a const string. + * + * @param str the string + * @returns the string data + */ +const char* +_dbus_string_get_const_data (const DBusString *str) +{ + DBUS_CONST_STRING_PREAMBLE (str); + + return (const char*) real->str; +} +#endif /* _dbus_string_get_const_data */ + +/** + * Gets a sub-portion of the raw character buffer from the + * string. The "len" field is required simply for error + * checking, to be sure you don't try to use more + * string than exists. The nul termination of the + * returned buffer remains at the end of the entire + * string, not at start + len. + * + * @param str the string + * @param start byte offset to return + * @param len length of segment to return + * @returns the string data + */ +char* +_dbus_string_get_data_len (DBusString *str, + int start, + int len) +{ + DBUS_STRING_PREAMBLE (str); + _dbus_assert (start >= 0); + _dbus_assert (len >= 0); + _dbus_assert (start <= real->len); + _dbus_assert (len <= real->len - start); + + return (char*) real->str + start; +} + +/* only do the function if we don't have the macro */ +#ifndef _dbus_string_get_const_data_len +/** + * const version of _dbus_string_get_data_len(). + * + * @param str the string + * @param start byte offset to return + * @param len length of segment to return + * @returns the string data + */ +const char* +_dbus_string_get_const_data_len (const DBusString *str, + int start, + int len) +{ + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start >= 0); + _dbus_assert (len >= 0); + _dbus_assert (start <= real->len); + _dbus_assert (len <= real->len - start); + + return (const char*) real->str + start; +} +#endif /* _dbus_string_get_const_data_len */ + +/* only do the function if we don't have the macro */ +#ifndef _dbus_string_set_byte +/** + * Sets the value of the byte at the given position. + * + * @param str the string + * @param i the position + * @param byte the new value + */ +void +_dbus_string_set_byte (DBusString *str, + int i, + unsigned char byte) +{ + DBUS_STRING_PREAMBLE (str); + _dbus_assert (i < real->len); + _dbus_assert (i >= 0); + + real->str[i] = byte; +} +#endif /* _dbus_string_set_byte */ + +/* only have the function if we didn't create a macro */ +#ifndef _dbus_string_get_byte +/** + * Gets the byte at the given position. It is + * allowed to ask for the nul byte at the end of + * the string. + * + * @param str the string + * @param start the position + * @returns the byte at that position + */ +unsigned char +_dbus_string_get_byte (const DBusString *str, + int start) +{ + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start <= real->len); + _dbus_assert (start >= 0); + + return real->str[start]; +} +#endif /* _dbus_string_get_byte */ + +/** + * Inserts a number of bytes of a given value at the + * given position. + * + * @param str the string + * @param i the position + * @param n_bytes number of bytes + * @param byte the value to insert + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_string_insert_bytes (DBusString *str, + int i, + int n_bytes, + unsigned char byte) +{ + DBUS_STRING_PREAMBLE (str); + _dbus_assert (i <= real->len); + _dbus_assert (i >= 0); + _dbus_assert (n_bytes >= 0); + + if (n_bytes == 0) + return TRUE; + + if (!open_gap (n_bytes, real, i)) + return FALSE; + + memset (real->str + i, byte, n_bytes); + + return TRUE; +} + +/** + * Inserts a single byte at the given position. + * + * @param str the string + * @param i the position + * @param byte the value to insert + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_string_insert_byte (DBusString *str, + int i, + unsigned char byte) +{ + DBUS_STRING_PREAMBLE (str); + _dbus_assert (i <= real->len); + _dbus_assert (i >= 0); + + if (!open_gap (1, real, i)) + return FALSE; + + real->str[i] = byte; + + return TRUE; +} + +/** + * Like _dbus_string_get_data(), but removes the + * gotten data from the original string. The caller + * must free the data returned. This function may + * fail due to lack of memory, and return #FALSE. + * + * @param str the string + * @param data_return location to return the buffer + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_string_steal_data (DBusString *str, + char **data_return) +{ + int old_max_length; + DBUS_STRING_PREAMBLE (str); + _dbus_assert (data_return != NULL); + + undo_alignment (real); + + *data_return = (char*) real->str; + + old_max_length = real->max_length; + + /* reset the string */ + if (!_dbus_string_init (str)) + { + /* hrm, put it back then */ + real->str = (unsigned char*) *data_return; + *data_return = NULL; + fixup_alignment (real); + return FALSE; + } + + real->max_length = old_max_length; + + return TRUE; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Like _dbus_string_get_data_len(), but removes the gotten data from + * the original string. The caller must free the data returned. This + * function may fail due to lack of memory, and return #FALSE. + * The returned string is nul-terminated and has length len. + * + * @todo this function is broken because on failure it + * may corrupt the source string. + * + * @param str the string + * @param data_return location to return the buffer + * @param start the start of segment to steal + * @param len the length of segment to steal + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_string_steal_data_len (DBusString *str, + char **data_return, + int start, + int len) +{ + DBusString dest; + DBUS_STRING_PREAMBLE (str); + _dbus_assert (data_return != NULL); + _dbus_assert (start >= 0); + _dbus_assert (len >= 0); + _dbus_assert (start <= real->len); + _dbus_assert (len <= real->len - start); + + if (!_dbus_string_init (&dest)) + return FALSE; + + set_max_length (&dest, real->max_length); + + if (!_dbus_string_move_len (str, start, len, &dest, 0)) + { + _dbus_string_free (&dest); + return FALSE; + } + + _dbus_warn ("Broken code in _dbus_string_steal_data_len(), see @todo, FIXME\n"); + if (!_dbus_string_steal_data (&dest, data_return)) + { + _dbus_string_free (&dest); + return FALSE; + } + + _dbus_string_free (&dest); + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Copies the data from the string into a char* + * + * @param str the string + * @param data_return place to return the data + * @returns #TRUE on success, #FALSE on no memory + */ +dbus_bool_t +_dbus_string_copy_data (const DBusString *str, + char **data_return) +{ + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (data_return != NULL); + + *data_return = dbus_malloc (real->len + 1); + if (*data_return == NULL) + return FALSE; + + memcpy (*data_return, real->str, real->len + 1); + + return TRUE; +} + +/** + * Copies the contents of a DBusString into a different buffer. It is + * a bug if avail_len is too short to hold the string contents. nul + * termination is not copied, just the supplied bytes. + * + * @param str a string + * @param buffer a C buffer to copy data to + * @param avail_len maximum length of C buffer + */ +void +_dbus_string_copy_to_buffer (const DBusString *str, + char *buffer, + int avail_len) +{ + DBUS_CONST_STRING_PREAMBLE (str); + + _dbus_assert (avail_len >= 0); + _dbus_assert (avail_len >= real->len); + + memcpy (buffer, real->str, real->len); +} + +/** + * Copies the contents of a DBusString into a different buffer. It is + * a bug if avail_len is too short to hold the string contents plus a + * nul byte. + * + * @param str a string + * @param buffer a C buffer to copy data to + * @param avail_len maximum length of C buffer + */ +void +_dbus_string_copy_to_buffer_with_nul (const DBusString *str, + char *buffer, + int avail_len) +{ + DBUS_CONST_STRING_PREAMBLE (str); + + _dbus_assert (avail_len >= 0); + _dbus_assert (avail_len > real->len); + + memcpy (buffer, real->str, real->len+1); +} + +#ifdef DBUS_BUILD_TESTS +/** + * Copies a segment of the string into a char* + * + * @param str the string + * @param data_return place to return the data + * @param start start index + * @param len length to copy + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_string_copy_data_len (const DBusString *str, + char **data_return, + int start, + int len) +{ + DBusString dest; + + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (data_return != NULL); + _dbus_assert (start >= 0); + _dbus_assert (len >= 0); + _dbus_assert (start <= real->len); + _dbus_assert (len <= real->len - start); + + if (!_dbus_string_init (&dest)) + return FALSE; + + set_max_length (&dest, real->max_length); + + if (!_dbus_string_copy_len (str, start, len, &dest, 0)) + { + _dbus_string_free (&dest); + return FALSE; + } + + if (!_dbus_string_steal_data (&dest, data_return)) + { + _dbus_string_free (&dest); + return FALSE; + } + + _dbus_string_free (&dest); + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ + +/* Only have the function if we don't have the macro */ +#ifndef _dbus_string_get_length +/** + * Gets the length of a string (not including nul termination). + * + * @returns the length. + */ +int +_dbus_string_get_length (const DBusString *str) +{ + DBUS_CONST_STRING_PREAMBLE (str); + + return real->len; +} +#endif /* !_dbus_string_get_length */ + +/** + * Makes a string longer by the given number of bytes. Checks whether + * adding additional_length to the current length would overflow an + * integer, and checks for exceeding a string's max length. + * The new bytes are not initialized, other than nul-terminating + * the end of the string. The uninitialized bytes may contain + * nul bytes or other junk. + * + * @param str a string + * @param additional_length length to add to the string. + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_string_lengthen (DBusString *str, + int additional_length) +{ + DBUS_STRING_PREAMBLE (str); + _dbus_assert (additional_length >= 0); + + if (_DBUS_UNLIKELY (additional_length > real->max_length - real->len)) + return FALSE; /* would overflow */ + + return set_length (real, + real->len + additional_length); +} + +/** + * Makes a string shorter by the given number of bytes. + * + * @param str a string + * @param length_to_remove length to remove from the string. + */ +void +_dbus_string_shorten (DBusString *str, + int length_to_remove) +{ + DBUS_STRING_PREAMBLE (str); + _dbus_assert (length_to_remove >= 0); + _dbus_assert (length_to_remove <= real->len); + + set_length (real, + real->len - length_to_remove); +} + +/** + * Sets the length of a string. Can be used to truncate or lengthen + * the string. If the string is lengthened, the function may fail and + * return #FALSE. Newly-added bytes are not initialized, as with + * _dbus_string_lengthen(). + * + * @param str a string + * @param length new length of the string. + * @returns #FALSE on failure. + */ +dbus_bool_t +_dbus_string_set_length (DBusString *str, + int length) +{ + DBUS_STRING_PREAMBLE (str); + _dbus_assert (length >= 0); + + return set_length (real, length); +} + +static dbus_bool_t +align_insert_point_then_open_gap (DBusString *str, + int *insert_at_p, + int alignment, + int gap_size) +{ + unsigned long new_len; /* ulong to avoid _DBUS_ALIGN_VALUE overflow */ + unsigned long gap_pos; + int insert_at; + int delta; + DBUS_STRING_PREAMBLE (str); + _dbus_assert (alignment >= 1); + _dbus_assert (alignment <= 8); /* it has to be a bug if > 8 */ + + insert_at = *insert_at_p; + + _dbus_assert (insert_at <= real->len); + + gap_pos = _DBUS_ALIGN_VALUE (insert_at, alignment); + new_len = real->len + (gap_pos - insert_at) + gap_size; + + if (_DBUS_UNLIKELY (new_len > (unsigned long) real->max_length)) + return FALSE; + + delta = new_len - real->len; + _dbus_assert (delta >= 0); + + if (delta == 0) /* only happens if gap_size == 0 and insert_at is aligned already */ + { + _dbus_assert (((unsigned long) *insert_at_p) == gap_pos); + return TRUE; + } + + if (_DBUS_UNLIKELY (!open_gap (new_len - real->len, + real, insert_at))) + return FALSE; + + /* nul the padding if we had to add any padding */ + if (gap_size < delta) + { + memset (&real->str[insert_at], '\0', + gap_pos - insert_at); + } + + *insert_at_p = gap_pos; + + return TRUE; +} + +static dbus_bool_t +align_length_then_lengthen (DBusString *str, + int alignment, + int then_lengthen_by) +{ + int insert_at; + + insert_at = _dbus_string_get_length (str); + + return align_insert_point_then_open_gap (str, + &insert_at, + alignment, then_lengthen_by); +} + +/** + * Align the length of a string to a specific alignment (typically 4 or 8) + * by appending nul bytes to the string. + * + * @param str a string + * @param alignment the alignment + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_string_align_length (DBusString *str, + int alignment) +{ + return align_length_then_lengthen (str, alignment, 0); +} + +/** + * Preallocate extra_bytes such that a future lengthening of the + * string by extra_bytes is guaranteed to succeed without an out of + * memory error. + * + * @param str a string + * @param extra_bytes bytes to alloc + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_string_alloc_space (DBusString *str, + int extra_bytes) +{ + if (!_dbus_string_lengthen (str, extra_bytes)) + return FALSE; + _dbus_string_shorten (str, extra_bytes); + + return TRUE; +} + +static dbus_bool_t +append (DBusRealString *real, + const char *buffer, + int buffer_len) +{ + if (buffer_len == 0) + return TRUE; + + if (!_dbus_string_lengthen ((DBusString*)real, buffer_len)) + return FALSE; + + memcpy (real->str + (real->len - buffer_len), + buffer, + buffer_len); + + return TRUE; +} + +/** + * Appends a nul-terminated C-style string to a DBusString. + * + * @param str the DBusString + * @param buffer the nul-terminated characters to append + * @returns #FALSE if not enough memory. + */ +dbus_bool_t +_dbus_string_append (DBusString *str, + const char *buffer) +{ + unsigned long buffer_len; + + DBUS_STRING_PREAMBLE (str); + _dbus_assert (buffer != NULL); + + buffer_len = strlen (buffer); + if (buffer_len > (unsigned long) real->max_length) + return FALSE; + + return append (real, buffer, buffer_len); +} + +/** assign 2 bytes from one string to another */ +#define ASSIGN_2_OCTETS(p, octets) \ + *((dbus_uint16_t*)(p)) = *((dbus_uint16_t*)(octets)); + +/** assign 4 bytes from one string to another */ +#define ASSIGN_4_OCTETS(p, octets) \ + *((dbus_uint32_t*)(p)) = *((dbus_uint32_t*)(octets)); + +#ifdef DBUS_HAVE_INT64 +/** assign 8 bytes from one string to another */ +#define ASSIGN_8_OCTETS(p, octets) \ + *((dbus_uint64_t*)(p)) = *((dbus_uint64_t*)(octets)); +#else +/** assign 8 bytes from one string to another */ +#define ASSIGN_8_OCTETS(p, octets) \ +do { \ + unsigned char *b; \ + \ + b = p; \ + \ + *b++ = octets[0]; \ + *b++ = octets[1]; \ + *b++ = octets[2]; \ + *b++ = octets[3]; \ + *b++ = octets[4]; \ + *b++ = octets[5]; \ + *b++ = octets[6]; \ + *b++ = octets[7]; \ + _dbus_assert (b == p + 8); \ +} while (0) +#endif /* DBUS_HAVE_INT64 */ + +#ifdef DBUS_BUILD_TESTS +/** + * Appends 4 bytes aligned on a 4 byte boundary + * with any alignment padding initialized to 0. + * + * @param str the DBusString + * @param octets 4 bytes to append + * @returns #FALSE if not enough memory. + */ +dbus_bool_t +_dbus_string_append_4_aligned (DBusString *str, + const unsigned char octets[4]) +{ + DBUS_STRING_PREAMBLE (str); + + if (!align_length_then_lengthen (str, 4, 4)) + return FALSE; + + ASSIGN_4_OCTETS (real->str + (real->len - 4), octets); + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ + +#ifdef DBUS_BUILD_TESTS +/** + * Appends 8 bytes aligned on an 8 byte boundary + * with any alignment padding initialized to 0. + * + * @param str the DBusString + * @param octets 8 bytes to append + * @returns #FALSE if not enough memory. + */ +dbus_bool_t +_dbus_string_append_8_aligned (DBusString *str, + const unsigned char octets[8]) +{ + DBUS_STRING_PREAMBLE (str); + + if (!align_length_then_lengthen (str, 8, 8)) + return FALSE; + + ASSIGN_8_OCTETS (real->str + (real->len - 8), octets); + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Inserts 2 bytes aligned on a 2 byte boundary + * with any alignment padding initialized to 0. + * + * @param str the DBusString + * @param insert_at where to insert + * @param octets 2 bytes to insert + * @returns #FALSE if not enough memory. + */ +dbus_bool_t +_dbus_string_insert_2_aligned (DBusString *str, + int insert_at, + const unsigned char octets[4]) +{ + DBUS_STRING_PREAMBLE (str); + + if (!align_insert_point_then_open_gap (str, &insert_at, 2, 2)) + return FALSE; + + ASSIGN_2_OCTETS (real->str + insert_at, octets); + + return TRUE; +} + +/** + * Inserts 4 bytes aligned on a 4 byte boundary + * with any alignment padding initialized to 0. + * + * @param str the DBusString + * @param insert_at where to insert + * @param octets 4 bytes to insert + * @returns #FALSE if not enough memory. + */ +dbus_bool_t +_dbus_string_insert_4_aligned (DBusString *str, + int insert_at, + const unsigned char octets[4]) +{ + DBUS_STRING_PREAMBLE (str); + + if (!align_insert_point_then_open_gap (str, &insert_at, 4, 4)) + return FALSE; + + ASSIGN_4_OCTETS (real->str + insert_at, octets); + + return TRUE; +} + +/** + * Inserts 8 bytes aligned on an 8 byte boundary + * with any alignment padding initialized to 0. + * + * @param str the DBusString + * @param insert_at where to insert + * @param octets 8 bytes to insert + * @returns #FALSE if not enough memory. + */ +dbus_bool_t +_dbus_string_insert_8_aligned (DBusString *str, + int insert_at, + const unsigned char octets[8]) +{ + DBUS_STRING_PREAMBLE (str); + + if (!align_insert_point_then_open_gap (str, &insert_at, 8, 8)) + return FALSE; + + _dbus_assert (_DBUS_ALIGN_VALUE (insert_at, 8) == (unsigned) insert_at); + + ASSIGN_8_OCTETS (real->str + insert_at, octets); + + return TRUE; +} + + +/** + * Inserts padding at *insert_at such to align it to the given + * boundary. Initializes the padding to nul bytes. Sets *insert_at + * to the aligned position. + * + * @param str the DBusString + * @param insert_at location to be aligned + * @param alignment alignment boundary (1, 2, 4, or 8) + * @returns #FALSE if not enough memory. + */ +dbus_bool_t +_dbus_string_insert_alignment (DBusString *str, + int *insert_at, + int alignment) +{ + DBUS_STRING_PREAMBLE (str); + + if (!align_insert_point_then_open_gap (str, insert_at, alignment, 0)) + return FALSE; + + _dbus_assert (_DBUS_ALIGN_VALUE (*insert_at, alignment) == (unsigned) *insert_at); + + return TRUE; +} + +/** + * Appends a printf-style formatted string + * to the #DBusString. + * + * @param str the string + * @param format printf format + * @param args variable argument list + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_string_append_printf_valist (DBusString *str, + const char *format, + va_list args) +{ + int len; + va_list args_copy; + + DBUS_STRING_PREAMBLE (str); + + DBUS_VA_COPY (args_copy, args); + + /* Measure the message length without terminating nul */ + len = _dbus_printf_string_upper_bound (format, args); + + if (!_dbus_string_lengthen (str, len)) + { + /* don't leak the copy */ + va_end (args_copy); + return FALSE; + } + + vsprintf ((char*) (real->str + (real->len - len)), + format, args_copy); + + va_end (args_copy); + + return TRUE; +} + +/** + * Appends a printf-style formatted string + * to the #DBusString. + * + * @param str the string + * @param format printf format + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_string_append_printf (DBusString *str, + const char *format, + ...) +{ + va_list args; + dbus_bool_t retval; + + va_start (args, format); + retval = _dbus_string_append_printf_valist (str, format, args); + va_end (args); + + return retval; +} + +/** + * Appends block of bytes with the given length to a DBusString. + * + * @param str the DBusString + * @param buffer the bytes to append + * @param len the number of bytes to append + * @returns #FALSE if not enough memory. + */ +dbus_bool_t +_dbus_string_append_len (DBusString *str, + const char *buffer, + int len) +{ + DBUS_STRING_PREAMBLE (str); + _dbus_assert (buffer != NULL); + _dbus_assert (len >= 0); + + return append (real, buffer, len); +} + +/** + * Appends a single byte to the string, returning #FALSE + * if not enough memory. + * + * @param str the string + * @param byte the byte to append + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_string_append_byte (DBusString *str, + unsigned char byte) +{ + DBUS_STRING_PREAMBLE (str); + + if (!set_length (real, real->len + 1)) + return FALSE; + + real->str[real->len-1] = byte; + + return TRUE; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Appends a single Unicode character, encoding the character + * in UTF-8 format. + * + * @param str the string + * @param ch the Unicode character + */ +dbus_bool_t +_dbus_string_append_unichar (DBusString *str, + dbus_unichar_t ch) +{ + int len; + int first; + int i; + unsigned char *out; + + DBUS_STRING_PREAMBLE (str); + + /* this code is from GLib but is pretty standard I think */ + + len = 0; + + if (ch < 0x80) + { + first = 0; + len = 1; + } + else if (ch < 0x800) + { + first = 0xc0; + len = 2; + } + else if (ch < 0x10000) + { + first = 0xe0; + len = 3; + } + else if (ch < 0x200000) + { + first = 0xf0; + len = 4; + } + else if (ch < 0x4000000) + { + first = 0xf8; + len = 5; + } + else + { + first = 0xfc; + len = 6; + } + + if (len > (real->max_length - real->len)) + return FALSE; /* real->len + len would overflow */ + + if (!set_length (real, real->len + len)) + return FALSE; + + out = real->str + (real->len - len); + + for (i = len - 1; i > 0; --i) + { + out[i] = (ch & 0x3f) | 0x80; + ch >>= 6; + } + out[0] = ch | first; + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ + +static void +delete (DBusRealString *real, + int start, + int len) +{ + if (len == 0) + return; + + memmove (real->str + start, real->str + start + len, real->len - (start + len)); + real->len -= len; + real->str[real->len] = '\0'; +} + +/** + * Deletes a segment of a DBusString with length len starting at + * start. (Hint: to clear an entire string, setting length to 0 + * with _dbus_string_set_length() is easier.) + * + * @param str the DBusString + * @param start where to start deleting + * @param len the number of bytes to delete + */ +void +_dbus_string_delete (DBusString *str, + int start, + int len) +{ + DBUS_STRING_PREAMBLE (str); + _dbus_assert (start >= 0); + _dbus_assert (len >= 0); + _dbus_assert (start <= real->len); + _dbus_assert (len <= real->len - start); + + delete (real, start, len); +} + +static dbus_bool_t +copy (DBusRealString *source, + int start, + int len, + DBusRealString *dest, + int insert_at) +{ + if (len == 0) + return TRUE; + + if (!open_gap (len, dest, insert_at)) + return FALSE; + + memmove (dest->str + insert_at, + source->str + start, + len); + + return TRUE; +} + +/** + * Checks assertions for two strings we're copying a segment between, + * and declares real_source/real_dest variables. + * + * @param source the source string + * @param start the starting offset + * @param dest the dest string + * @param insert_at where the copied segment is inserted + */ +#define DBUS_STRING_COPY_PREAMBLE(source, start, dest, insert_at) \ + DBusRealString *real_source = (DBusRealString*) source; \ + DBusRealString *real_dest = (DBusRealString*) dest; \ + _dbus_assert ((source) != (dest)); \ + DBUS_GENERIC_STRING_PREAMBLE (real_source); \ + DBUS_GENERIC_STRING_PREAMBLE (real_dest); \ + _dbus_assert (!real_dest->constant); \ + _dbus_assert (!real_dest->locked); \ + _dbus_assert ((start) >= 0); \ + _dbus_assert ((start) <= real_source->len); \ + _dbus_assert ((insert_at) >= 0); \ + _dbus_assert ((insert_at) <= real_dest->len) + +/** + * Moves the end of one string into another string. Both strings + * must be initialized, valid strings. + * + * @param source the source string + * @param start where to chop off the source string + * @param dest the destination string + * @param insert_at where to move the chopped-off part of source string + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_string_move (DBusString *source, + int start, + DBusString *dest, + int insert_at) +{ + DBusRealString *real_source = (DBusRealString*) source; + _dbus_assert (start <= real_source->len); + + return _dbus_string_move_len (source, start, + real_source->len - start, + dest, insert_at); +} + +/** + * Like _dbus_string_move(), but does not delete the section + * of the source string that's copied to the dest string. + * + * @param source the source string + * @param start where to start copying the source string + * @param dest the destination string + * @param insert_at where to place the copied part of source string + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_string_copy (const DBusString *source, + int start, + DBusString *dest, + int insert_at) +{ + DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at); + + return copy (real_source, start, + real_source->len - start, + real_dest, + insert_at); +} + +/** + * Like _dbus_string_move(), but can move a segment from + * the middle of the source string. + * + * @todo this doesn't do anything with max_length field. + * we should probably just kill the max_length field though. + * + * @param source the source string + * @param start first byte of source string to move + * @param len length of segment to move + * @param dest the destination string + * @param insert_at where to move the bytes from the source string + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_string_move_len (DBusString *source, + int start, + int len, + DBusString *dest, + int insert_at) + +{ + DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at); + _dbus_assert (len >= 0); + _dbus_assert ((start + len) <= real_source->len); + + + if (len == 0) + { + return TRUE; + } + else if (start == 0 && + len == real_source->len && + real_dest->len == 0) + { + /* Short-circuit moving an entire existing string to an empty string + * by just swapping the buffers. + */ + /* we assume ->constant doesn't matter as you can't have + * a constant string involved in a move. + */ +#define ASSIGN_DATA(a, b) do { \ + (a)->str = (b)->str; \ + (a)->len = (b)->len; \ + (a)->allocated = (b)->allocated; \ + (a)->align_offset = (b)->align_offset; \ + } while (0) + + DBusRealString tmp; + + ASSIGN_DATA (&tmp, real_source); + ASSIGN_DATA (real_source, real_dest); + ASSIGN_DATA (real_dest, &tmp); + + return TRUE; + } + else + { + if (!copy (real_source, start, len, + real_dest, + insert_at)) + return FALSE; + + delete (real_source, start, + len); + + return TRUE; + } +} + +/** + * Like _dbus_string_copy(), but can copy a segment from the middle of + * the source string. + * + * @param source the source string + * @param start where to start copying the source string + * @param len length of segment to copy + * @param dest the destination string + * @param insert_at where to place the copied segment of source string + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_string_copy_len (const DBusString *source, + int start, + int len, + DBusString *dest, + int insert_at) +{ + DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at); + _dbus_assert (len >= 0); + _dbus_assert (start <= real_source->len); + _dbus_assert (len <= real_source->len - start); + + return copy (real_source, start, len, + real_dest, + insert_at); +} + +/** + * Replaces a segment of dest string with a segment of source string. + * + * @todo optimize the case where the two lengths are the same, and + * avoid memmoving the data in the trailing part of the string twice. + * + * @todo avoid inserting the source into dest, then deleting + * the replaced chunk of dest (which creates a potentially large + * intermediate string). Instead, extend the replaced chunk + * of dest with padding to the same size as the source chunk, + * then copy in the source bytes. + * + * @param source the source string + * @param start where to start copying the source string + * @param len length of segment to copy + * @param dest the destination string + * @param replace_at start of segment of dest string to replace + * @param replace_len length of segment of dest string to replace + * @returns #FALSE if not enough memory + * + */ +dbus_bool_t +_dbus_string_replace_len (const DBusString *source, + int start, + int len, + DBusString *dest, + int replace_at, + int replace_len) +{ + DBUS_STRING_COPY_PREAMBLE (source, start, dest, replace_at); + _dbus_assert (len >= 0); + _dbus_assert (start <= real_source->len); + _dbus_assert (len <= real_source->len - start); + _dbus_assert (replace_at >= 0); + _dbus_assert (replace_at <= real_dest->len); + _dbus_assert (replace_len <= real_dest->len - replace_at); + + if (!copy (real_source, start, len, + real_dest, replace_at)) + return FALSE; + + delete (real_dest, replace_at + len, replace_len); + + return TRUE; +} + +/** + * Looks for the first occurance of a byte, deletes that byte, + * and moves everything after the byte to the beginning of a + * separate string. Both strings must be initialized, valid + * strings. + * + * @param source the source string + * @param byte the byte to remove and split the string at + * @param tail the split off string + * @returns #FALSE if not enough memory or if byte could not be found + * + */ +dbus_bool_t +_dbus_string_split_on_byte (DBusString *source, + unsigned char byte, + DBusString *tail) +{ + int byte_position; + char byte_string[2] = ""; + int head_length; + int tail_length; + + byte_string[0] = (char) byte; + + if (!_dbus_string_find (source, 0, byte_string, &byte_position)) + return FALSE; + + head_length = byte_position; + tail_length = _dbus_string_get_length (source) - head_length - 1; + + if (!_dbus_string_move_len (source, byte_position + 1, tail_length, + tail, 0)) + return FALSE; + + /* remove the trailing delimiter byte from the head now. + */ + if (!_dbus_string_set_length (source, head_length)) + return FALSE; + + return TRUE; +} + +/* Unicode macros and utf8_validate() from GLib Owen Taylor, Havoc + * Pennington, and Tom Tromey are the authors and authorized relicense. + */ + +/** computes length and mask of a unicode character + * @param Char the char + * @param Mask the mask variable to assign to + * @param Len the length variable to assign to + */ +#define UTF8_COMPUTE(Char, Mask, Len) \ + if (Char < 128) \ + { \ + Len = 1; \ + Mask = 0x7f; \ + } \ + else if ((Char & 0xe0) == 0xc0) \ + { \ + Len = 2; \ + Mask = 0x1f; \ + } \ + else if ((Char & 0xf0) == 0xe0) \ + { \ + Len = 3; \ + Mask = 0x0f; \ + } \ + else if ((Char & 0xf8) == 0xf0) \ + { \ + Len = 4; \ + Mask = 0x07; \ + } \ + else if ((Char & 0xfc) == 0xf8) \ + { \ + Len = 5; \ + Mask = 0x03; \ + } \ + else if ((Char & 0xfe) == 0xfc) \ + { \ + Len = 6; \ + Mask = 0x01; \ + } \ + else \ + { \ + Len = 0; \ + Mask = 0; \ + } + +/** + * computes length of a unicode character in UTF-8 + * @param Char the char + */ +#define UTF8_LENGTH(Char) \ + ((Char) < 0x80 ? 1 : \ + ((Char) < 0x800 ? 2 : \ + ((Char) < 0x10000 ? 3 : \ + ((Char) < 0x200000 ? 4 : \ + ((Char) < 0x4000000 ? 5 : 6))))) + +/** + * Gets a UTF-8 value. + * + * @param Result variable for extracted unicode char. + * @param Chars the bytes to decode + * @param Count counter variable + * @param Mask mask for this char + * @param Len length for this char in bytes + */ +#define UTF8_GET(Result, Chars, Count, Mask, Len) \ + (Result) = (Chars)[0] & (Mask); \ + for ((Count) = 1; (Count) < (Len); ++(Count)) \ + { \ + if (((Chars)[(Count)] & 0xc0) != 0x80) \ + { \ + (Result) = -1; \ + break; \ + } \ + (Result) <<= 6; \ + (Result) |= ((Chars)[(Count)] & 0x3f); \ + } + +/** + * Check whether a Unicode (5.2) char is in a valid range. + * + * The first check comes from the Unicode guarantee to never encode + * a point above 0x0010ffff, since UTF-16 couldn't represent it. + * + * The second check covers surrogate pairs (category Cs). + * + * The last two checks cover "Noncharacter": defined as: + * "A code point that is permanently reserved for + * internal use, and that should never be interchanged. In + * Unicode 3.1, these consist of the values U+nFFFE and U+nFFFF + * (where n is from 0 to 10_16) and the values U+FDD0..U+FDEF." + * + * @param Char the character + */ +#define UNICODE_VALID(Char) \ + ((Char) < 0x110000 && \ + (((Char) & 0xFFFFF800) != 0xD800) && \ + ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \ + ((Char) & 0xFFFE) != 0xFFFE) + +#ifdef DBUS_BUILD_TESTS +/** + * Gets a unicode character from a UTF-8 string. Does no validation; + * you must verify that the string is valid UTF-8 in advance and must + * pass in the start of a character. + * + * @param str the string + * @param start the start of the UTF-8 character. + * @param ch_return location to return the character + * @param end_return location to return the byte index of next character + */ +void +_dbus_string_get_unichar (const DBusString *str, + int start, + dbus_unichar_t *ch_return, + int *end_return) +{ + int i, mask, len; + dbus_unichar_t result; + unsigned char c; + unsigned char *p; + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start >= 0); + _dbus_assert (start <= real->len); + + if (ch_return) + *ch_return = 0; + if (end_return) + *end_return = real->len; + + mask = 0; + p = real->str + start; + c = *p; + + UTF8_COMPUTE (c, mask, len); + if (len == 0) + return; + UTF8_GET (result, p, i, mask, len); + + if (result == (dbus_unichar_t)-1) + return; + + if (ch_return) + *ch_return = result; + if (end_return) + *end_return = start + len; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Finds the given substring in the string, + * returning #TRUE and filling in the byte index + * where the substring was found, if it was found. + * Returns #FALSE if the substring wasn't found. + * Sets *start to the length of the string if the substring + * is not found. + * + * @param str the string + * @param start where to start looking + * @param substr the substring + * @param found return location for where it was found, or #NULL + * @returns #TRUE if found + */ +dbus_bool_t +_dbus_string_find (const DBusString *str, + int start, + const char *substr, + int *found) +{ + return _dbus_string_find_to (str, start, + ((const DBusRealString*)str)->len, + substr, found); +} + +/** + * Finds end of line ("\r\n" or "\n") in the string, + * returning #TRUE and filling in the byte index + * where the eol string was found, if it was found. + * Returns #FALSE if eol wasn't found. + * + * @param str the string + * @param start where to start looking + * @param found return location for where eol was found or string length otherwise + * @param found_len return length of found eol string or zero otherwise + * @returns #TRUE if found + */ +dbus_bool_t +_dbus_string_find_eol (const DBusString *str, + int start, + int *found, + int *found_len) +{ + int i; + + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start <= real->len); + _dbus_assert (start >= 0); + + i = start; + while (i < real->len) + { + if (real->str[i] == '\r') + { + if ((i+1) < real->len && real->str[i+1] == '\n') /* "\r\n" */ + { + if (found) + *found = i; + if (found_len) + *found_len = 2; + return TRUE; + } + else /* only "\r" */ + { + if (found) + *found = i; + if (found_len) + *found_len = 1; + return TRUE; + } + } + else if (real->str[i] == '\n') /* only "\n" */ + { + if (found) + *found = i; + if (found_len) + *found_len = 1; + return TRUE; + } + ++i; + } + + if (found) + *found = real->len; + + if (found_len) + *found_len = 0; + + return FALSE; +} + +/** + * Finds the given substring in the string, + * up to a certain position, + * returning #TRUE and filling in the byte index + * where the substring was found, if it was found. + * Returns #FALSE if the substring wasn't found. + * Sets *start to the length of the string if the substring + * is not found. + * + * @param str the string + * @param start where to start looking + * @param end where to stop looking + * @param substr the substring + * @param found return location for where it was found, or #NULL + * @returns #TRUE if found + */ +dbus_bool_t +_dbus_string_find_to (const DBusString *str, + int start, + int end, + const char *substr, + int *found) +{ + int i; + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (substr != NULL); + _dbus_assert (start <= real->len); + _dbus_assert (start >= 0); + _dbus_assert (substr != NULL); + _dbus_assert (end <= real->len); + _dbus_assert (start <= end); + + /* we always "find" an empty string */ + if (*substr == '\0') + { + if (found) + *found = start; + return TRUE; + } + + i = start; + while (i < end) + { + if (real->str[i] == substr[0]) + { + int j = i + 1; + + while (j < end) + { + if (substr[j - i] == '\0') + break; + else if (real->str[j] != substr[j - i]) + break; + + ++j; + } + + if (substr[j - i] == '\0') + { + if (found) + *found = i; + return TRUE; + } + } + + ++i; + } + + if (found) + *found = end; + + return FALSE; +} + +/** + * Finds a blank (space or tab) in the string. Returns #TRUE + * if found, #FALSE otherwise. If a blank is not found sets + * *found to the length of the string. + * + * @param str the string + * @param start byte index to start looking + * @param found place to store the location of the first blank + * @returns #TRUE if a blank was found + */ +dbus_bool_t +_dbus_string_find_blank (const DBusString *str, + int start, + int *found) +{ + int i; + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start <= real->len); + _dbus_assert (start >= 0); + + i = start; + while (i < real->len) + { + if (real->str[i] == ' ' || + real->str[i] == '\t') + { + if (found) + *found = i; + return TRUE; + } + + ++i; + } + + if (found) + *found = real->len; + + return FALSE; +} + +/** + * Skips blanks from start, storing the first non-blank in *end + * (blank is space or tab). + * + * @param str the string + * @param start where to start + * @param end where to store the first non-blank byte index + */ +void +_dbus_string_skip_blank (const DBusString *str, + int start, + int *end) +{ + int i; + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start <= real->len); + _dbus_assert (start >= 0); + + i = start; + while (i < real->len) + { + if (!DBUS_IS_ASCII_BLANK (real->str[i])) + break; + + ++i; + } + + _dbus_assert (i == real->len || !DBUS_IS_ASCII_WHITE (real->str[i])); + + if (end) + *end = i; +} + + +/** + * Skips whitespace from start, storing the first non-whitespace in *end. + * (whitespace is space, tab, newline, CR). + * + * @param str the string + * @param start where to start + * @param end where to store the first non-whitespace byte index + */ +void +_dbus_string_skip_white (const DBusString *str, + int start, + int *end) +{ + int i; + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start <= real->len); + _dbus_assert (start >= 0); + + i = start; + while (i < real->len) + { + if (!DBUS_IS_ASCII_WHITE (real->str[i])) + break; + + ++i; + } + + _dbus_assert (i == real->len || !(DBUS_IS_ASCII_WHITE (real->str[i]))); + + if (end) + *end = i; +} + +/** + * Skips whitespace from end, storing the start index of the trailing + * whitespace in *start. (whitespace is space, tab, newline, CR). + * + * @param str the string + * @param end where to start scanning backward + * @param start where to store the start of whitespace chars + */ +void +_dbus_string_skip_white_reverse (const DBusString *str, + int end, + int *start) +{ + int i; + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (end <= real->len); + _dbus_assert (end >= 0); + + i = end; + while (i > 0) + { + if (!DBUS_IS_ASCII_WHITE (real->str[i-1])) + break; + --i; + } + + _dbus_assert (i >= 0 && (i == 0 || !(DBUS_IS_ASCII_WHITE (real->str[i-1])))); + + if (start) + *start = i; +} + +/** + * Assigns a newline-terminated or \\r\\n-terminated line from the front + * of the string to the given dest string. The dest string's previous + * contents are deleted. If the source string contains no newline, + * moves the entire source string to the dest string. + * + * @todo owen correctly notes that this is a stupid function (it was + * written purely for test code, + * e.g. dbus-message-builder.c). Probably should be enforced as test + * code only with ifdef DBUS_BUILD_TESTS + * + * @param source the source string + * @param dest the destination string (contents are replaced) + * @returns #FALSE if no memory, or source has length 0 + */ +dbus_bool_t +_dbus_string_pop_line (DBusString *source, + DBusString *dest) +{ + int eol, eol_len; + + _dbus_string_set_length (dest, 0); + + eol = 0; + eol_len = 0; + if (!_dbus_string_find_eol (source, 0, &eol, &eol_len)) + { + _dbus_assert (eol == _dbus_string_get_length (source)); + if (eol == 0) + { + /* If there's no newline and source has zero length, we're done */ + return FALSE; + } + /* otherwise, the last line of the file has no eol characters */ + } + + /* remember eol can be 0 if it's an empty line, but eol_len should not be zero also + * since find_eol returned TRUE + */ + + if (!_dbus_string_move_len (source, 0, eol + eol_len, dest, 0)) + return FALSE; + + /* remove line ending */ + if (!_dbus_string_set_length (dest, eol)) + { + _dbus_assert_not_reached ("out of memory when shortening a string"); + return FALSE; + } + + return TRUE; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Deletes up to and including the first blank space + * in the string. + * + * @param str the string + */ +void +_dbus_string_delete_first_word (DBusString *str) +{ + int i; + + if (_dbus_string_find_blank (str, 0, &i)) + _dbus_string_skip_blank (str, i, &i); + + _dbus_string_delete (str, 0, i); +} +#endif + +#ifdef DBUS_BUILD_TESTS +/** + * Deletes any leading blanks in the string + * + * @param str the string + */ +void +_dbus_string_delete_leading_blanks (DBusString *str) +{ + int i; + + _dbus_string_skip_blank (str, 0, &i); + + if (i > 0) + _dbus_string_delete (str, 0, i); +} +#endif + +/** + * Deletes leading and trailing whitespace + * + * @param str the string + */ +void +_dbus_string_chop_white(DBusString *str) +{ + int i; + + _dbus_string_skip_white (str, 0, &i); + + if (i > 0) + _dbus_string_delete (str, 0, i); + + _dbus_string_skip_white_reverse (str, _dbus_string_get_length (str), &i); + + _dbus_string_set_length (str, i); +} + +/** + * Tests two DBusString for equality. + * + * @todo memcmp is probably faster + * + * @param a first string + * @param b second string + * @returns #TRUE if equal + */ +dbus_bool_t +_dbus_string_equal (const DBusString *a, + const DBusString *b) +{ + const unsigned char *ap; + const unsigned char *bp; + const unsigned char *a_end; + const DBusRealString *real_a = (const DBusRealString*) a; + const DBusRealString *real_b = (const DBusRealString*) b; + DBUS_GENERIC_STRING_PREAMBLE (real_a); + DBUS_GENERIC_STRING_PREAMBLE (real_b); + + if (real_a->len != real_b->len) + return FALSE; + + ap = real_a->str; + bp = real_b->str; + a_end = real_a->str + real_a->len; + while (ap != a_end) + { + if (*ap != *bp) + return FALSE; + + ++ap; + ++bp; + } + + return TRUE; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Tests two DBusString for equality up to the given length. + * The strings may be shorter than the given length. + * + * @todo write a unit test + * + * @todo memcmp is probably faster + * + * @param a first string + * @param b second string + * @param len the maximum length to look at + * @returns #TRUE if equal for the given number of bytes + */ +dbus_bool_t +_dbus_string_equal_len (const DBusString *a, + const DBusString *b, + int len) +{ + const unsigned char *ap; + const unsigned char *bp; + const unsigned char *a_end; + const DBusRealString *real_a = (const DBusRealString*) a; + const DBusRealString *real_b = (const DBusRealString*) b; + DBUS_GENERIC_STRING_PREAMBLE (real_a); + DBUS_GENERIC_STRING_PREAMBLE (real_b); + + if (real_a->len != real_b->len && + (real_a->len < len || real_b->len < len)) + return FALSE; + + ap = real_a->str; + bp = real_b->str; + a_end = real_a->str + MIN (real_a->len, len); + while (ap != a_end) + { + if (*ap != *bp) + return FALSE; + + ++ap; + ++bp; + } + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Tests two sub-parts of two DBusString for equality. The specified + * range of the first string must exist; the specified start position + * of the second string must exist. + * + * @todo write a unit test + * + * @todo memcmp is probably faster + * + * @param a first string + * @param a_start where to start substring in first string + * @param a_len length of substring in first string + * @param b second string + * @param b_start where to start substring in second string + * @returns #TRUE if the two substrings are equal + */ +dbus_bool_t +_dbus_string_equal_substring (const DBusString *a, + int a_start, + int a_len, + const DBusString *b, + int b_start) +{ + const unsigned char *ap; + const unsigned char *bp; + const unsigned char *a_end; + const DBusRealString *real_a = (const DBusRealString*) a; + const DBusRealString *real_b = (const DBusRealString*) b; + DBUS_GENERIC_STRING_PREAMBLE (real_a); + DBUS_GENERIC_STRING_PREAMBLE (real_b); + _dbus_assert (a_start >= 0); + _dbus_assert (a_len >= 0); + _dbus_assert (a_start <= real_a->len); + _dbus_assert (a_len <= real_a->len - a_start); + _dbus_assert (b_start >= 0); + _dbus_assert (b_start <= real_b->len); + + if (a_len > real_b->len - b_start) + return FALSE; + + ap = real_a->str + a_start; + bp = real_b->str + b_start; + a_end = ap + a_len; + while (ap != a_end) + { + if (*ap != *bp) + return FALSE; + + ++ap; + ++bp; + } + + _dbus_assert (bp <= (real_b->str + real_b->len)); + + return TRUE; +} + +/** + * Checks whether a string is equal to a C string. + * + * @param a the string + * @param c_str the C string + * @returns #TRUE if equal + */ +dbus_bool_t +_dbus_string_equal_c_str (const DBusString *a, + const char *c_str) +{ + const unsigned char *ap; + const unsigned char *bp; + const unsigned char *a_end; + const DBusRealString *real_a = (const DBusRealString*) a; + DBUS_GENERIC_STRING_PREAMBLE (real_a); + _dbus_assert (c_str != NULL); + + ap = real_a->str; + bp = (const unsigned char*) c_str; + a_end = real_a->str + real_a->len; + while (ap != a_end && *bp) + { + if (*ap != *bp) + return FALSE; + + ++ap; + ++bp; + } + + if (ap != a_end || *bp) + return FALSE; + + return TRUE; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Checks whether a string starts with the given C string. + * + * @param a the string + * @param c_str the C string + * @returns #TRUE if string starts with it + */ +dbus_bool_t +_dbus_string_starts_with_c_str (const DBusString *a, + const char *c_str) +{ + const unsigned char *ap; + const unsigned char *bp; + const unsigned char *a_end; + const DBusRealString *real_a = (const DBusRealString*) a; + DBUS_GENERIC_STRING_PREAMBLE (real_a); + _dbus_assert (c_str != NULL); + + ap = real_a->str; + bp = (const unsigned char*) c_str; + a_end = real_a->str + real_a->len; + while (ap != a_end && *bp) + { + if (*ap != *bp) + return FALSE; + + ++ap; + ++bp; + } + + if (*bp == '\0') + return TRUE; + else + return FALSE; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Appends a two-character hex digit to a string, where the hex digit + * has the value of the given byte. + * + * @param str the string + * @param byte the byte + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_string_append_byte_as_hex (DBusString *str, + int byte) +{ + const char hexdigits[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' + }; + + if (!_dbus_string_append_byte (str, + hexdigits[(byte >> 4)])) + return FALSE; + + if (!_dbus_string_append_byte (str, + hexdigits[(byte & 0x0f)])) + { + _dbus_string_set_length (str, + _dbus_string_get_length (str) - 1); + return FALSE; + } + + return TRUE; +} + +/** + * Encodes a string in hex, the way MD5 and SHA-1 are usually + * encoded. (Each byte is two hex digits.) + * + * @param source the string to encode + * @param start byte index to start encoding + * @param dest string where encoded data should be placed + * @param insert_at where to place encoded data + * @returns #TRUE if encoding was successful, #FALSE if no memory etc. + */ +dbus_bool_t +_dbus_string_hex_encode (const DBusString *source, + int start, + DBusString *dest, + int insert_at) +{ + DBusString result; + const unsigned char *p; + const unsigned char *end; + dbus_bool_t retval; + + _dbus_assert (start <= _dbus_string_get_length (source)); + + if (!_dbus_string_init (&result)) + return FALSE; + + retval = FALSE; + + p = (const unsigned char*) _dbus_string_get_const_data (source); + end = p + _dbus_string_get_length (source); + p += start; + + while (p != end) + { + if (!_dbus_string_append_byte_as_hex (&result, *p)) + goto out; + + ++p; + } + + if (!_dbus_string_move (&result, 0, dest, insert_at)) + goto out; + + retval = TRUE; + + out: + _dbus_string_free (&result); + return retval; +} + +/** + * Decodes a string from hex encoding. + * + * @param source the string to decode + * @param start byte index to start decode + * @param end_return return location of the end of the hex data, or #NULL + * @param dest string where decoded data should be placed + * @param insert_at where to place decoded data + * @returns #TRUE if decoding was successful, #FALSE if no memory. + */ +dbus_bool_t +_dbus_string_hex_decode (const DBusString *source, + int start, + int *end_return, + DBusString *dest, + int insert_at) +{ + DBusString result; + const unsigned char *p; + const unsigned char *end; + dbus_bool_t retval; + dbus_bool_t high_bits; + + _dbus_assert (start <= _dbus_string_get_length (source)); + + if (!_dbus_string_init (&result)) + return FALSE; + + retval = FALSE; + + high_bits = TRUE; + p = (const unsigned char*) _dbus_string_get_const_data (source); + end = p + _dbus_string_get_length (source); + p += start; + + while (p != end) + { + unsigned int val; + + switch (*p) + { + case '0': + val = 0; + break; + case '1': + val = 1; + break; + case '2': + val = 2; + break; + case '3': + val = 3; + break; + case '4': + val = 4; + break; + case '5': + val = 5; + break; + case '6': + val = 6; + break; + case '7': + val = 7; + break; + case '8': + val = 8; + break; + case '9': + val = 9; + break; + case 'a': + case 'A': + val = 10; + break; + case 'b': + case 'B': + val = 11; + break; + case 'c': + case 'C': + val = 12; + break; + case 'd': + case 'D': + val = 13; + break; + case 'e': + case 'E': + val = 14; + break; + case 'f': + case 'F': + val = 15; + break; + default: + goto done; + } + + if (high_bits) + { + if (!_dbus_string_append_byte (&result, + val << 4)) + goto out; + } + else + { + int len; + unsigned char b; + + len = _dbus_string_get_length (&result); + + b = _dbus_string_get_byte (&result, len - 1); + + b |= val; + + _dbus_string_set_byte (&result, len - 1, b); + } + + high_bits = !high_bits; + + ++p; + } + + done: + if (!_dbus_string_move (&result, 0, dest, insert_at)) + goto out; + + if (end_return) + *end_return = p - (const unsigned char*) _dbus_string_get_const_data (source); + + retval = TRUE; + + out: + _dbus_string_free (&result); + return retval; +} + +/** + * Checks that the given range of the string is valid ASCII with no + * nul bytes. If the given range is not entirely contained in the + * string, returns #FALSE. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is all valid ASCII + */ +dbus_bool_t +_dbus_string_validate_ascii (const DBusString *str, + int start, + int len) +{ + const unsigned char *s; + const unsigned char *end; + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start >= 0); + _dbus_assert (start <= real->len); + _dbus_assert (len >= 0); + + if (len > real->len - start) + return FALSE; + + s = real->str + start; + end = s + len; + while (s != end) + { + if (_DBUS_UNLIKELY (!_DBUS_ISASCII (*s))) + return FALSE; + + ++s; + } + + return TRUE; +} + +/** + * Checks that the given range of the string is valid UTF-8. If the + * given range is not entirely contained in the string, returns + * #FALSE. If the string contains any nul bytes in the given range, + * returns #FALSE. If the start and start+len are not on character + * boundaries, returns #FALSE. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is all valid UTF-8 + */ +dbus_bool_t +_dbus_string_validate_utf8 (const DBusString *str, + int start, + int len) +{ + const unsigned char *p; + const unsigned char *end; + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start >= 0); + _dbus_assert (start <= real->len); + _dbus_assert (len >= 0); + + /* we are doing _DBUS_UNLIKELY() here which might be + * dubious in a generic library like GLib, but in D-Bus + * we know we're validating messages and that it would + * only be evil/broken apps that would have invalid + * UTF-8. Also, this function seems to be a performance + * bottleneck in profiles. + */ + + if (_DBUS_UNLIKELY (len > real->len - start)) + return FALSE; + + p = real->str + start; + end = p + len; + + while (p < end) + { + int i, mask, char_len; + dbus_unichar_t result; + + /* nul bytes considered invalid */ + if (*p == '\0') + break; + + /* Special-case ASCII; this makes us go a lot faster in + * D-Bus profiles where we are typically validating + * function names and such. We have to know that + * all following checks will pass for ASCII though, + * comments follow ... + */ + if (*p < 128) + { + ++p; + continue; + } + + UTF8_COMPUTE (*p, mask, char_len); + + if (_DBUS_UNLIKELY (char_len == 0)) /* ASCII: char_len == 1 */ + break; + + /* check that the expected number of bytes exists in the remaining length */ + if (_DBUS_UNLIKELY ((end - p) < char_len)) /* ASCII: p < end and char_len == 1 */ + break; + + UTF8_GET (result, p, i, mask, char_len); + + /* Check for overlong UTF-8 */ + if (_DBUS_UNLIKELY (UTF8_LENGTH (result) != char_len)) /* ASCII: UTF8_LENGTH == 1 */ + break; +#if 0 + /* The UNICODE_VALID check below will catch this */ + if (_DBUS_UNLIKELY (result == (dbus_unichar_t)-1)) /* ASCII: result = ascii value */ + break; +#endif + + if (_DBUS_UNLIKELY (!UNICODE_VALID (result))) /* ASCII: always valid */ + break; + + /* UNICODE_VALID should have caught it */ + _dbus_assert (result != (dbus_unichar_t)-1); + + p += char_len; + } + + /* See that we covered the entire length if a length was + * passed in + */ + if (_DBUS_UNLIKELY (p != end)) + return FALSE; + else + return TRUE; +} + +/** + * Checks that the given range of the string is all nul bytes. If the + * given range is not entirely contained in the string, returns + * #FALSE. + * + * @todo this is inconsistent with most of DBusString in that + * it allows a start,len range that extends past the string end. + * + * @param str the string + * @param start first byte index to check + * @param len number of bytes to check + * @returns #TRUE if the byte range exists and is all nul bytes + */ +dbus_bool_t +_dbus_string_validate_nul (const DBusString *str, + int start, + int len) +{ + const unsigned char *s; + const unsigned char *end; + DBUS_CONST_STRING_PREAMBLE (str); + _dbus_assert (start >= 0); + _dbus_assert (len >= 0); + _dbus_assert (start <= real->len); + + if (len > real->len - start) + return FALSE; + + s = real->str + start; + end = s + len; + while (s != end) + { + if (_DBUS_UNLIKELY (*s != '\0')) + return FALSE; + ++s; + } + + return TRUE; +} + +/** + * Clears all allocated bytes in the string to zero. + * + * @param str the string + */ +void +_dbus_string_zero (DBusString *str) +{ + DBUS_STRING_PREAMBLE (str); + + memset (real->str - real->align_offset, '\0', real->allocated); +} +/** @} */ + +/* tests are in dbus-string-util.c */ diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h new file mode 100644 index 00000000..b1850274 --- /dev/null +++ b/dbus/dbus-string.h @@ -0,0 +1,321 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-string.h String utility class (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2003 Red Hat, Inc. + * Copyright (C) 2006 Ralf Habacker + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_STRING_H +#define DBUS_STRING_H + +#include + +#include +#include +#include + +#include + +DBUS_BEGIN_DECLS + +/** + * DBusString object + */ +struct DBusString +{ + const void *dummy1; /**< placeholder */ + int dummy2; /**< placeholder */ + int dummy3; /**< placeholder */ + int dummy4; /**< placeholder */ + unsigned int dummy5 : 1; /**< placeholder */ + unsigned int dummy6 : 1; /**< placeholder */ + unsigned int dummy7 : 1; /**< placeholder */ + unsigned int dummy8 : 3; /**< placeholder */ +}; + +#ifdef DBUS_DISABLE_ASSERT +/* Some simple inlining hacks; the current linker is not smart enough + * to inline non-exported symbols across files in the library. + * Note that these break type safety (due to the casts) + */ +#define _dbus_string_get_data(s) ((char*)(((DBusString*)(s))->dummy1)) +#define _dbus_string_get_length(s) (((DBusString*)(s))->dummy2) +#define _dbus_string_set_byte(s, i, b) ((((unsigned char*)(((DBusString*)(s))->dummy1))[(i)]) = (unsigned char) (b)) +#define _dbus_string_get_byte(s, i) (((const unsigned char*)(((DBusString*)(s))->dummy1))[(i)]) +#define _dbus_string_get_const_data(s) ((const char*)(((DBusString*)(s))->dummy1)) +#define _dbus_string_get_const_data_len(s,start,len) (((const char*)(((DBusString*)(s))->dummy1)) + (start)) +#endif + +dbus_bool_t _dbus_string_init (DBusString *str); +void _dbus_string_init_const (DBusString *str, + const char *value); +void _dbus_string_init_const_len (DBusString *str, + const char *value, + int len); +dbus_bool_t _dbus_string_init_preallocated (DBusString *str, + int allocate_size); +void _dbus_string_free (DBusString *str); +void _dbus_string_lock (DBusString *str); +dbus_bool_t _dbus_string_compact (DBusString *str, + int max_waste); +#ifndef _dbus_string_get_data +char* _dbus_string_get_data (DBusString *str); +#endif /* _dbus_string_get_data */ +#ifndef _dbus_string_get_const_data +const char* _dbus_string_get_const_data (const DBusString *str); +#endif /* _dbus_string_get_const_data */ +char* _dbus_string_get_data_len (DBusString *str, + int start, + int len); +#ifndef _dbus_string_get_const_data_len +const char* _dbus_string_get_const_data_len (const DBusString *str, + int start, + int len); +#endif +#ifndef _dbus_string_set_byte +void _dbus_string_set_byte (DBusString *str, + int i, + unsigned char byte); +#endif +#ifndef _dbus_string_get_byte +unsigned char _dbus_string_get_byte (const DBusString *str, + int start); +#endif /* _dbus_string_get_byte */ +dbus_bool_t _dbus_string_insert_bytes (DBusString *str, + int i, + int n_bytes, + unsigned char byte); +dbus_bool_t _dbus_string_insert_byte (DBusString *str, + int i, + unsigned char byte); +dbus_bool_t _dbus_string_steal_data (DBusString *str, + char **data_return); +dbus_bool_t _dbus_string_steal_data_len (DBusString *str, + char **data_return, + int start, + int len); +dbus_bool_t _dbus_string_copy_data (const DBusString *str, + char **data_return); +dbus_bool_t _dbus_string_copy_data_len (const DBusString *str, + char **data_return, + int start, + int len); +void _dbus_string_copy_to_buffer (const DBusString *str, + char *buffer, + int len); +void _dbus_string_copy_to_buffer_with_nul (const DBusString *str, + char *buffer, + int avail_len); +#ifndef _dbus_string_get_length +int _dbus_string_get_length (const DBusString *str); +#endif /* !_dbus_string_get_length */ + +dbus_bool_t _dbus_string_lengthen (DBusString *str, + int additional_length); +void _dbus_string_shorten (DBusString *str, + int length_to_remove); +dbus_bool_t _dbus_string_set_length (DBusString *str, + int length); +dbus_bool_t _dbus_string_align_length (DBusString *str, + int alignment); +dbus_bool_t _dbus_string_alloc_space (DBusString *str, + int extra_bytes); +dbus_bool_t _dbus_string_append (DBusString *str, + const char *buffer); +dbus_bool_t _dbus_string_append_len (DBusString *str, + const char *buffer, + int len); +dbus_bool_t _dbus_string_append_int (DBusString *str, + long value); +dbus_bool_t _dbus_string_append_uint (DBusString *str, + unsigned long value); +dbus_bool_t _dbus_string_append_double (DBusString *str, + double value); +dbus_bool_t _dbus_string_append_byte (DBusString *str, + unsigned char byte); +dbus_bool_t _dbus_string_append_unichar (DBusString *str, + dbus_unichar_t ch); +dbus_bool_t _dbus_string_append_4_aligned (DBusString *str, + const unsigned char octets[4]); +dbus_bool_t _dbus_string_append_8_aligned (DBusString *str, + const unsigned char octets[8]); +dbus_bool_t _dbus_string_append_printf (DBusString *str, + const char *format, + ...) _DBUS_GNUC_PRINTF (2, 3); +dbus_bool_t _dbus_string_append_printf_valist (DBusString *str, + const char *format, + va_list args); +dbus_bool_t _dbus_string_insert_2_aligned (DBusString *str, + int insert_at, + const unsigned char octets[2]); +dbus_bool_t _dbus_string_insert_4_aligned (DBusString *str, + int insert_at, + const unsigned char octets[4]); +dbus_bool_t _dbus_string_insert_8_aligned (DBusString *str, + int insert_at, + const unsigned char octets[8]); +dbus_bool_t _dbus_string_insert_alignment (DBusString *str, + int *insert_at, + int alignment); +void _dbus_string_delete (DBusString *str, + int start, + int len); +dbus_bool_t _dbus_string_move (DBusString *source, + int start, + DBusString *dest, + int insert_at); +dbus_bool_t _dbus_string_copy (const DBusString *source, + int start, + DBusString *dest, + int insert_at); +dbus_bool_t _dbus_string_move_len (DBusString *source, + int start, + int len, + DBusString *dest, + int insert_at); +dbus_bool_t _dbus_string_copy_len (const DBusString *source, + int start, + int len, + DBusString *dest, + int insert_at); +dbus_bool_t _dbus_string_replace_len (const DBusString *source, + int start, + int len, + DBusString *dest, + int replace_at, + int replace_len); +dbus_bool_t _dbus_string_split_on_byte (DBusString *source, + unsigned char byte, + DBusString *tail); +void _dbus_string_get_unichar (const DBusString *str, + int start, + dbus_unichar_t *ch_return, + int *end_return); +dbus_bool_t _dbus_string_parse_int (const DBusString *str, + int start, + long *value_return, + int *end_return); +dbus_bool_t _dbus_string_parse_uint (const DBusString *str, + int start, + unsigned long *value_return, + int *end_return); +dbus_bool_t _dbus_string_parse_double (const DBusString *str, + int start, + double *value, + int *end_return); +dbus_bool_t _dbus_string_find (const DBusString *str, + int start, + const char *substr, + int *found); +dbus_bool_t _dbus_string_find_eol (const DBusString *str, + int start, + int *found, + int *found_len); +dbus_bool_t _dbus_string_find_to (const DBusString *str, + int start, + int end, + const char *substr, + int *found); +dbus_bool_t _dbus_string_find_byte_backward (const DBusString *str, + int start, + unsigned char byte, + int *found); +dbus_bool_t _dbus_string_find_blank (const DBusString *str, + int start, + int *found); +void _dbus_string_skip_blank (const DBusString *str, + int start, + int *end); +void _dbus_string_skip_white (const DBusString *str, + int start, + int *end); +void _dbus_string_skip_white_reverse (const DBusString *str, + int end, + int *start); +dbus_bool_t _dbus_string_equal (const DBusString *a, + const DBusString *b); +dbus_bool_t _dbus_string_equal_c_str (const DBusString *a, + const char *c_str); +dbus_bool_t _dbus_string_equal_len (const DBusString *a, + const DBusString *b, + int len); +dbus_bool_t _dbus_string_equal_substring (const DBusString *a, + int a_start, + int a_len, + const DBusString *b, + int b_start); +dbus_bool_t _dbus_string_starts_with_c_str (const DBusString *a, + const char *c_str); +dbus_bool_t _dbus_string_ends_with_c_str (const DBusString *a, + const char *c_str); +dbus_bool_t _dbus_string_pop_line (DBusString *source, + DBusString *dest); +void _dbus_string_delete_first_word (DBusString *str); +void _dbus_string_delete_leading_blanks (DBusString *str); +void _dbus_string_chop_white (DBusString *str); +dbus_bool_t _dbus_string_append_byte_as_hex (DBusString *str, + int byte); +dbus_bool_t _dbus_string_hex_encode (const DBusString *source, + int start, + DBusString *dest, + int insert_at); +dbus_bool_t _dbus_string_hex_decode (const DBusString *source, + int start, + int *end_return, + DBusString *dest, + int insert_at); +dbus_bool_t _dbus_string_validate_ascii (const DBusString *str, + int start, + int len); +dbus_bool_t _dbus_string_validate_utf8 (const DBusString *str, + int start, + int len); +dbus_bool_t _dbus_string_validate_nul (const DBusString *str, + int start, + int len); +void _dbus_string_zero (DBusString *str); + + +/** + * We allocate 1 byte for nul termination, plus 7 bytes for possible + * align_offset, so we always need 8 bytes on top of the string's + * length to be in the allocated block. + */ +#define _DBUS_STRING_ALLOCATION_PADDING 8 + +/** + * Defines a static const variable with type #DBusString called "name" + * containing the given string literal. + * + * @param name the name of the variable + * @param str the string value + */ +#define _DBUS_STRING_DEFINE_STATIC(name, str) \ + static const char _dbus_static_string_##name[] = str; \ + static const DBusString name = { _dbus_static_string_##name, \ + sizeof(_dbus_static_string_##name), \ + sizeof(_dbus_static_string_##name) + \ + _DBUS_STRING_ALLOCATION_PADDING, \ + sizeof(_dbus_static_string_##name), \ + TRUE, TRUE, FALSE, 0 } + +DBUS_END_DECLS + +#endif /* DBUS_STRING_H */ diff --git a/dbus/dbus-sysdeps-pthread.c b/dbus/dbus-sysdeps-pthread.c new file mode 100644 index 00000000..46e4204d --- /dev/null +++ b/dbus/dbus-sysdeps-pthread.c @@ -0,0 +1,363 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-sysdeps-pthread.c Implements threads using pthreads (internal to libdbus) + * + * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-sysdeps.h" +#include "dbus-threads.h" + +#include +#include +#include + +#ifdef HAVE_ERRNO_H +#include +#endif + +#include + +/* Whether we have a "monotonic" clock; i.e. a clock not affected by + * changes in system time. + * This is initialized once in check_monotonic_clock below. + * https://bugs.freedesktop.org/show_bug.cgi?id=18121 + */ +static dbus_bool_t have_monotonic_clock = 0; + +typedef struct { + pthread_mutex_t lock; /**< lock protecting count field */ + volatile int count; /**< count of how many times lock holder has recursively locked */ + volatile pthread_t holder; /**< holder of the lock if count >0, + valid but arbitrary thread if count + has ever been >0, uninitialized memory + if count has never been >0 */ +} DBusMutexPThread; + +typedef struct { + pthread_cond_t cond; /**< the condition */ +} DBusCondVarPThread; + +#define DBUS_MUTEX(m) ((DBusMutex*) m) +#define DBUS_MUTEX_PTHREAD(m) ((DBusMutexPThread*) m) + +#define DBUS_COND_VAR(c) ((DBusCondVar*) c) +#define DBUS_COND_VAR_PTHREAD(c) ((DBusCondVarPThread*) c) + + +#ifdef DBUS_DISABLE_ASSERT +/* (tmp != 0) is a no-op usage to silence compiler */ +#define PTHREAD_CHECK(func_name, result_or_call) \ + do { int tmp = (result_or_call); if (tmp != 0) {;} } while (0) +#else +#define PTHREAD_CHECK(func_name, result_or_call) do { \ + int tmp = (result_or_call); \ + if (tmp != 0) { \ + _dbus_warn_check_failed ("pthread function %s failed with %d %s in %s\n", \ + func_name, tmp, strerror(tmp), _DBUS_FUNCTION_NAME); \ + } \ +} while (0) +#endif /* !DBUS_DISABLE_ASSERT */ + +static DBusMutex* +_dbus_pthread_mutex_new (void) +{ + DBusMutexPThread *pmutex; + int result; + + pmutex = dbus_new (DBusMutexPThread, 1); + if (pmutex == NULL) + return NULL; + + result = pthread_mutex_init (&pmutex->lock, NULL); + + if (result == ENOMEM || result == EAGAIN) + { + dbus_free (pmutex); + return NULL; + } + else + { + PTHREAD_CHECK ("pthread_mutex_init", result); + } + + /* Only written */ + pmutex->count = 0; + + /* There's no portable way to have a "null" pthread afaik so we + * can't set pmutex->holder to anything sensible. We only access it + * once the lock is held (which means we've set it). + */ + + return DBUS_MUTEX (pmutex); +} + +static void +_dbus_pthread_mutex_free (DBusMutex *mutex) +{ + DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex); + + _dbus_assert (pmutex->count == 0); + + PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&pmutex->lock)); + + dbus_free (pmutex); +} + +static void +_dbus_pthread_mutex_lock (DBusMutex *mutex) +{ + DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex); + pthread_t self = pthread_self (); + + /* If the count is > 0 then someone had the lock, maybe us. If it is + * 0, then it might immediately change right after we read it, + * but it will be changed by another thread; i.e. if we read 0, + * we assume that this thread doesn't have the lock. + * + * Not 100% sure this is safe, but ... seems like it should be. + */ + if (pmutex->count == 0) + { + /* We know we don't have the lock; someone may have the lock. */ + + PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&pmutex->lock)); + + /* We now have the lock. Count must be 0 since it must be 0 when + * the lock is released by another thread, and we just now got + * the lock. + */ + _dbus_assert (pmutex->count == 0); + + pmutex->holder = self; + pmutex->count = 1; + } + else + { + /* We know someone had the lock, possibly us. Thus + * pmutex->holder is not pointing to junk, though it may not be + * the lock holder anymore if the lock holder is not us. If the + * lock holder is us, then we definitely have the lock. + */ + + if (pthread_equal (pmutex->holder, self)) + { + /* We already have the lock. */ + _dbus_assert (pmutex->count > 0); + } + else + { + /* Wait for the lock */ + PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&pmutex->lock)); + pmutex->holder = self; + _dbus_assert (pmutex->count == 0); + } + + pmutex->count += 1; + } +} + +static void +_dbus_pthread_mutex_unlock (DBusMutex *mutex) +{ + DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex); + + _dbus_assert (pmutex->count > 0); + + pmutex->count -= 1; + + if (pmutex->count == 0) + PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&pmutex->lock)); + + /* We leave pmutex->holder set to ourselves, its content is undefined if count is 0 */ +} + +static DBusCondVar * +_dbus_pthread_condvar_new (void) +{ + DBusCondVarPThread *pcond; + pthread_condattr_t attr; + int result; + + pcond = dbus_new (DBusCondVarPThread, 1); + if (pcond == NULL) + return NULL; + + pthread_condattr_init (&attr); +#ifdef HAVE_MONOTONIC_CLOCK + if (have_monotonic_clock) + pthread_condattr_setclock (&attr, CLOCK_MONOTONIC); +#endif + + result = pthread_cond_init (&pcond->cond, &attr); + pthread_condattr_destroy (&attr); + + if (result == EAGAIN || result == ENOMEM) + { + dbus_free (pcond); + return NULL; + } + else + { + PTHREAD_CHECK ("pthread_cond_init", result); + } + + return DBUS_COND_VAR (pcond); +} + +static void +_dbus_pthread_condvar_free (DBusCondVar *cond) +{ + DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond); + + PTHREAD_CHECK ("pthread_cond_destroy", pthread_cond_destroy (&pcond->cond)); + + dbus_free (pcond); +} + +static void +_dbus_pthread_condvar_wait (DBusCondVar *cond, + DBusMutex *mutex) +{ + DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex); + DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond); + int old_count; + + _dbus_assert (pmutex->count > 0); + _dbus_assert (pthread_equal (pmutex->holder, pthread_self ())); + + old_count = pmutex->count; + pmutex->count = 0; /* allow other threads to lock */ + PTHREAD_CHECK ("pthread_cond_wait", pthread_cond_wait (&pcond->cond, &pmutex->lock)); + _dbus_assert (pmutex->count == 0); + pmutex->count = old_count; + pmutex->holder = pthread_self(); /* other threads may have locked the mutex in the meantime */ +} + +static dbus_bool_t +_dbus_pthread_condvar_wait_timeout (DBusCondVar *cond, + DBusMutex *mutex, + int timeout_milliseconds) +{ + DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex); + DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond); + struct timeval time_now; + struct timespec end_time; + int result; + int old_count; + + _dbus_assert (pmutex->count > 0); + _dbus_assert (pthread_equal (pmutex->holder, pthread_self ())); + +#ifdef HAVE_MONOTONIC_CLOCK + if (have_monotonic_clock) + { + struct timespec monotonic_timer; + clock_gettime (CLOCK_MONOTONIC,&monotonic_timer); + time_now.tv_sec = monotonic_timer.tv_sec; + time_now.tv_usec = monotonic_timer.tv_nsec / 1000; + } + else + /* This else falls through to gettimeofday */ +#endif + gettimeofday (&time_now, NULL); + + end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000; + end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000; + if (end_time.tv_nsec > 1000*1000*1000) + { + end_time.tv_sec += 1; + end_time.tv_nsec -= 1000*1000*1000; + } + + old_count = pmutex->count; + pmutex->count = 0; + result = pthread_cond_timedwait (&pcond->cond, &pmutex->lock, &end_time); + + if (result != ETIMEDOUT) + { + PTHREAD_CHECK ("pthread_cond_timedwait", result); + } + + _dbus_assert (pmutex->count == 0); + pmutex->count = old_count; + pmutex->holder = pthread_self(); /* other threads may have locked the mutex in the meantime */ + + /* return true if we did not time out */ + return result != ETIMEDOUT; +} + +static void +_dbus_pthread_condvar_wake_one (DBusCondVar *cond) +{ + DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond); + + PTHREAD_CHECK ("pthread_cond_signal", pthread_cond_signal (&pcond->cond)); +} + +static void +_dbus_pthread_condvar_wake_all (DBusCondVar *cond) +{ + DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond); + + PTHREAD_CHECK ("pthread_cond_broadcast", pthread_cond_broadcast (&pcond->cond)); +} + +static const DBusThreadFunctions pthread_functions = +{ + DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK | + DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK | + DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK | + DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK| + DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK, + NULL, NULL, NULL, NULL, + _dbus_pthread_condvar_new, + _dbus_pthread_condvar_free, + _dbus_pthread_condvar_wait, + _dbus_pthread_condvar_wait_timeout, + _dbus_pthread_condvar_wake_one, + _dbus_pthread_condvar_wake_all, + _dbus_pthread_mutex_new, + _dbus_pthread_mutex_free, + _dbus_pthread_mutex_lock, + _dbus_pthread_mutex_unlock +}; + +static void +check_monotonic_clock (void) +{ +#ifdef HAVE_MONOTONIC_CLOCK + struct timespec dummy; + if (clock_getres (CLOCK_MONOTONIC, &dummy) == 0) + have_monotonic_clock = TRUE; +#endif +} + +dbus_bool_t +_dbus_threads_init_platform_specific (void) +{ + check_monotonic_clock (); + return dbus_threads_init (&pthread_functions); +} diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c new file mode 100644 index 00000000..ce3475a6 --- /dev/null +++ b/dbus/dbus-sysdeps-unix.c @@ -0,0 +1,3495 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-sysdeps-unix.c Wrappers around UNIX system/libc features (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define _GNU_SOURCE + +#include "dbus-internals.h" +#include "dbus-sysdeps.h" +#include "dbus-sysdeps-unix.h" +#include "dbus-threads.h" +#include "dbus-protocol.h" +#include "dbus-transport.h" +#include "dbus-string.h" +#include "dbus-userdb.h" +#include "dbus-list.h" +#include "dbus-credentials.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_WRITEV +#include +#endif +#ifdef HAVE_POLL +#include +#endif +#ifdef HAVE_BACKTRACE +#include +#endif +#ifdef HAVE_GETPEERUCRED +#include +#endif + +#ifdef HAVE_ADT +#include +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef AI_ADDRCONFIG +#define AI_ADDRCONFIG 0 +#endif + +#ifndef HAVE_SOCKLEN_T +#define socklen_t int +#endif + +static dbus_bool_t +_dbus_open_socket (int *fd_p, + int domain, + int type, + int protocol, + DBusError *error) +{ + *fd_p = socket (domain, type, protocol); + if (*fd_p >= 0) + { + _dbus_verbose ("socket fd %d opened\n", *fd_p); + return TRUE; + } + else + { + dbus_set_error(error, + _dbus_error_from_errno (errno), + "Failed to open socket: %s", + _dbus_strerror (errno)); + return FALSE; + } +} + +dbus_bool_t +_dbus_open_tcp_socket (int *fd, + DBusError *error) +{ + return _dbus_open_socket(fd, AF_INET, SOCK_STREAM, 0, error); +} + +/** + * Opens a UNIX domain socket (as in the socket() call). + * Does not bind the socket. + * @param fd return location for socket descriptor + * @param error return location for an error + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_open_unix_socket (int *fd, + DBusError *error) +{ + return _dbus_open_socket(fd, PF_UNIX, SOCK_STREAM, 0, error); +} + +/** + * Closes a socket. Should not be used on non-socket + * file descriptors or handles. + * + * @param fd the socket + * @param error return location for an error + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_close_socket (int fd, + DBusError *error) +{ + return _dbus_close (fd, error); +} + +/** + * Like _dbus_read(), but only works on sockets so is + * available on Windows. + * + * @param fd the socket + * @param buffer string to append data to + * @param count max amount of data to read + * @returns number of bytes appended to the string + */ +int +_dbus_read_socket (int fd, + DBusString *buffer, + int count) +{ + return _dbus_read (fd, buffer, count); +} + +/** + * Like _dbus_write(), but only supports sockets + * and is thus available on Windows. + * + * @param fd the file descriptor to write + * @param buffer the buffer to write data from + * @param start the first byte in the buffer to write + * @param len the number of bytes to try to write + * @returns the number of bytes written or -1 on error + */ +int +_dbus_write_socket (int fd, + const DBusString *buffer, + int start, + int len) +{ + return _dbus_write (fd, buffer, start, len); +} + +/** + * write data to a pipe. + * + * @param pipe the pipe instance + * @param buffer the buffer to write data from + * @param start the first byte in the buffer to write + * @param len the number of bytes to try to write + * @param error error return + * @returns the number of bytes written or -1 on error + */ +int +_dbus_pipe_write (DBusPipe *pipe, + const DBusString *buffer, + int start, + int len, + DBusError *error) +{ + int written; + + written = _dbus_write (pipe->fd_or_handle, buffer, start, len); + if (written < 0) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Writing to pipe: %s\n", + _dbus_strerror (errno)); + } + return written; +} + +/** + * close a pipe. + * + * @param pipe the pipe instance + * @param error return location for an error + * @returns #FALSE if error is set + */ +int +_dbus_pipe_close (DBusPipe *pipe, + DBusError *error) +{ + if (_dbus_close (pipe->fd_or_handle, error) < 0) + { + return -1; + } + else + { + _dbus_pipe_invalidate (pipe); + return 0; + } +} + +/** + * Like _dbus_write_two() but only works on sockets and is thus + * available on Windows. + * + * @param fd the file descriptor + * @param buffer1 first buffer + * @param start1 first byte to write in first buffer + * @param len1 number of bytes to write from first buffer + * @param buffer2 second buffer, or #NULL + * @param start2 first byte to write in second buffer + * @param len2 number of bytes to write in second buffer + * @returns total bytes written from both buffers, or -1 on error + */ +int +_dbus_write_socket_two (int fd, + const DBusString *buffer1, + int start1, + int len1, + const DBusString *buffer2, + int start2, + int len2) +{ + return _dbus_write_two (fd, buffer1, start1, len1, + buffer2, start2, len2); +} + + +/** + * Thin wrapper around the read() system call that appends + * the data it reads to the DBusString buffer. It appends + * up to the given count, and returns the same value + * and same errno as read(). The only exception is that + * _dbus_read() handles EINTR for you. Also, _dbus_read() can + * return ENOMEM, even though regular UNIX read doesn't. + * + * Unlike _dbus_read_socket(), _dbus_read() is not available + * on Windows. + * + * @param fd the file descriptor to read from + * @param buffer the buffer to append data to + * @param count the amount of data to read + * @returns the number of bytes read or -1 + */ +int +_dbus_read (int fd, + DBusString *buffer, + int count) +{ + int bytes_read; + int start; + char *data; + + _dbus_assert (count >= 0); + + start = _dbus_string_get_length (buffer); + + if (!_dbus_string_lengthen (buffer, count)) + { + errno = ENOMEM; + return -1; + } + + data = _dbus_string_get_data_len (buffer, start, count); + + again: + + bytes_read = read (fd, data, count); + + if (bytes_read < 0) + { + if (errno == EINTR) + goto again; + else + { + /* put length back (note that this doesn't actually realloc anything) */ + _dbus_string_set_length (buffer, start); + return -1; + } + } + else + { + /* put length back (doesn't actually realloc) */ + _dbus_string_set_length (buffer, start + bytes_read); + +#if 0 + if (bytes_read > 0) + _dbus_verbose_bytes_of_string (buffer, start, bytes_read); +#endif + + return bytes_read; + } +} + +/** + * Thin wrapper around the write() system call that writes a part of a + * DBusString and handles EINTR for you. + * + * @param fd the file descriptor to write + * @param buffer the buffer to write data from + * @param start the first byte in the buffer to write + * @param len the number of bytes to try to write + * @returns the number of bytes written or -1 on error + */ +int +_dbus_write (int fd, + const DBusString *buffer, + int start, + int len) +{ + const char *data; + int bytes_written; + + data = _dbus_string_get_const_data_len (buffer, start, len); + + again: + + bytes_written = write (fd, data, len); + + if (bytes_written < 0 && errno == EINTR) + goto again; + +#if 0 + if (bytes_written > 0) + _dbus_verbose_bytes_of_string (buffer, start, bytes_written); +#endif + + return bytes_written; +} + +/** + * Like _dbus_write() but will use writev() if possible + * to write both buffers in sequence. The return value + * is the number of bytes written in the first buffer, + * plus the number written in the second. If the first + * buffer is written successfully and an error occurs + * writing the second, the number of bytes in the first + * is returned (i.e. the error is ignored), on systems that + * don't have writev. Handles EINTR for you. + * The second buffer may be #NULL. + * + * @param fd the file descriptor + * @param buffer1 first buffer + * @param start1 first byte to write in first buffer + * @param len1 number of bytes to write from first buffer + * @param buffer2 second buffer, or #NULL + * @param start2 first byte to write in second buffer + * @param len2 number of bytes to write in second buffer + * @returns total bytes written from both buffers, or -1 on error + */ +int +_dbus_write_two (int fd, + const DBusString *buffer1, + int start1, + int len1, + const DBusString *buffer2, + int start2, + int len2) +{ + _dbus_assert (buffer1 != NULL); + _dbus_assert (start1 >= 0); + _dbus_assert (start2 >= 0); + _dbus_assert (len1 >= 0); + _dbus_assert (len2 >= 0); + +#ifdef HAVE_WRITEV + { + struct iovec vectors[2]; + const char *data1; + const char *data2; + int bytes_written; + + data1 = _dbus_string_get_const_data_len (buffer1, start1, len1); + + if (buffer2 != NULL) + data2 = _dbus_string_get_const_data_len (buffer2, start2, len2); + else + { + data2 = NULL; + start2 = 0; + len2 = 0; + } + + vectors[0].iov_base = (char*) data1; + vectors[0].iov_len = len1; + vectors[1].iov_base = (char*) data2; + vectors[1].iov_len = len2; + + again: + + bytes_written = writev (fd, + vectors, + data2 ? 2 : 1); + + if (bytes_written < 0 && errno == EINTR) + goto again; + + return bytes_written; + } +#else /* HAVE_WRITEV */ + { + int ret1; + + ret1 = _dbus_write (fd, buffer1, start1, len1); + if (ret1 == len1 && buffer2 != NULL) + { + ret2 = _dbus_write (fd, buffer2, start2, len2); + if (ret2 < 0) + ret2 = 0; /* we can't report an error as the first write was OK */ + + return ret1 + ret2; + } + else + return ret1; + } +#endif /* !HAVE_WRITEV */ +} + +#define _DBUS_MAX_SUN_PATH_LENGTH 99 + +/** + * @def _DBUS_MAX_SUN_PATH_LENGTH + * + * Maximum length of the path to a UNIX domain socket, + * sockaddr_un::sun_path member. POSIX requires that all systems + * support at least 100 bytes here, including the nul termination. + * We use 99 for the max value to allow for the nul. + * + * We could probably also do sizeof (addr.sun_path) + * but this way we are the same on all platforms + * which is probably a good idea. + */ + +/** + * Creates a socket and connects it to the UNIX domain socket at the + * given path. The connection fd is returned, and is set up as + * nonblocking. + * + * Uses abstract sockets instead of filesystem-linked sockets if + * requested (it's possible only on Linux; see "man 7 unix" on Linux). + * On non-Linux abstract socket usage always fails. + * + * @param path the path to UNIX domain socket + * @param abstract #TRUE to use abstract namespace + * @param error return location for error code + * @returns connection file descriptor or -1 on error + */ +int +_dbus_connect_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error) +{ + int fd; + size_t path_len; + struct sockaddr_un addr; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_verbose ("connecting to unix socket %s abstract=%d\n", + path, abstract); + + + if (!_dbus_open_unix_socket (&fd, error)) + { + _DBUS_ASSERT_ERROR_IS_SET(error); + return -1; + } + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + + _DBUS_ZERO (addr); + addr.sun_family = AF_UNIX; + path_len = strlen (path); + + if (abstract) + { +#ifdef HAVE_ABSTRACT_SOCKETS + addr.sun_path[0] = '\0'; /* this is what says "use abstract" */ + path_len++; /* Account for the extra nul byte added to the start of sun_path */ + + if (path_len > _DBUS_MAX_SUN_PATH_LENGTH) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Abstract socket name too long\n"); + _dbus_close (fd, NULL); + return -1; + } + + strncpy (&addr.sun_path[1], path, path_len); + /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */ +#else /* HAVE_ABSTRACT_SOCKETS */ + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Operating system does not support abstract socket namespace\n"); + _dbus_close (fd, NULL); + return -1; +#endif /* ! HAVE_ABSTRACT_SOCKETS */ + } + else + { + if (path_len > _DBUS_MAX_SUN_PATH_LENGTH) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Socket name too long\n"); + _dbus_close (fd, NULL); + return -1; + } + + strncpy (addr.sun_path, path, path_len); + } + + if (connect (fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0) + { + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to connect to socket %s: %s", + path, _dbus_strerror (errno)); + + _dbus_close (fd, NULL); + fd = -1; + + return -1; + } + + if (!_dbus_set_fd_nonblocking (fd, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + + _dbus_close (fd, NULL); + fd = -1; + + return -1; + } + + return fd; +} + +/** + * Enables or disables the reception of credentials on the given socket during + * the next message transmission. This is only effective if the #LOCAL_CREDS + * system feature exists, in which case the other side of the connection does + * not have to do anything special to send the credentials. + * + * @param fd socket on which to change the #LOCAL_CREDS flag. + * @param on whether to enable or disable the #LOCAL_CREDS flag. + */ +static dbus_bool_t +_dbus_set_local_creds (int fd, dbus_bool_t on) +{ + dbus_bool_t retval = TRUE; + +#if defined(HAVE_CMSGCRED) + /* NOOP just to make sure only one codepath is used + * and to prefer CMSGCRED + */ +#elif defined(LOCAL_CREDS) + int val = on ? 1 : 0; + if (setsockopt (fd, 0, LOCAL_CREDS, &val, sizeof (val)) < 0) + { + _dbus_verbose ("Unable to set LOCAL_CREDS socket option on fd %d\n", fd); + retval = FALSE; + } + else + _dbus_verbose ("LOCAL_CREDS %s for further messages on fd %d\n", + on ? "enabled" : "disabled", fd); +#endif + + return retval; +} + +/** + * Creates a socket and binds it to the given path, + * then listens on the socket. The socket is + * set to be nonblocking. + * + * Uses abstract sockets instead of filesystem-linked + * sockets if requested (it's possible only on Linux; + * see "man 7 unix" on Linux). + * On non-Linux abstract socket usage always fails. + * + * @param path the socket name + * @param abstract #TRUE to use abstract namespace + * @param error return location for errors + * @returns the listening file descriptor or -1 on error + */ +int +_dbus_listen_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error) +{ + int listen_fd; + struct sockaddr_un addr; + size_t path_len; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_verbose ("listening on unix socket %s abstract=%d\n", + path, abstract); + + if (!_dbus_open_unix_socket (&listen_fd, error)) + { + _DBUS_ASSERT_ERROR_IS_SET(error); + return -1; + } + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + + _DBUS_ZERO (addr); + addr.sun_family = AF_UNIX; + path_len = strlen (path); + + if (abstract) + { +#ifdef HAVE_ABSTRACT_SOCKETS + /* remember that abstract names aren't nul-terminated so we rely + * on sun_path being filled in with zeroes above. + */ + addr.sun_path[0] = '\0'; /* this is what says "use abstract" */ + path_len++; /* Account for the extra nul byte added to the start of sun_path */ + + if (path_len > _DBUS_MAX_SUN_PATH_LENGTH) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Abstract socket name too long\n"); + _dbus_close (listen_fd, NULL); + return -1; + } + + strncpy (&addr.sun_path[1], path, path_len); + /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */ +#else /* HAVE_ABSTRACT_SOCKETS */ + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "Operating system does not support abstract socket namespace\n"); + _dbus_close (listen_fd, NULL); + return -1; +#endif /* ! HAVE_ABSTRACT_SOCKETS */ + } + else + { + /* Discussed security implications of this with Nalin, + * and we couldn't think of where it would kick our ass, but + * it still seems a bit sucky. It also has non-security suckage; + * really we'd prefer to exit if the socket is already in use. + * But there doesn't seem to be a good way to do this. + * + * Just to be extra careful, I threw in the stat() - clearly + * the stat() can't *fix* any security issue, but it at least + * avoids inadvertent/accidental data loss. + */ + { + struct stat sb; + + if (stat (path, &sb) == 0 && + S_ISSOCK (sb.st_mode)) + unlink (path); + } + + if (path_len > _DBUS_MAX_SUN_PATH_LENGTH) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Abstract socket name too long\n"); + _dbus_close (listen_fd, NULL); + return -1; + } + + strncpy (addr.sun_path, path, path_len); + } + + if (bind (listen_fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to bind socket \"%s\": %s", + path, _dbus_strerror (errno)); + _dbus_close (listen_fd, NULL); + return -1; + } + + if (listen (listen_fd, 30 /* backlog */) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to listen on socket \"%s\": %s", + path, _dbus_strerror (errno)); + _dbus_close (listen_fd, NULL); + return -1; + } + + if (!_dbus_set_local_creds (listen_fd, TRUE)) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to enable LOCAL_CREDS on socket \"%s\": %s", + path, _dbus_strerror (errno)); + close (listen_fd); + return -1; + } + + if (!_dbus_set_fd_nonblocking (listen_fd, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_close (listen_fd, NULL); + return -1; + } + + /* Try opening up the permissions, but if we can't, just go ahead + * and continue, maybe it will be good enough. + */ + if (!abstract && chmod (path, 0777) < 0) + _dbus_warn ("Could not set mode 0777 on socket %s\n", + path); + + return listen_fd; +} + +/** + * Creates a socket and connects to a socket at the given host + * and port. The connection fd is returned, and is set up as + * nonblocking. + * + * @param host the host name to connect to + * @param port the port to connect to + * @param family the address family to listen on, NULL for all + * @param error return location for error code + * @returns connection file descriptor or -1 on error + */ +int +_dbus_connect_tcp_socket (const char *host, + const char *port, + const char *family, + DBusError *error) +{ + int fd = -1, res; + struct addrinfo hints; + struct addrinfo *ai, *tmp; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_open_tcp_socket (&fd, error)) + { + _DBUS_ASSERT_ERROR_IS_SET(error); + return -1; + } + + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + + _DBUS_ZERO (hints); + + if (!family) + hints.ai_family = AF_UNSPEC; + else if (!strcmp(family, "ipv4")) + hints.ai_family = AF_INET; + else if (!strcmp(family, "ipv6")) + hints.ai_family = AF_INET6; + else + { + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Unknown address family %s", family); + return -1; + } + hints.ai_protocol = IPPROTO_TCP; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; + + if ((res = getaddrinfo(host, port, &hints, &ai)) != 0) + { + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to lookup host/port: \"%s:%s\": %s (%d)", + host, port, gai_strerror(res), res); + _dbus_close (fd, NULL); + return -1; + } + + tmp = ai; + while (tmp) + { + if (!_dbus_open_socket (&fd, tmp->ai_family, SOCK_STREAM, 0, error)) + { + freeaddrinfo(ai); + _DBUS_ASSERT_ERROR_IS_SET(error); + return -1; + } + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + + if (connect (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0) + { + _dbus_close(fd, NULL); + fd = -1; + tmp = tmp->ai_next; + continue; + } + + break; + } + freeaddrinfo(ai); + + if (fd == -1) + { + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to connect to socket \"%s:%s\" %s", + host, port, _dbus_strerror(errno)); + return -1; + } + + + if (!_dbus_set_fd_nonblocking (fd, error)) + { + _dbus_close (fd, NULL); + fd = -1; + + return -1; + } + + return fd; +} + +/** + * Creates a socket and binds it to the given path, then listens on + * the socket. The socket is set to be nonblocking. In case of port=0 + * a random free port is used and returned in the port parameter. + * If inaddr_any is specified, the hostname is ignored. + * + * @param host the host name to listen on + * @param port the port to listen on, if zero a free port will be used + * @param family the address family to listen on, NULL for all + * @param retport string to return the actual port listened on + * @param fds_p location to store returned file descriptors + * @param error return location for errors + * @returns the number of listening file descriptors or -1 on error + */ +int +_dbus_listen_tcp_socket (const char *host, + const char *port, + const char *family, + DBusString *retport, + int **fds_p, + DBusError *error) +{ + int nlisten_fd = 0, *listen_fd = NULL, res, i; + struct addrinfo hints; + struct addrinfo *ai, *tmp; + + *fds_p = NULL; + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _DBUS_ZERO (hints); + + if (!family) + hints.ai_family = AF_UNSPEC; + else if (!strcmp(family, "ipv4")) + hints.ai_family = AF_INET; + else if (!strcmp(family, "ipv6")) + hints.ai_family = AF_INET6; + else + { + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Unknown address family %s", family); + return -1; + } + + hints.ai_protocol = IPPROTO_TCP; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; + + redo_lookup_with_port: + if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai) + { + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to lookup host/port: \"%s:%s\": %s (%d)", + host ? host : "*", port, gai_strerror(res), res); + return -1; + } + + tmp = ai; + while (tmp) + { + int fd = -1, *newlisten_fd; + if (!_dbus_open_socket (&fd, tmp->ai_family, SOCK_STREAM, 0, error)) + { + _DBUS_ASSERT_ERROR_IS_SET(error); + goto failed; + } + _DBUS_ASSERT_ERROR_IS_CLEAR(error); + + if (bind (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0) + { + _dbus_close(fd, NULL); + if (errno == EADDRINUSE) + { + /* Depending on kernel policy, it may or may not + be neccessary to bind to both IPv4 & 6 addresses + so ignore EADDRINUSE here */ + tmp = tmp->ai_next; + continue; + } + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to bind socket \"%s:%s\": %s", + host ? host : "*", port, _dbus_strerror (errno)); + goto failed; + } + + if (listen (fd, 30 /* backlog */) < 0) + { + _dbus_close (fd, NULL); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to listen on socket \"%s:%s\": %s", + host ? host : "*", port, _dbus_strerror (errno)); + goto failed; + } + + newlisten_fd = dbus_realloc(listen_fd, sizeof(int)*(nlisten_fd+1)); + if (!newlisten_fd) + { + _dbus_close (fd, NULL); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to allocate file handle array: %s", + _dbus_strerror (errno)); + goto failed; + } + listen_fd = newlisten_fd; + listen_fd[nlisten_fd] = fd; + nlisten_fd++; + + if (!_dbus_string_get_length(retport)) + { + /* If the user didn't specify a port, or used 0, then + the kernel chooses a port. After the first address + is bound to, we need to force all remaining addresses + to use the same port */ + if (!port || !strcmp(port, "0")) + { + struct sockaddr_storage addr; + socklen_t addrlen; + char portbuf[50]; + + addrlen = sizeof(addr); + getsockname(fd, (struct sockaddr*) &addr, &addrlen); + + if ((res = getnameinfo((struct sockaddr*)&addr, addrlen, NULL, 0, + portbuf, sizeof(portbuf), + NI_NUMERICHOST)) != 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to resolve port \"%s:%s\": %s (%s)", + host ? host : "*", port, gai_strerror(res), res); + goto failed; + } + if (!_dbus_string_append(retport, portbuf)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed; + } + + /* Release current address list & redo lookup */ + port = _dbus_string_get_const_data(retport); + freeaddrinfo(ai); + goto redo_lookup_with_port; + } + else + { + if (!_dbus_string_append(retport, port)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed; + } + } + } + + tmp = tmp->ai_next; + } + freeaddrinfo(ai); + ai = NULL; + + if (!nlisten_fd) + { + errno = EADDRINUSE; + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to bind socket \"%s:%s\": %s", + host ? host : "*", port, _dbus_strerror (errno)); + return -1; + } + + for (i = 0 ; i < nlisten_fd ; i++) + { + if (!_dbus_set_fd_nonblocking (listen_fd[i], error)) + { + goto failed; + } + } + + *fds_p = listen_fd; + + return nlisten_fd; + + failed: + if (ai) + freeaddrinfo(ai); + for (i = 0 ; i < nlisten_fd ; i++) + _dbus_close(listen_fd[i], NULL); + dbus_free(listen_fd); + return -1; +} + +static dbus_bool_t +write_credentials_byte (int server_fd, + DBusError *error) +{ + int bytes_written; + char buf[1] = { '\0' }; +#if defined(HAVE_CMSGCRED) + union { + struct cmsghdr hdr; + char cred[CMSG_SPACE (sizeof (struct cmsgcred))]; + } cmsg; + struct iovec iov; + struct msghdr msg; + iov.iov_base = buf; + iov.iov_len = 1; + + memset (&msg, 0, sizeof (msg)); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + msg.msg_control = (caddr_t) &cmsg; + msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred)); + memset (&cmsg, 0, sizeof (cmsg)); + cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred)); + cmsg.hdr.cmsg_level = SOL_SOCKET; + cmsg.hdr.cmsg_type = SCM_CREDS; +#endif + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + again: + +#if defined(HAVE_CMSGCRED) + bytes_written = sendmsg (server_fd, &msg, 0); +#else + bytes_written = write (server_fd, buf, 1); +#endif + + if (bytes_written < 0 && errno == EINTR) + goto again; + + if (bytes_written < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to write credentials byte: %s", + _dbus_strerror (errno)); + return FALSE; + } + else if (bytes_written == 0) + { + dbus_set_error (error, DBUS_ERROR_IO_ERROR, + "wrote zero bytes writing credentials byte"); + return FALSE; + } + else + { + _dbus_assert (bytes_written == 1); + _dbus_verbose ("wrote credentials byte\n"); + return TRUE; + } +} + +/** + * Reads a single byte which must be nul (an error occurs otherwise), + * and reads unix credentials if available. Clears the credentials + * object, then adds pid/uid if available, so any previous credentials + * stored in the object are lost. + * + * Return value indicates whether a byte was read, not whether + * we got valid credentials. On some systems, such as Linux, + * reading/writing the byte isn't actually required, but we do it + * anyway just to avoid multiple codepaths. + * + * Fails if no byte is available, so you must select() first. + * + * The point of the byte is that on some systems we have to + * use sendmsg()/recvmsg() to transmit credentials. + * + * @param client_fd the client file descriptor + * @param credentials object to add client credentials to + * @param error location to store error code + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_read_credentials_socket (int client_fd, + DBusCredentials *credentials, + DBusError *error) +{ + struct msghdr msg; + struct iovec iov; + char buf; + dbus_uid_t uid_read; + dbus_pid_t pid_read; + int bytes_read; + +#ifdef HAVE_CMSGCRED + union { + struct cmsghdr hdr; + char cred[CMSG_SPACE (sizeof (struct cmsgcred))]; + } cmsg; + +#elif defined(LOCAL_CREDS) + struct { + struct cmsghdr hdr; + struct sockcred cred; + } cmsg; +#endif + + uid_read = DBUS_UID_UNSET; + pid_read = DBUS_PID_UNSET; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* The POSIX spec certainly doesn't promise this, but + * we need these assertions to fail as soon as we're wrong about + * it so we can do the porting fixups + */ + _dbus_assert (sizeof (pid_t) <= sizeof (dbus_pid_t)); + _dbus_assert (sizeof (uid_t) <= sizeof (dbus_uid_t)); + _dbus_assert (sizeof (gid_t) <= sizeof (dbus_gid_t)); + + _dbus_credentials_clear (credentials); + + /* Systems supporting LOCAL_CREDS are configured to have this feature + * enabled (if it does not conflict with HAVE_CMSGCRED) prior accepting + * the connection. Therefore, the received message must carry the + * credentials information without doing anything special. + */ + + iov.iov_base = &buf; + iov.iov_len = 1; + + memset (&msg, 0, sizeof (msg)); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + +#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS) + memset (&cmsg, 0, sizeof (cmsg)); + msg.msg_control = (caddr_t) &cmsg; + msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred)); +#endif + + again: + bytes_read = recvmsg (client_fd, &msg, 0); + + if (bytes_read < 0) + { + if (errno == EINTR) + goto again; + + /* EAGAIN or EWOULDBLOCK would be unexpected here since we would + * normally only call read_credentials if the socket was ready + * for reading + */ + + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to read credentials byte: %s", + _dbus_strerror (errno)); + return FALSE; + } + else if (bytes_read == 0) + { + /* this should not happen unless we are using recvmsg wrong, + * so is essentially here for paranoia + */ + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to read credentials byte (zero-length read)"); + return FALSE; + } + else if (buf != '\0') + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Credentials byte was not nul"); + return FALSE; + } + +#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS) + if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof (struct cmsgcred)) + || cmsg.hdr.cmsg_type != SCM_CREDS) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Message from recvmsg() was not SCM_CREDS"); + return FALSE; + } +#endif + + _dbus_verbose ("read credentials byte\n"); + + { +#ifdef SO_PEERCRED + struct ucred cr; + int cr_len = sizeof (cr); + + if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 && + cr_len == sizeof (cr)) + { + pid_read = cr.pid; + uid_read = cr.uid; + } + else + { + _dbus_verbose ("Failed to getsockopt() credentials, returned len %d/%d: %s\n", + cr_len, (int) sizeof (cr), _dbus_strerror (errno)); + } +#elif defined(HAVE_CMSGCRED) + struct cmsgcred *cred; + + cred = (struct cmsgcred *) CMSG_DATA (&cmsg.hdr); + pid_read = cred->cmcred_pid; + uid_read = cred->cmcred_euid; +#elif defined(LOCAL_CREDS) + pid_read = DBUS_PID_UNSET; + uid_read = cmsg.cred.sc_uid; + /* Since we have already got the credentials from this socket, we can + * disable its LOCAL_CREDS flag if it was ever set. */ + _dbus_set_local_creds (client_fd, FALSE); +#elif defined(HAVE_GETPEEREID) + uid_t euid; + gid_t egid; + if (getpeereid (client_fd, &euid, &egid) == 0) + { + uid_read = euid; + } + else + { + _dbus_verbose ("Failed to getpeereid() credentials: %s\n", _dbus_strerror (errno)); + } +#elif defined(HAVE_GETPEERUCRED) + ucred_t * ucred = NULL; + if (getpeerucred (client_fd, &ucred) == 0) + { + pid_read = ucred_getpid (ucred); + uid_read = ucred_geteuid (ucred); +#ifdef HAVE_ADT + /* generate audit session data based on socket ucred */ + adt_session_data_t *adth = NULL; + adt_export_data_t *data = NULL; + size_t size = 0; + if (adt_start_session (&adth, NULL, 0) || (adth == NULL)) + { + _dbus_verbose ("Failed to adt_start_session(): %s\n", _dbus_strerror (errno)); + } + else + { + if (adt_set_from_ucred (adth, ucred, ADT_NEW)) + { + _dbus_verbose ("Failed to adt_set_from_ucred(): %s\n", _dbus_strerror (errno)); + } + else + { + size = adt_export_session_data (adth, &data); + if (size <= 0) + { + _dbus_verbose ("Failed to adt_export_session_data(): %s\n", _dbus_strerror (errno)); + } + else + { + _dbus_credentials_add_adt_audit_data (credentials, data, size); + free (data); + } + } + (void) adt_end_session (adth); + } +#endif /* HAVE_ADT */ + } + else + { + _dbus_verbose ("Failed to getpeerucred() credentials: %s\n", _dbus_strerror (errno)); + } + if (ucred != NULL) + ucred_free (ucred); +#else /* !SO_PEERCRED && !HAVE_CMSGCRED && !HAVE_GETPEEREID && !HAVE_GETPEERUCRED */ + _dbus_verbose ("Socket credentials not supported on this OS\n"); +#endif + } + + _dbus_verbose ("Credentials:" + " pid "DBUS_PID_FORMAT + " uid "DBUS_UID_FORMAT + "\n", + pid_read, + uid_read); + + if (pid_read != DBUS_PID_UNSET) + { + if (!_dbus_credentials_add_unix_pid (credentials, pid_read)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + } + + if (uid_read != DBUS_UID_UNSET) + { + if (!_dbus_credentials_add_unix_uid (credentials, uid_read)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + } + + return TRUE; +} + +/** + * Sends a single nul byte with our UNIX credentials as ancillary + * data. Returns #TRUE if the data was successfully written. On + * systems that don't support sending credentials, just writes a byte, + * doesn't send any credentials. On some systems, such as Linux, + * reading/writing the byte isn't actually required, but we do it + * anyway just to avoid multiple codepaths. + * + * Fails if no byte can be written, so you must select() first. + * + * The point of the byte is that on some systems we have to + * use sendmsg()/recvmsg() to transmit credentials. + * + * @param server_fd file descriptor for connection to server + * @param error return location for error code + * @returns #TRUE if the byte was sent + */ +dbus_bool_t +_dbus_send_credentials_socket (int server_fd, + DBusError *error) +{ + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (write_credentials_byte (server_fd, error)) + return TRUE; + else + return FALSE; +} + +/** + * Accepts a connection on a listening socket. + * Handles EINTR for you. + * + * @param listen_fd the listen file descriptor + * @returns the connection fd of the client, or -1 on error + */ +int +_dbus_accept (int listen_fd) +{ + int client_fd; + struct sockaddr addr; + socklen_t addrlen; + + addrlen = sizeof (addr); + + retry: + client_fd = accept (listen_fd, &addr, &addrlen); + + if (client_fd < 0) + { + if (errno == EINTR) + goto retry; + } + + _dbus_verbose ("client fd %d accepted\n", client_fd); + + return client_fd; +} + +/** + * Checks to make sure the given directory is + * private to the user + * + * @param dir the name of the directory + * @param error error return + * @returns #FALSE on failure + **/ +dbus_bool_t +_dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error) +{ + const char *directory; + struct stat sb; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + directory = _dbus_string_get_const_data (dir); + + if (stat (directory, &sb) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "%s", _dbus_strerror (errno)); + + return FALSE; + } + + if ((S_IROTH & sb.st_mode) || (S_IWOTH & sb.st_mode) || + (S_IRGRP & sb.st_mode) || (S_IWGRP & sb.st_mode)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "%s directory is not private to the user", directory); + return FALSE; + } + + return TRUE; +} + +static dbus_bool_t +fill_user_info_from_passwd (struct passwd *p, + DBusUserInfo *info, + DBusError *error) +{ + _dbus_assert (p->pw_name != NULL); + _dbus_assert (p->pw_dir != NULL); + + info->uid = p->pw_uid; + info->primary_gid = p->pw_gid; + info->username = _dbus_strdup (p->pw_name); + info->homedir = _dbus_strdup (p->pw_dir); + + if (info->username == NULL || + info->homedir == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return FALSE; + } + + return TRUE; +} + +static dbus_bool_t +fill_user_info (DBusUserInfo *info, + dbus_uid_t uid, + const DBusString *username, + DBusError *error) +{ + const char *username_c; + + /* exactly one of username/uid provided */ + _dbus_assert (username != NULL || uid != DBUS_UID_UNSET); + _dbus_assert (username == NULL || uid == DBUS_UID_UNSET); + + info->uid = DBUS_UID_UNSET; + info->primary_gid = DBUS_GID_UNSET; + info->group_ids = NULL; + info->n_group_ids = 0; + info->username = NULL; + info->homedir = NULL; + + if (username != NULL) + username_c = _dbus_string_get_const_data (username); + else + username_c = NULL; + + /* For now assuming that the getpwnam() and getpwuid() flavors + * are always symmetrical, if not we have to add more configure + * checks + */ + +#if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R) + { + struct passwd *p; + int result; + size_t buflen; + char *buf; + struct passwd p_str; + + /* retrieve maximum needed size for buf */ + buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + + /* sysconf actually returns a long, but everything else expects size_t, + * so just recast here. + * https://bugs.freedesktop.org/show_bug.cgi?id=17061 + */ + if ((long) buflen <= 0) + buflen = 1024; + + result = -1; + while (1) + { + buf = dbus_malloc (buflen); + if (buf == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return FALSE; + } + + p = NULL; +#ifdef HAVE_POSIX_GETPWNAM_R + if (uid != DBUS_UID_UNSET) + result = getpwuid_r (uid, &p_str, buf, buflen, + &p); + else + result = getpwnam_r (username_c, &p_str, buf, buflen, + &p); +#else + if (uid != DBUS_UID_UNSET) + p = getpwuid_r (uid, &p_str, buf, buflen); + else + p = getpwnam_r (username_c, &p_str, buf, buflen); + result = 0; +#endif /* !HAVE_POSIX_GETPWNAM_R */ + //Try a bigger buffer if ERANGE was returned + if (result == ERANGE && buflen < 512 * 1024) + { + dbus_free (buf); + buflen *= 2; + } + else + { + break; + } + } + if (result == 0 && p == &p_str) + { + if (!fill_user_info_from_passwd (p, info, error)) + { + dbus_free (buf); + return FALSE; + } + dbus_free (buf); + } + else + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "User \"%s\" unknown or no memory to allocate password entry\n", + username_c ? username_c : "???"); + _dbus_verbose ("User %s unknown\n", username_c ? username_c : "???"); + dbus_free (buf); + return FALSE; + } + } +#else /* ! HAVE_GETPWNAM_R */ + { + /* I guess we're screwed on thread safety here */ + struct passwd *p; + + if (uid != DBUS_UID_UNSET) + p = getpwuid (uid); + else + p = getpwnam (username_c); + + if (p != NULL) + { + if (!fill_user_info_from_passwd (p, info, error)) + { + return FALSE; + } + } + else + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "User \"%s\" unknown or no memory to allocate password entry\n", + username_c ? username_c : "???"); + _dbus_verbose ("User %s unknown\n", username_c ? username_c : "???"); + return FALSE; + } + } +#endif /* ! HAVE_GETPWNAM_R */ + + /* Fill this in so we can use it to get groups */ + username_c = info->username; + +#ifdef HAVE_GETGROUPLIST + { + gid_t *buf; + int buf_count; + int i; + int initial_buf_count; + + initial_buf_count = 17; + buf_count = initial_buf_count; + buf = dbus_new (gid_t, buf_count); + if (buf == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed; + } + + if (getgrouplist (username_c, + info->primary_gid, + buf, &buf_count) < 0) + { + gid_t *new; + /* Presumed cause of negative return code: buf has insufficient + entries to hold the entire group list. The Linux behavior in this + case is to pass back the actual number of groups in buf_count, but + on Mac OS X 10.5, buf_count is unhelpfully left alone. + So as a hack, try to help out a bit by guessing a larger + number of groups, within reason.. might still fail, of course, + but we can at least print a more informative message. I looked up + the "right way" to do this by downloading Apple's own source code + for the "id" command, and it turns out that they use an + undocumented library function getgrouplist_2 (!) which is not + declared in any header in /usr/include (!!). That did not seem + like the way to go here. + */ + if (buf_count == initial_buf_count) + { + buf_count *= 16; /* Retry with an arbitrarily scaled-up array */ + } + new = dbus_realloc (buf, buf_count * sizeof (buf[0])); + if (new == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + dbus_free (buf); + goto failed; + } + + buf = new; + + errno = 0; + if (getgrouplist (username_c, info->primary_gid, buf, &buf_count) < 0) + { + if (errno == 0) + { + _dbus_warn ("It appears that username \"%s\" is in more than %d groups.\nProceeding with just the first %d groups.", + username_c, buf_count, buf_count); + } + else + { + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to get groups for username \"%s\" primary GID " + DBUS_GID_FORMAT ": %s\n", + username_c, info->primary_gid, + _dbus_strerror (errno)); + dbus_free (buf); + goto failed; + } + } + } + + info->group_ids = dbus_new (dbus_gid_t, buf_count); + if (info->group_ids == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + dbus_free (buf); + goto failed; + } + + for (i = 0; i < buf_count; ++i) + info->group_ids[i] = buf[i]; + + info->n_group_ids = buf_count; + + dbus_free (buf); + } +#else /* HAVE_GETGROUPLIST */ + { + /* We just get the one group ID */ + info->group_ids = dbus_new (dbus_gid_t, 1); + if (info->group_ids == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed; + } + + info->n_group_ids = 1; + + (info->group_ids)[0] = info->primary_gid; + } +#endif /* HAVE_GETGROUPLIST */ + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + return TRUE; + + failed: + _DBUS_ASSERT_ERROR_IS_SET (error); + return FALSE; +} + +/** + * Gets user info for the given username. + * + * @param info user info object to initialize + * @param username the username + * @param error error return + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_user_info_fill (DBusUserInfo *info, + const DBusString *username, + DBusError *error) +{ + return fill_user_info (info, DBUS_UID_UNSET, + username, error); +} + +/** + * Gets user info for the given user ID. + * + * @param info user info object to initialize + * @param uid the user ID + * @param error error return + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_user_info_fill_uid (DBusUserInfo *info, + dbus_uid_t uid, + DBusError *error) +{ + return fill_user_info (info, uid, + NULL, error); +} + +/** + * Adds the credentials of the current process to the + * passed-in credentials object. + * + * @param credentials credentials to add to + * @returns #FALSE if no memory; does not properly roll back on failure, so only some credentials may have been added + */ +dbus_bool_t +_dbus_credentials_add_from_current_process (DBusCredentials *credentials) +{ + /* The POSIX spec certainly doesn't promise this, but + * we need these assertions to fail as soon as we're wrong about + * it so we can do the porting fixups + */ + _dbus_assert (sizeof (pid_t) <= sizeof (dbus_pid_t)); + _dbus_assert (sizeof (uid_t) <= sizeof (dbus_uid_t)); + _dbus_assert (sizeof (gid_t) <= sizeof (dbus_gid_t)); + + if (!_dbus_credentials_add_unix_pid(credentials, _dbus_getpid())) + return FALSE; + if (!_dbus_credentials_add_unix_uid(credentials, _dbus_geteuid())) + return FALSE; + + return TRUE; +} + +/** + * Append to the string the identity we would like to have when we + * authenticate, on UNIX this is the current process UID and on + * Windows something else, probably a Windows SID string. No escaping + * is required, that is done in dbus-auth.c. The username here + * need not be anything human-readable, it can be the machine-readable + * form i.e. a user id. + * + * @param str the string to append to + * @returns #FALSE on no memory + */ +dbus_bool_t +_dbus_append_user_from_current_process (DBusString *str) +{ + return _dbus_string_append_uint (str, + _dbus_geteuid ()); +} + +/** + * Gets our process ID + * @returns process ID + */ +dbus_pid_t +_dbus_getpid (void) +{ + return getpid (); +} + +/** Gets our UID + * @returns process UID + */ +dbus_uid_t +_dbus_getuid (void) +{ + return getuid (); +} + +/** Gets our effective UID + * @returns process effective UID + */ +dbus_uid_t +_dbus_geteuid (void) +{ + return geteuid (); +} + +/** + * The only reason this is separate from _dbus_getpid() is to allow it + * on Windows for logging but not for other purposes. + * + * @returns process ID to put in log messages + */ +unsigned long +_dbus_pid_for_log (void) +{ + return getpid (); +} + +/** + * Gets a UID from a UID string. + * + * @param uid_str the UID in string form + * @param uid UID to fill in + * @returns #TRUE if successfully filled in UID + */ +dbus_bool_t +_dbus_parse_uid (const DBusString *uid_str, + dbus_uid_t *uid) +{ + int end; + long val; + + if (_dbus_string_get_length (uid_str) == 0) + { + _dbus_verbose ("UID string was zero length\n"); + return FALSE; + } + + val = -1; + end = 0; + if (!_dbus_string_parse_int (uid_str, 0, &val, + &end)) + { + _dbus_verbose ("could not parse string as a UID\n"); + return FALSE; + } + + if (end != _dbus_string_get_length (uid_str)) + { + _dbus_verbose ("string contained trailing stuff after UID\n"); + return FALSE; + } + + *uid = val; + + return TRUE; +} + + +_DBUS_DEFINE_GLOBAL_LOCK (atomic); + +#if DBUS_USE_ATOMIC_INT_486_COND +/* Taken from CVS version 1.7 of glibc's sysdeps/i386/i486/atomicity.h */ +/* Since the asm stuff here is gcc-specific we go ahead and use "inline" also */ +static inline dbus_int32_t +atomic_exchange_and_add (DBusAtomic *atomic, + volatile dbus_int32_t val) +{ + register dbus_int32_t result; + + __asm__ __volatile__ ("lock; xaddl %0,%1" + : "=r" (result), "=m" (atomic->value) + : "0" (val), "m" (atomic->value)); + return result; +} +#endif + +/** + * Atomically increments an integer + * + * @param atomic pointer to the integer to increment + * @returns the value before incrementing + * + * @todo implement arch-specific faster atomic ops + */ +dbus_int32_t +_dbus_atomic_inc (DBusAtomic *atomic) +{ +#if DBUS_USE_ATOMIC_INT_486_COND + return atomic_exchange_and_add (atomic, 1); +#else + dbus_int32_t res; + _DBUS_LOCK (atomic); + res = atomic->value; + atomic->value += 1; + _DBUS_UNLOCK (atomic); + return res; +#endif +} + +/** + * Atomically decrement an integer + * + * @param atomic pointer to the integer to decrement + * @returns the value before decrementing + * + * @todo implement arch-specific faster atomic ops + */ +dbus_int32_t +_dbus_atomic_dec (DBusAtomic *atomic) +{ +#if DBUS_USE_ATOMIC_INT_486_COND + return atomic_exchange_and_add (atomic, -1); +#else + dbus_int32_t res; + + _DBUS_LOCK (atomic); + res = atomic->value; + atomic->value -= 1; + _DBUS_UNLOCK (atomic); + return res; +#endif +} + +#ifdef DBUS_BUILD_TESTS +/** Gets our GID + * @returns process GID + */ +dbus_gid_t +_dbus_getgid (void) +{ + return getgid (); +} +#endif + +/** + * Wrapper for poll(). + * + * @param fds the file descriptors to poll + * @param n_fds number of descriptors in the array + * @param timeout_milliseconds timeout or -1 for infinite + * @returns numbers of fds with revents, or <0 on error + */ +int +_dbus_poll (DBusPollFD *fds, + int n_fds, + int timeout_milliseconds) +{ +#if defined(HAVE_POLL) && !defined(BROKEN_POLL) + /* This big thing is a constant expression and should get optimized + * out of existence. So it's more robust than a configure check at + * no cost. + */ + if (_DBUS_POLLIN == POLLIN && + _DBUS_POLLPRI == POLLPRI && + _DBUS_POLLOUT == POLLOUT && + _DBUS_POLLERR == POLLERR && + _DBUS_POLLHUP == POLLHUP && + _DBUS_POLLNVAL == POLLNVAL && + sizeof (DBusPollFD) == sizeof (struct pollfd) && + _DBUS_STRUCT_OFFSET (DBusPollFD, fd) == + _DBUS_STRUCT_OFFSET (struct pollfd, fd) && + _DBUS_STRUCT_OFFSET (DBusPollFD, events) == + _DBUS_STRUCT_OFFSET (struct pollfd, events) && + _DBUS_STRUCT_OFFSET (DBusPollFD, revents) == + _DBUS_STRUCT_OFFSET (struct pollfd, revents)) + { + return poll ((struct pollfd*) fds, + n_fds, + timeout_milliseconds); + } + else + { + /* We have to convert the DBusPollFD to an array of + * struct pollfd, poll, and convert back. + */ + _dbus_warn ("didn't implement poll() properly for this system yet\n"); + return -1; + } +#else /* ! HAVE_POLL */ + + fd_set read_set, write_set, err_set; + int max_fd = 0; + int i; + struct timeval tv; + int ready; + + FD_ZERO (&read_set); + FD_ZERO (&write_set); + FD_ZERO (&err_set); + + for (i = 0; i < n_fds; i++) + { + DBusPollFD *fdp = &fds[i]; + + if (fdp->events & _DBUS_POLLIN) + FD_SET (fdp->fd, &read_set); + + if (fdp->events & _DBUS_POLLOUT) + FD_SET (fdp->fd, &write_set); + + FD_SET (fdp->fd, &err_set); + + max_fd = MAX (max_fd, fdp->fd); + } + + tv.tv_sec = timeout_milliseconds / 1000; + tv.tv_usec = (timeout_milliseconds % 1000) * 1000; + + ready = select (max_fd + 1, &read_set, &write_set, &err_set, + timeout_milliseconds < 0 ? NULL : &tv); + + if (ready > 0) + { + for (i = 0; i < n_fds; i++) + { + DBusPollFD *fdp = &fds[i]; + + fdp->revents = 0; + + if (FD_ISSET (fdp->fd, &read_set)) + fdp->revents |= _DBUS_POLLIN; + + if (FD_ISSET (fdp->fd, &write_set)) + fdp->revents |= _DBUS_POLLOUT; + + if (FD_ISSET (fdp->fd, &err_set)) + fdp->revents |= _DBUS_POLLERR; + } + } + + return ready; +#endif +} + +/** + * Get current time, as in gettimeofday(). Use the monotonic clock if + * available, to avoid problems when the system time changes. + * + * @param tv_sec return location for number of seconds + * @param tv_usec return location for number of microseconds (thousandths) + */ +void +_dbus_get_current_time (long *tv_sec, + long *tv_usec) +{ + struct timeval t; + +#ifdef HAVE_MONOTONIC_CLOCK + struct timespec ts; + clock_gettime (CLOCK_MONOTONIC, &ts); + + if (tv_sec) + *tv_sec = ts.tv_sec; + if (tv_usec) + *tv_usec = ts.tv_nsec / 1000; +#else + gettimeofday (&t, NULL); + + if (tv_sec) + *tv_sec = t.tv_sec; + if (tv_usec) + *tv_usec = t.tv_usec; +#endif +} + +/** + * Appends the contents of the given file to the string, + * returning error code. At the moment, won't open a file + * more than a megabyte in size. + * + * @param str the string to append to + * @param filename filename to load + * @param error place to set an error + * @returns #FALSE if error was set + */ +dbus_bool_t +_dbus_file_get_contents (DBusString *str, + const DBusString *filename, + DBusError *error) +{ + int fd; + struct stat sb; + int orig_len; + int total; + const char *filename_c; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + filename_c = _dbus_string_get_const_data (filename); + + /* O_BINARY useful on Cygwin */ + fd = open (filename_c, O_RDONLY | O_BINARY); + if (fd < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to open \"%s\": %s", + filename_c, + _dbus_strerror (errno)); + return FALSE; + } + + _dbus_verbose ("file fd %d opened\n", fd); + + if (fstat (fd, &sb) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to stat \"%s\": %s", + filename_c, + _dbus_strerror (errno)); + + _dbus_verbose ("fstat() failed: %s", + _dbus_strerror (errno)); + + _dbus_close (fd, NULL); + + return FALSE; + } + + if (sb.st_size > _DBUS_ONE_MEGABYTE) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "File size %lu of \"%s\" is too large.", + (unsigned long) sb.st_size, filename_c); + _dbus_close (fd, NULL); + return FALSE; + } + + total = 0; + orig_len = _dbus_string_get_length (str); + if (sb.st_size > 0 && S_ISREG (sb.st_mode)) + { + int bytes_read; + + while (total < (int) sb.st_size) + { + bytes_read = _dbus_read (fd, str, + sb.st_size - total); + if (bytes_read <= 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Error reading \"%s\": %s", + filename_c, + _dbus_strerror (errno)); + + _dbus_verbose ("read() failed: %s", + _dbus_strerror (errno)); + + _dbus_close (fd, NULL); + _dbus_string_set_length (str, orig_len); + return FALSE; + } + else + total += bytes_read; + } + + _dbus_close (fd, NULL); + return TRUE; + } + else if (sb.st_size != 0) + { + _dbus_verbose ("Can only open regular files at the moment.\n"); + dbus_set_error (error, DBUS_ERROR_FAILED, + "\"%s\" is not a regular file", + filename_c); + _dbus_close (fd, NULL); + return FALSE; + } + else + { + _dbus_close (fd, NULL); + return TRUE; + } +} + +/** + * Writes a string out to a file. If the file exists, + * it will be atomically overwritten by the new data. + * + * @param str the string to write out + * @param filename the file to save string to + * @param error error to be filled in on failure + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_string_save_to_file (const DBusString *str, + const DBusString *filename, + DBusError *error) +{ + int fd; + int bytes_to_write; + const char *filename_c; + DBusString tmp_filename; + const char *tmp_filename_c; + int total; + dbus_bool_t need_unlink; + dbus_bool_t retval; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + fd = -1; + retval = FALSE; + need_unlink = FALSE; + + if (!_dbus_string_init (&tmp_filename)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return FALSE; + } + + if (!_dbus_string_copy (filename, 0, &tmp_filename, 0)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (&tmp_filename); + return FALSE; + } + + if (!_dbus_string_append (&tmp_filename, ".")) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (&tmp_filename); + return FALSE; + } + +#define N_TMP_FILENAME_RANDOM_BYTES 8 + if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_string_free (&tmp_filename); + return FALSE; + } + + filename_c = _dbus_string_get_const_data (filename); + tmp_filename_c = _dbus_string_get_const_data (&tmp_filename); + + fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT, + 0600); + if (fd < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not create %s: %s", tmp_filename_c, + _dbus_strerror (errno)); + goto out; + } + + _dbus_verbose ("tmp file fd %d opened\n", fd); + + need_unlink = TRUE; + + total = 0; + bytes_to_write = _dbus_string_get_length (str); + + while (total < bytes_to_write) + { + int bytes_written; + + bytes_written = _dbus_write (fd, str, total, + bytes_to_write - total); + + if (bytes_written <= 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not write to %s: %s", tmp_filename_c, + _dbus_strerror (errno)); + + goto out; + } + + total += bytes_written; + } + + if (fsync(fd)) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not synchronize file %s: %s", + tmp_filename_c, _dbus_strerror (errno)); + + goto out; + } + + if (!_dbus_close (fd, NULL)) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not close file %s: %s", + tmp_filename_c, _dbus_strerror (errno)); + + goto out; + } + + fd = -1; + + if (rename (tmp_filename_c, filename_c) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not rename %s to %s: %s", + tmp_filename_c, filename_c, + _dbus_strerror (errno)); + + goto out; + } + + need_unlink = FALSE; + + retval = TRUE; + + out: + /* close first, then unlink, to prevent ".nfs34234235" garbage + * files + */ + + if (fd >= 0) + _dbus_close (fd, NULL); + + if (need_unlink && unlink (tmp_filename_c) < 0) + _dbus_verbose ("Failed to unlink temp file %s: %s\n", + tmp_filename_c, _dbus_strerror (errno)); + + _dbus_string_free (&tmp_filename); + + if (!retval) + _DBUS_ASSERT_ERROR_IS_SET (error); + + return retval; +} + +/** Makes the file readable by every user in the system. + * + * @param filename the filename + * @param error error location + * @returns #TRUE if the file's permissions could be changed. + */ +dbus_bool_t +_dbus_make_file_world_readable(const DBusString *filename, + DBusError *error) +{ + const char *filename_c; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + filename_c = _dbus_string_get_const_data (filename); + if (chmod (filename_c, 0644) == -1) + { + dbus_set_error (error, + DBUS_ERROR_FAILED, + "Could not change permissions of file %s: %s\n", + filename_c, + _dbus_strerror (errno)); + return FALSE; + } + return TRUE; +} + +/** Creates the given file, failing if the file already exists. + * + * @param filename the filename + * @param error error location + * @returns #TRUE if we created the file and it didn't exist + */ +dbus_bool_t +_dbus_create_file_exclusively (const DBusString *filename, + DBusError *error) +{ + int fd; + const char *filename_c; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + filename_c = _dbus_string_get_const_data (filename); + + fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT, + 0600); + if (fd < 0) + { + dbus_set_error (error, + DBUS_ERROR_FAILED, + "Could not create file %s: %s\n", + filename_c, + _dbus_strerror (errno)); + return FALSE; + } + + _dbus_verbose ("exclusive file fd %d opened\n", fd); + + if (!_dbus_close (fd, NULL)) + { + dbus_set_error (error, + DBUS_ERROR_FAILED, + "Could not close file %s: %s\n", + filename_c, + _dbus_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/** + * Deletes the given file. + * + * @param filename the filename + * @param error error location + * + * @returns #TRUE if unlink() succeeded + */ +dbus_bool_t +_dbus_delete_file (const DBusString *filename, + DBusError *error) +{ + const char *filename_c; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + filename_c = _dbus_string_get_const_data (filename); + + if (unlink (filename_c) < 0) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to delete file %s: %s\n", + filename_c, _dbus_strerror (errno)); + return FALSE; + } + else + return TRUE; +} + +/** + * Creates a directory; succeeds if the directory + * is created or already existed. + * + * @param filename directory filename + * @param error initialized error object + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_create_directory (const DBusString *filename, + DBusError *error) +{ + const char *filename_c; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + filename_c = _dbus_string_get_const_data (filename); + + if (mkdir (filename_c, 0700) < 0) + { + if (errno == EEXIST) + return TRUE; + + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to create directory %s: %s\n", + filename_c, _dbus_strerror (errno)); + return FALSE; + } + else + return TRUE; +} + +/** + * Appends the given filename to the given directory. + * + * @todo it might be cute to collapse multiple '/' such as "foo//" + * concat "//bar" + * + * @param dir the directory name + * @param next_component the filename + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_concat_dir_and_file (DBusString *dir, + const DBusString *next_component) +{ + dbus_bool_t dir_ends_in_slash; + dbus_bool_t file_starts_with_slash; + + if (_dbus_string_get_length (dir) == 0 || + _dbus_string_get_length (next_component) == 0) + return TRUE; + + dir_ends_in_slash = '/' == _dbus_string_get_byte (dir, + _dbus_string_get_length (dir) - 1); + + file_starts_with_slash = '/' == _dbus_string_get_byte (next_component, 0); + + if (dir_ends_in_slash && file_starts_with_slash) + { + _dbus_string_shorten (dir, 1); + } + else if (!(dir_ends_in_slash || file_starts_with_slash)) + { + if (!_dbus_string_append_byte (dir, '/')) + return FALSE; + } + + return _dbus_string_copy (next_component, 0, dir, + _dbus_string_get_length (dir)); +} + +/** nanoseconds in a second */ +#define NANOSECONDS_PER_SECOND 1000000000 +/** microseconds in a second */ +#define MICROSECONDS_PER_SECOND 1000000 +/** milliseconds in a second */ +#define MILLISECONDS_PER_SECOND 1000 +/** nanoseconds in a millisecond */ +#define NANOSECONDS_PER_MILLISECOND 1000000 +/** microseconds in a millisecond */ +#define MICROSECONDS_PER_MILLISECOND 1000 + +/** + * Sleeps the given number of milliseconds. + * @param milliseconds number of milliseconds + */ +void +_dbus_sleep_milliseconds (int milliseconds) +{ +#ifdef HAVE_NANOSLEEP + struct timespec req; + struct timespec rem; + + req.tv_sec = milliseconds / MILLISECONDS_PER_SECOND; + req.tv_nsec = (milliseconds % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND; + rem.tv_sec = 0; + rem.tv_nsec = 0; + + while (nanosleep (&req, &rem) < 0 && errno == EINTR) + req = rem; +#elif defined (HAVE_USLEEP) + usleep (milliseconds * MICROSECONDS_PER_MILLISECOND); +#else /* ! HAVE_USLEEP */ + sleep (MAX (milliseconds / 1000, 1)); +#endif +} + +static dbus_bool_t +_dbus_generate_pseudorandom_bytes (DBusString *str, + int n_bytes) +{ + int old_len; + char *p; + + old_len = _dbus_string_get_length (str); + + if (!_dbus_string_lengthen (str, n_bytes)) + return FALSE; + + p = _dbus_string_get_data_len (str, old_len, n_bytes); + + _dbus_generate_pseudorandom_bytes_buffer (p, n_bytes); + + return TRUE; +} + +/** + * Generates the given number of random bytes, + * using the best mechanism we can come up with. + * + * @param str the string + * @param n_bytes the number of random bytes to append to string + * @returns #TRUE on success, #FALSE if no memory + */ +dbus_bool_t +_dbus_generate_random_bytes (DBusString *str, + int n_bytes) +{ + int old_len; + int fd; + + /* FALSE return means "no memory", if it could + * mean something else then we'd need to return + * a DBusError. So we always fall back to pseudorandom + * if the I/O fails. + */ + + old_len = _dbus_string_get_length (str); + fd = -1; + + /* note, urandom on linux will fall back to pseudorandom */ + fd = open ("/dev/urandom", O_RDONLY); + if (fd < 0) + return _dbus_generate_pseudorandom_bytes (str, n_bytes); + + _dbus_verbose ("/dev/urandom fd %d opened\n", fd); + + if (_dbus_read (fd, str, n_bytes) != n_bytes) + { + _dbus_close (fd, NULL); + _dbus_string_set_length (str, old_len); + return _dbus_generate_pseudorandom_bytes (str, n_bytes); + } + + _dbus_verbose ("Read %d bytes from /dev/urandom\n", + n_bytes); + + _dbus_close (fd, NULL); + + return TRUE; +} + +/** + * Exit the process, returning the given value. + * + * @param code the exit code + */ +void +_dbus_exit (int code) +{ + _exit (code); +} + +/** + * A wrapper around strerror() because some platforms + * may be lame and not have strerror(). Also, never + * returns NULL. + * + * @param error_number errno. + * @returns error description. + */ +const char* +_dbus_strerror (int error_number) +{ + const char *msg; + + msg = strerror (error_number); + if (msg == NULL) + msg = "unknown"; + + return msg; +} + +/** + * signal (SIGPIPE, SIG_IGN); + */ +void +_dbus_disable_sigpipe (void) +{ + signal (SIGPIPE, SIG_IGN); +} + +/** + * Sets the file descriptor to be close + * on exec. Should be called for all file + * descriptors in D-Bus code. + * + * @param fd the file descriptor + */ +void +_dbus_fd_set_close_on_exec (int fd) +{ + int val; + + val = fcntl (fd, F_GETFD, 0); + + if (val < 0) + return; + + val |= FD_CLOEXEC; + + fcntl (fd, F_SETFD, val); +} + +/** + * Closes a file descriptor. + * + * @param fd the file descriptor + * @param error error object + * @returns #FALSE if error set + */ +dbus_bool_t +_dbus_close (int fd, + DBusError *error) +{ + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + again: + if (close (fd) < 0) + { + if (errno == EINTR) + goto again; + + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not close fd %d", fd); + return FALSE; + } + + return TRUE; +} + +/** + * Sets a file descriptor to be nonblocking. + * + * @param fd the file descriptor. + * @param error address of error location. + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_set_fd_nonblocking (int fd, + DBusError *error) +{ + int val; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + val = fcntl (fd, F_GETFL, 0); + if (val < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to get flags from file descriptor %d: %s", + fd, _dbus_strerror (errno)); + _dbus_verbose ("Failed to get flags for fd %d: %s\n", fd, + _dbus_strerror (errno)); + return FALSE; + } + + if (fcntl (fd, F_SETFL, val | O_NONBLOCK) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to set nonblocking flag of file descriptor %d: %s", + fd, _dbus_strerror (errno)); + _dbus_verbose ("Failed to set fd %d nonblocking: %s\n", + fd, _dbus_strerror (errno)); + + return FALSE; + } + + return TRUE; +} + +/** + * On GNU libc systems, print a crude backtrace to stderr. On other + * systems, print "no backtrace support" and block for possible gdb + * attachment if an appropriate environment variable is set. + */ +void +_dbus_print_backtrace (void) +{ +#if defined (HAVE_BACKTRACE) && defined (DBUS_BUILT_R_DYNAMIC) + void *bt[500]; + int bt_size; + int i; + char **syms; + + bt_size = backtrace (bt, 500); + + syms = backtrace_symbols (bt, bt_size); + + i = 0; + while (i < bt_size) + { + /* don't use dbus_warn since it can _dbus_abort() */ + fprintf (stderr, " %s\n", syms[i]); + ++i; + } + fflush (stderr); + + free (syms); +#elif defined (HAVE_BACKTRACE) && ! defined (DBUS_BUILT_R_DYNAMIC) + fprintf (stderr, " D-Bus not built with -rdynamic so unable to print a backtrace\n"); +#else + fprintf (stderr, " D-Bus not compiled with backtrace support so unable to print a backtrace\n"); +#endif +} + +/** + * Creates a full-duplex pipe (as in socketpair()). + * Sets both ends of the pipe nonblocking. + * + * @todo libdbus only uses this for the debug-pipe server, so in + * principle it could be in dbus-sysdeps-util.c, except that + * dbus-sysdeps-util.c isn't in libdbus when tests are enabled and the + * debug-pipe server is used. + * + * @param fd1 return location for one end + * @param fd2 return location for the other end + * @param blocking #TRUE if pipe should be blocking + * @param error error return + * @returns #FALSE on failure (if error is set) + */ +dbus_bool_t +_dbus_full_duplex_pipe (int *fd1, + int *fd2, + dbus_bool_t blocking, + DBusError *error) +{ +#ifdef HAVE_SOCKETPAIR + int fds[2]; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not create full-duplex pipe"); + return FALSE; + } + + if (!blocking && + (!_dbus_set_fd_nonblocking (fds[0], NULL) || + !_dbus_set_fd_nonblocking (fds[1], NULL))) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Could not set full-duplex pipe nonblocking"); + + _dbus_close (fds[0], NULL); + _dbus_close (fds[1], NULL); + + return FALSE; + } + + *fd1 = fds[0]; + *fd2 = fds[1]; + + _dbus_verbose ("full-duplex pipe %d <-> %d\n", + *fd1, *fd2); + + return TRUE; +#else + _dbus_warn ("_dbus_full_duplex_pipe() not implemented on this OS\n"); + dbus_set_error (error, DBUS_ERROR_FAILED, + "_dbus_full_duplex_pipe() not implemented on this OS"); + return FALSE; +#endif +} + +/** + * Measure the length of the given format string and arguments, + * not including the terminating nul. + * + * @param format a printf-style format string + * @param args arguments for the format string + * @returns length of the given format string and args + */ +int +_dbus_printf_string_upper_bound (const char *format, + va_list args) +{ + char c; + return vsnprintf (&c, 1, format, args); +} + +/** + * Gets the temporary files directory by inspecting the environment variables + * TMPDIR, TMP, and TEMP in that order. If none of those are set "/tmp" is returned + * + * @returns location of temp directory + */ +const char* +_dbus_get_tmpdir(void) +{ + static const char* tmpdir = NULL; + + if (tmpdir == NULL) + { + /* TMPDIR is what glibc uses, then + * glibc falls back to the P_tmpdir macro which + * just expands to "/tmp" + */ + if (tmpdir == NULL) + tmpdir = getenv("TMPDIR"); + + /* These two env variables are probably + * broken, but maybe some OS uses them? + */ + if (tmpdir == NULL) + tmpdir = getenv("TMP"); + if (tmpdir == NULL) + tmpdir = getenv("TEMP"); + + /* And this is the sane fallback. */ + if (tmpdir == NULL) + tmpdir = "/tmp"; + } + + _dbus_assert(tmpdir != NULL); + + return tmpdir; +} + +/** + * Execute a subprocess, returning up to 1024 bytes of output + * into @p result. + * + * If successful, returns #TRUE and appends the output to @p + * result. If a failure happens, returns #FALSE and + * sets an error in @p error. + * + * @note It's not an error if the subprocess terminates normally + * without writing any data to stdout. Verify the @p result length + * before and after this function call to cover this case. + * + * @param progname initial path to exec (may or may not be absolute) + * @param path_fallback if %TRUE, search PATH for executable + * @param argv NULL-terminated list of arguments + * @param result a DBusString where the output can be append + * @param error a DBusError to store the error in case of failure + * @returns #TRUE on success, #FALSE if an error happened + */ +static dbus_bool_t +_read_subprocess_line_argv (const char *progpath, + dbus_bool_t path_fallback, + char * const *argv, + DBusString *result, + DBusError *error) +{ + int result_pipe[2] = { -1, -1 }; + int errors_pipe[2] = { -1, -1 }; + pid_t pid; + int ret; + int status; + int orig_len; + int i; + + dbus_bool_t retval; + sigset_t new_set, old_set; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + retval = FALSE; + + /* We need to block any existing handlers for SIGCHLD temporarily; they + * will cause waitpid() below to fail. + * https://bugs.freedesktop.org/show_bug.cgi?id=21347 + */ + sigemptyset (&new_set); + sigaddset (&new_set, SIGCHLD); + sigprocmask (SIG_BLOCK, &new_set, &old_set); + + orig_len = _dbus_string_get_length (result); + +#define READ_END 0 +#define WRITE_END 1 + if (pipe (result_pipe) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to create a pipe to call %s: %s", + progpath, _dbus_strerror (errno)); + _dbus_verbose ("Failed to create a pipe to call %s: %s\n", + progpath, _dbus_strerror (errno)); + goto out; + } + if (pipe (errors_pipe) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to create a pipe to call %s: %s", + progpath, _dbus_strerror (errno)); + _dbus_verbose ("Failed to create a pipe to call %s: %s\n", + progpath, _dbus_strerror (errno)); + goto out; + } + + pid = fork (); + if (pid < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to fork() to call %s: %s", + progpath, _dbus_strerror (errno)); + _dbus_verbose ("Failed to fork() to call %s: %s\n", + progpath, _dbus_strerror (errno)); + goto out; + } + + if (pid == 0) + { + /* child process */ + int maxfds; + int fd; + + fd = open ("/dev/null", O_RDWR); + if (fd == -1) + /* huh?! can't open /dev/null? */ + _exit (1); + + _dbus_verbose ("/dev/null fd %d opened\n", fd); + + /* set-up stdXXX */ + close (result_pipe[READ_END]); + close (errors_pipe[READ_END]); + close (0); /* close stdin */ + close (1); /* close stdout */ + close (2); /* close stderr */ + + if (dup2 (fd, 0) == -1) + _exit (1); + if (dup2 (result_pipe[WRITE_END], 1) == -1) + _exit (1); + if (dup2 (errors_pipe[WRITE_END], 2) == -1) + _exit (1); + + maxfds = sysconf (_SC_OPEN_MAX); + /* Pick something reasonable if for some reason sysconf + * says unlimited. + */ + if (maxfds < 0) + maxfds = 1024; + /* close all inherited fds */ + for (i = 3; i < maxfds; i++) + close (i); + + sigprocmask (SIG_SETMASK, &old_set, NULL); + + /* If it looks fully-qualified, try execv first */ + if (progpath[0] == '/') + { + execv (progpath, argv); + /* Ok, that failed. Now if path_fallback is given, let's + * try unqualified. This is mostly a hack to work + * around systems which ship dbus-launch in /usr/bin + * but everything else in /bin (because dbus-launch + * depends on X11). + */ + if (path_fallback) + /* We must have a slash, because we checked above */ + execvp (strrchr (progpath, '/')+1, argv); + } + else + execvp (progpath, argv); + + /* still nothing, we failed */ + _exit (1); + } + + /* parent process */ + close (result_pipe[WRITE_END]); + close (errors_pipe[WRITE_END]); + result_pipe[WRITE_END] = -1; + errors_pipe[WRITE_END] = -1; + + ret = 0; + do + { + ret = _dbus_read (result_pipe[READ_END], result, 1024); + } + while (ret > 0); + + /* reap the child process to avoid it lingering as zombie */ + do + { + ret = waitpid (pid, &status, 0); + } + while (ret == -1 && errno == EINTR); + + /* We succeeded if the process exited with status 0 and + anything was read */ + if (!WIFEXITED (status) || WEXITSTATUS (status) != 0 ) + { + /* The process ended with error */ + DBusString error_message; + _dbus_string_init (&error_message); + ret = 0; + do + { + ret = _dbus_read (errors_pipe[READ_END], &error_message, 1024); + } + while (ret > 0); + + _dbus_string_set_length (result, orig_len); + if (_dbus_string_get_length (&error_message) > 0) + dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, + "%s terminated abnormally with the following error: %s", + progpath, _dbus_string_get_data (&error_message)); + else + dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, + "%s terminated abnormally without any error message", + progpath); + goto out; + } + + retval = TRUE; + + out: + sigprocmask (SIG_SETMASK, &old_set, NULL); + + if (retval) + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + else + _DBUS_ASSERT_ERROR_IS_SET (error); + + if (result_pipe[0] != -1) + close (result_pipe[0]); + if (result_pipe[1] != -1) + close (result_pipe[1]); + if (errors_pipe[0] != -1) + close (errors_pipe[0]); + if (errors_pipe[1] != -1) + close (errors_pipe[1]); + + return retval; +} + +/** + * Returns the address of a new session bus. + * + * If successful, returns #TRUE and appends the address to @p + * address. If a failure happens, returns #FALSE and + * sets an error in @p error. + * + * @param address a DBusString where the address can be stored + * @param error a DBusError to store the error in case of failure + * @returns #TRUE on success, #FALSE if an error happened + */ +dbus_bool_t +_dbus_get_autolaunch_address (DBusString *address, + DBusError *error) +{ + static char *argv[6]; + int i; + DBusString uuid; + dbus_bool_t retval; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + retval = FALSE; + + if (!_dbus_string_init (&uuid)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_get_local_machine_uuid_encoded (&uuid)) + { + _DBUS_SET_OOM (error); + goto out; + } + + i = 0; + argv[i] = "dbus-launch"; + ++i; + argv[i] = "--autolaunch"; + ++i; + argv[i] = _dbus_string_get_data (&uuid); + ++i; + argv[i] = "--binary-syntax"; + ++i; + argv[i] = "--close-stderr"; + ++i; + argv[i] = NULL; + ++i; + + _dbus_assert (i == _DBUS_N_ELEMENTS (argv)); + + retval = _read_subprocess_line_argv (DBUS_BINDIR "/dbus-launch", + TRUE, + argv, address, error); + + out: + _dbus_string_free (&uuid); + return retval; +} + +/** + * Reads the uuid of the machine we're running on from + * the dbus configuration. Optionally try to create it + * (only root can do this usually). + * + * On UNIX, reads a file that gets created by dbus-uuidgen + * in a post-install script. On Windows, if there's a standard + * machine uuid we could just use that, but I can't find one + * with the right properties (the hardware profile guid can change + * without rebooting I believe). If there's no standard one + * we might want to use the registry instead of a file for + * this, and I'm not sure how we'd ensure the uuid gets created. + * + * @param machine_id guid to init with the machine's uuid + * @param create_if_not_found try to create the uuid if it doesn't exist + * @param error the error return + * @returns #FALSE if the error is set + */ +dbus_bool_t +_dbus_read_local_machine_uuid (DBusGUID *machine_id, + dbus_bool_t create_if_not_found, + DBusError *error) +{ + DBusString filename; + _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE); + return _dbus_read_uuid_file (&filename, machine_id, create_if_not_found, error); +} + +#define DBUS_UNIX_STANDARD_SESSION_SERVICEDIR "/dbus-1/services" +#define DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services" + +/** + * Determines the address of the session bus by querying a + * platform-specific method. + * + * The first parameter will be a boolean specifying whether + * or not a dynamic session lookup is supported on this platform. + * + * If supported is TRUE and the return value is #TRUE, the + * address will be appended to @p address. + * If a failure happens, returns #FALSE and sets an error in + * @p error. + * + * If supported is FALSE, ignore the return value. + * + * @param supported returns whether this method is supported + * @param address a DBusString where the address can be stored + * @param error a DBusError to store the error in case of failure + * @returns #TRUE on success, #FALSE if an error happened + */ +dbus_bool_t +_dbus_lookup_session_address (dbus_bool_t *supported, + DBusString *address, + DBusError *error) +{ + /* On non-Mac Unix platforms, if the session address isn't already + * set in DBUS_SESSION_BUS_ADDRESS environment variable, we punt and + * fall back to the autolaunch: global default; see + * init_session_address in dbus/dbus-bus.c. */ + *supported = FALSE; + return TRUE; +} + +/** + * Returns the standard directories for a session bus to look for service + * activation files + * + * On UNIX this should be the standard xdg freedesktop.org data directories: + * + * XDG_DATA_HOME=${XDG_DATA_HOME-$HOME/.local/share} + * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share} + * + * and + * + * DBUS_DATADIR + * + * @param dirs the directory list we are returning + * @returns #FALSE on OOM + */ + +dbus_bool_t +_dbus_get_standard_session_servicedirs (DBusList **dirs) +{ + const char *xdg_data_home; + const char *xdg_data_dirs; + DBusString servicedir_path; + + if (!_dbus_string_init (&servicedir_path)) + return FALSE; + + xdg_data_home = _dbus_getenv ("XDG_DATA_HOME"); + xdg_data_dirs = _dbus_getenv ("XDG_DATA_DIRS"); + + if (xdg_data_dirs != NULL) + { + if (!_dbus_string_append (&servicedir_path, xdg_data_dirs)) + goto oom; + + if (!_dbus_string_append (&servicedir_path, ":")) + goto oom; + } + else + { + if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:")) + goto oom; + } + + /* + * add configured datadir to defaults + * this may be the same as an xdg dir + * however the config parser should take + * care of duplicates + */ + if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR":")) + goto oom; + + if (xdg_data_home != NULL) + { + if (!_dbus_string_append (&servicedir_path, xdg_data_home)) + goto oom; + } + else + { + const DBusString *homedir; + DBusString local_share; + + if (!_dbus_homedir_from_current_process (&homedir)) + goto oom; + + if (!_dbus_string_append (&servicedir_path, _dbus_string_get_const_data (homedir))) + goto oom; + + _dbus_string_init_const (&local_share, "/.local/share"); + if (!_dbus_concat_dir_and_file (&servicedir_path, &local_share)) + goto oom; + } + + if (!_dbus_split_paths_and_append (&servicedir_path, + DBUS_UNIX_STANDARD_SESSION_SERVICEDIR, + dirs)) + goto oom; + + _dbus_string_free (&servicedir_path); + return TRUE; + + oom: + _dbus_string_free (&servicedir_path); + return FALSE; +} + + +/** + * Returns the standard directories for a system bus to look for service + * activation files + * + * On UNIX this should be the standard xdg freedesktop.org data directories: + * + * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share} + * + * and + * + * DBUS_DATADIR + * + * On Windows there is no system bus and this function can return nothing. + * + * @param dirs the directory list we are returning + * @returns #FALSE on OOM + */ + +dbus_bool_t +_dbus_get_standard_system_servicedirs (DBusList **dirs) +{ + const char *xdg_data_dirs; + DBusString servicedir_path; + + if (!_dbus_string_init (&servicedir_path)) + return FALSE; + + xdg_data_dirs = _dbus_getenv ("XDG_DATA_DIRS"); + + if (xdg_data_dirs != NULL) + { + if (!_dbus_string_append (&servicedir_path, xdg_data_dirs)) + goto oom; + + if (!_dbus_string_append (&servicedir_path, ":")) + goto oom; + } + else + { + if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:")) + goto oom; + } + + /* + * add configured datadir to defaults + * this may be the same as an xdg dir + * however the config parser should take + * care of duplicates + */ + if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR":")) + goto oom; + + if (!_dbus_split_paths_and_append (&servicedir_path, + DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR, + dirs)) + goto oom; + + _dbus_string_free (&servicedir_path); + return TRUE; + + oom: + _dbus_string_free (&servicedir_path); + return FALSE; +} + +/** + * Append the absolute path of the system.conf file + * (there is no system bus on Windows so this can just + * return FALSE and print a warning or something) + * + * @param str the string to append to + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_append_system_config_file (DBusString *str) +{ + return _dbus_string_append (str, DBUS_SYSTEM_CONFIG_FILE); +} + +/** + * Append the absolute path of the session.conf file. + * + * @param str the string to append to + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_append_session_config_file (DBusString *str) +{ + return _dbus_string_append (str, DBUS_SESSION_CONFIG_FILE); +} + +/** + * Called when the bus daemon is signaled to reload its configuration; any + * caches should be nuked. Of course any caches that need explicit reload + * are probably broken, but c'est la vie. + * + * + */ +void +_dbus_flush_caches (void) +{ + _dbus_user_database_flush_system (); +} + +/** + * Appends the directory in which a keyring for the given credentials + * should be stored. The credentials should have either a Windows or + * UNIX user in them. The directory should be an absolute path. + * + * On UNIX the directory is ~/.dbus-keyrings while on Windows it should probably + * be something else, since the dotfile convention is not normal on Windows. + * + * @param directory string to append directory to + * @param credentials credentials the directory should be for + * + * @returns #FALSE on no memory + */ +dbus_bool_t +_dbus_append_keyring_directory_for_credentials (DBusString *directory, + DBusCredentials *credentials) +{ + DBusString homedir; + DBusString dotdir; + dbus_uid_t uid; + + _dbus_assert (credentials != NULL); + _dbus_assert (!_dbus_credentials_are_anonymous (credentials)); + + if (!_dbus_string_init (&homedir)) + return FALSE; + + uid = _dbus_credentials_get_unix_uid (credentials); + _dbus_assert (uid != DBUS_UID_UNSET); + + if (!_dbus_homedir_from_uid (uid, &homedir)) + goto failed; + +#ifdef DBUS_BUILD_TESTS + { + const char *override; + + override = _dbus_getenv ("DBUS_TEST_HOMEDIR"); + if (override != NULL && *override != '\0') + { + _dbus_string_set_length (&homedir, 0); + if (!_dbus_string_append (&homedir, override)) + goto failed; + + _dbus_verbose ("Using fake homedir for testing: %s\n", + _dbus_string_get_const_data (&homedir)); + } + else + { + static dbus_bool_t already_warned = FALSE; + if (!already_warned) + { + _dbus_warn ("Using your real home directory for testing, set DBUS_TEST_HOMEDIR to avoid\n"); + already_warned = TRUE; + } + } + } +#endif + + _dbus_string_init_const (&dotdir, ".dbus-keyrings"); + if (!_dbus_concat_dir_and_file (&homedir, + &dotdir)) + goto failed; + + if (!_dbus_string_copy (&homedir, 0, + directory, _dbus_string_get_length (directory))) { + goto failed; + } + + _dbus_string_free (&homedir); + return TRUE; + + failed: + _dbus_string_free (&homedir); + return FALSE; +} + + +/** + * See if errno is EAGAIN or EWOULDBLOCK (this has to be done differently + * for Winsock so is abstracted) + * + * @returns #TRUE if errno == EAGAIN or errno == EWOULDBLOCK + */ +dbus_bool_t +_dbus_get_is_errno_eagain_or_ewouldblock (void) +{ + return errno == EAGAIN || errno == EWOULDBLOCK; +} + +/* tests in dbus-sysdeps-util.c */ diff --git a/dbus/dbus-sysdeps-unix.h b/dbus/dbus-sysdeps-unix.h new file mode 100644 index 00000000..ecd20f67 --- /dev/null +++ b/dbus/dbus-sysdeps-unix.h @@ -0,0 +1,134 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-sysdeps-unix.h UNIX-specific wrappers around system/libc features (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_SYSDEPS_UNIX_H +#define DBUS_SYSDEPS_UNIX_H + +#include +#include + +#ifdef DBUS_WIN +#error "Don't include this on Windows" +#endif + +DBUS_BEGIN_DECLS + +/** + * @defgroup DBusSysdepsUnix UNIX-specific internal API + * @ingroup DBusInternals + * @brief Internal system-dependent API available on UNIX only + * @{ + */ + +dbus_bool_t +_dbus_close (int fd, + DBusError *error); +int +_dbus_read (int fd, + DBusString *buffer, + int count); +int +_dbus_write (int fd, + const DBusString *buffer, + int start, + int len); +int +_dbus_write_two (int fd, + const DBusString *buffer1, + int start1, + int len1, + const DBusString *buffer2, + int start2, + int len2); + +dbus_bool_t _dbus_open_unix_socket (int *fd, + DBusError *error); +int _dbus_connect_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error); +int _dbus_listen_unix_socket (const char *path, + dbus_bool_t abstract, + DBusError *error); + +dbus_bool_t _dbus_read_credentials (int client_fd, + DBusCredentials *credentials, + DBusError *error); +dbus_bool_t _dbus_send_credentials (int server_fd, + DBusError *error); + +/** Information about a UNIX user */ +typedef struct DBusUserInfo DBusUserInfo; +/** Information about a UNIX group */ +typedef struct DBusGroupInfo DBusGroupInfo; + +/** + * Information about a UNIX user + */ +struct DBusUserInfo +{ + dbus_uid_t uid; /**< UID */ + dbus_gid_t primary_gid; /**< GID */ + dbus_gid_t *group_ids; /**< Groups IDs, *including* above primary group */ + int n_group_ids; /**< Size of group IDs array */ + char *username; /**< Username */ + char *homedir; /**< Home directory */ +}; + +/** + * Information about a UNIX group + */ +struct DBusGroupInfo +{ + dbus_gid_t gid; /**< GID */ + char *groupname; /**< Group name */ +}; + +dbus_bool_t _dbus_user_info_fill (DBusUserInfo *info, + const DBusString *username, + DBusError *error); +dbus_bool_t _dbus_user_info_fill_uid (DBusUserInfo *info, + dbus_uid_t uid, + DBusError *error); +void _dbus_user_info_free (DBusUserInfo *info); + +dbus_bool_t _dbus_group_info_fill (DBusGroupInfo *info, + const DBusString *groupname, + DBusError *error); +dbus_bool_t _dbus_group_info_fill_gid (DBusGroupInfo *info, + dbus_gid_t gid, + DBusError *error); +void _dbus_group_info_free (DBusGroupInfo *info); + +dbus_uid_t _dbus_getuid (void); +dbus_uid_t _dbus_geteuid (void); +dbus_gid_t _dbus_getgid (void); + +dbus_bool_t _dbus_parse_uid (const DBusString *uid_str, + dbus_uid_t *uid); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_SYSDEPS_UNIX_H */ diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c new file mode 100644 index 00000000..93ad253e --- /dev/null +++ b/dbus/dbus-sysdeps-util-unix.c @@ -0,0 +1,1175 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-sysdeps-util-unix.c Would be in dbus-sysdeps-unix.c, but not used in libdbus + * + * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-sysdeps.h" +#include "dbus-sysdeps-unix.h" +#include "dbus-internals.h" +#include "dbus-protocol.h" +#include "dbus-string.h" +#define DBUS_USERDB_INCLUDES_PRIVATE 1 +#include "dbus-userdb.h" +#include "dbus-test.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SYSLIMITS_H +#include +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/** + * @addtogroup DBusInternalsUtils + * @{ + */ + + +/** + * Does the chdir, fork, setsid, etc. to become a daemon process. + * + * @param pidfile #NULL, or pidfile to create + * @param print_pid_pipe pipe to print daemon's pid to, or -1 for none + * @param error return location for errors + * @param keep_umask #TRUE to keep the original umask + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_become_daemon (const DBusString *pidfile, + DBusPipe *print_pid_pipe, + DBusError *error, + dbus_bool_t keep_umask) +{ + const char *s; + pid_t child_pid; + int dev_null_fd; + + _dbus_verbose ("Becoming a daemon...\n"); + + _dbus_verbose ("chdir to /\n"); + if (chdir ("/") < 0) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Could not chdir() to root directory"); + return FALSE; + } + + _dbus_verbose ("forking...\n"); + switch ((child_pid = fork ())) + { + case -1: + _dbus_verbose ("fork failed\n"); + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to fork daemon: %s", _dbus_strerror (errno)); + return FALSE; + break; + + case 0: + _dbus_verbose ("in child, closing std file descriptors\n"); + + /* silently ignore failures here, if someone + * doesn't have /dev/null we may as well try + * to continue anyhow + */ + + dev_null_fd = open ("/dev/null", O_RDWR); + if (dev_null_fd >= 0) + { + dup2 (dev_null_fd, 0); + dup2 (dev_null_fd, 1); + + s = _dbus_getenv ("DBUS_DEBUG_OUTPUT"); + if (s == NULL || *s == '\0') + dup2 (dev_null_fd, 2); + else + _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n"); + } + + if (!keep_umask) + { + /* Get a predictable umask */ + _dbus_verbose ("setting umask\n"); + umask (022); + } + + _dbus_verbose ("calling setsid()\n"); + if (setsid () == -1) + _dbus_assert_not_reached ("setsid() failed"); + + break; + + default: + if (!_dbus_write_pid_to_file_and_pipe (pidfile, print_pid_pipe, + child_pid, error)) + { + _dbus_verbose ("pid file or pipe write failed: %s\n", + error->message); + kill (child_pid, SIGTERM); + return FALSE; + } + + _dbus_verbose ("parent exiting\n"); + _exit (0); + break; + } + + return TRUE; +} + + +/** + * Creates a file containing the process ID. + * + * @param filename the filename to write to + * @param pid our process ID + * @param error return location for errors + * @returns #FALSE on failure + */ +static dbus_bool_t +_dbus_write_pid_file (const DBusString *filename, + unsigned long pid, + DBusError *error) +{ + const char *cfilename; + int fd; + FILE *f; + + cfilename = _dbus_string_get_const_data (filename); + + fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644); + + if (fd < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to open \"%s\": %s", cfilename, + _dbus_strerror (errno)); + return FALSE; + } + + if ((f = fdopen (fd, "w")) == NULL) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno)); + _dbus_close (fd, NULL); + return FALSE; + } + + if (fprintf (f, "%lu\n", pid) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to write to \"%s\": %s", cfilename, + _dbus_strerror (errno)); + + fclose (f); + return FALSE; + } + + if (fclose (f) == EOF) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to close \"%s\": %s", cfilename, + _dbus_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/** + * Writes the given pid_to_write to a pidfile (if non-NULL) and/or to a + * pipe (if non-NULL). Does nothing if pidfile and print_pid_pipe are both + * NULL. + * + * @param pidfile the file to write to or #NULL + * @param print_pid_pipe the pipe to write to or #NULL + * @param pid_to_write the pid to write out + * @param error error on failure + * @returns FALSE if error is set + */ +dbus_bool_t +_dbus_write_pid_to_file_and_pipe (const DBusString *pidfile, + DBusPipe *print_pid_pipe, + dbus_pid_t pid_to_write, + DBusError *error) +{ + if (pidfile) + { + _dbus_verbose ("writing pid file %s\n", _dbus_string_get_const_data (pidfile)); + if (!_dbus_write_pid_file (pidfile, + pid_to_write, + error)) + { + _dbus_verbose ("pid file write failed\n"); + _DBUS_ASSERT_ERROR_IS_SET(error); + return FALSE; + } + } + else + { + _dbus_verbose ("No pid file requested\n"); + } + + if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe)) + { + DBusString pid; + int bytes; + + _dbus_verbose ("writing our pid to pipe %d\n", print_pid_pipe->fd_or_handle); + + if (!_dbus_string_init (&pid)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_append_int (&pid, pid_to_write) || + !_dbus_string_append (&pid, "\n")) + { + _dbus_string_free (&pid); + _DBUS_SET_OOM (error); + return FALSE; + } + + bytes = _dbus_string_get_length (&pid); + if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes) + { + /* _dbus_pipe_write sets error only on failure, not short write */ + if (error != NULL && !dbus_error_is_set(error)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Printing message bus PID: did not write enough bytes\n"); + } + _dbus_string_free (&pid); + return FALSE; + } + + _dbus_string_free (&pid); + } + else + { + _dbus_verbose ("No pid pipe to write to\n"); + } + + return TRUE; +} + +/** + * Verify that after the fork we can successfully change to this user. + * + * @param user the username given in the daemon configuration + * @returns #TRUE if username is valid + */ +dbus_bool_t +_dbus_verify_daemon_user (const char *user) +{ + DBusString u; + + _dbus_string_init_const (&u, user); + + return _dbus_get_user_id_and_primary_group (&u, NULL, NULL); +} + + +/* The HAVE_LIBAUDIT case lives in selinux.c */ +#ifndef HAVE_LIBAUDIT +/** + * Changes the user and group the bus is running as. + * + * @param user the user to become + * @param error return location for errors + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_change_to_daemon_user (const char *user, + DBusError *error) +{ + dbus_uid_t uid; + dbus_gid_t gid; + DBusString u; + + _dbus_string_init_const (&u, user); + + if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "User '%s' does not appear to exist?", + user); + return FALSE; + } + + /* setgroups() only works if we are a privileged process, + * so we don't return error on failure; the only possible + * failure is that we don't have perms to do it. + * + * not sure this is right, maybe if setuid() + * is going to work then setgroups() should also work. + */ + if (setgroups (0, NULL) < 0) + _dbus_warn ("Failed to drop supplementary groups: %s\n", + _dbus_strerror (errno)); + + /* Set GID first, or the setuid may remove our permission + * to change the GID + */ + if (setgid (gid) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to set GID to %lu: %s", gid, + _dbus_strerror (errno)); + return FALSE; + } + + if (setuid (uid) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to set UID to %lu: %s", uid, + _dbus_strerror (errno)); + return FALSE; + } + + return TRUE; +} +#endif /* !HAVE_LIBAUDIT */ + +void +_dbus_init_system_log (void) +{ + openlog ("dbus", LOG_PID, LOG_DAEMON); +} +/** + * Log a message to the system log file (e.g. syslog on Unix). + * + * @param severity a severity value + * @param msg a printf-style format string + * @param args arguments for the format string + * + */ +void +_dbus_system_log (DBusSystemLogSeverity severity, const char *msg, ...) +{ + va_list args; + + va_start (args, msg); + + _dbus_system_logv (severity, msg, args); + + va_end (args); +} + +/** + * Log a message to the system log file (e.g. syslog on Unix). + * + * @param severity a severity value + * @param msg a printf-style format string + * @param args arguments for the format string + * + * If the FATAL severity is given, this function will terminate the program + * with an error code. + */ +void +_dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args) +{ + int flags; + switch (severity) + { + case DBUS_SYSTEM_LOG_INFO: + flags = LOG_DAEMON | LOG_NOTICE; + break; + case DBUS_SYSTEM_LOG_SECURITY: + flags = LOG_AUTH | LOG_NOTICE; + break; + case DBUS_SYSTEM_LOG_FATAL: + flags = LOG_DAEMON|LOG_CRIT; + default: + return; + } + + vsyslog (flags, msg, args); + + if (severity == DBUS_SYSTEM_LOG_FATAL) + exit (1); +} + +/** Installs a UNIX signal handler + * + * @param sig the signal to handle + * @param handler the handler + */ +void +_dbus_set_signal_handler (int sig, + DBusSignalHandler handler) +{ + struct sigaction act; + sigset_t empty_mask; + + sigemptyset (&empty_mask); + act.sa_handler = handler; + act.sa_mask = empty_mask; + act.sa_flags = 0; + sigaction (sig, &act, NULL); +} + + +/** + * Removes a directory; Directory must be empty + * + * @param filename directory filename + * @param error initialized error object + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_delete_directory (const DBusString *filename, + DBusError *error) +{ + const char *filename_c; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + filename_c = _dbus_string_get_const_data (filename); + + if (rmdir (filename_c) != 0) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to remove directory %s: %s\n", + filename_c, _dbus_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +/** Checks if a file exists +* +* @param file full path to the file +* @returns #TRUE if file exists +*/ +dbus_bool_t +_dbus_file_exists (const char *file) +{ + return (access (file, F_OK) == 0); +} + +/** Checks if user is at the console +* +* @param username user to check +* @param error return location for errors +* @returns #TRUE is the user is at the consolei and there are no errors +*/ +dbus_bool_t +_dbus_user_at_console (const char *username, + DBusError *error) +{ + + DBusString f; + dbus_bool_t result; + + result = FALSE; + if (!_dbus_string_init (&f)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR)) + { + _DBUS_SET_OOM (error); + goto out; + } + + + if (!_dbus_string_append (&f, username)) + { + _DBUS_SET_OOM (error); + goto out; + } + + result = _dbus_file_exists (_dbus_string_get_const_data (&f)); + + out: + _dbus_string_free (&f); + + return result; +} + + +/** + * Checks whether the filename is an absolute path + * + * @param filename the filename + * @returns #TRUE if an absolute path + */ +dbus_bool_t +_dbus_path_is_absolute (const DBusString *filename) +{ + if (_dbus_string_get_length (filename) > 0) + return _dbus_string_get_byte (filename, 0) == '/'; + else + return FALSE; +} + +/** + * stat() wrapper. + * + * @param filename the filename to stat + * @param statbuf the stat info to fill in + * @param error return location for error + * @returns #FALSE if error was set + */ +dbus_bool_t +_dbus_stat (const DBusString *filename, + DBusStat *statbuf, + DBusError *error) +{ + const char *filename_c; + struct stat sb; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + filename_c = _dbus_string_get_const_data (filename); + + if (stat (filename_c, &sb) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "%s", _dbus_strerror (errno)); + return FALSE; + } + + statbuf->mode = sb.st_mode; + statbuf->nlink = sb.st_nlink; + statbuf->uid = sb.st_uid; + statbuf->gid = sb.st_gid; + statbuf->size = sb.st_size; + statbuf->atime = sb.st_atime; + statbuf->mtime = sb.st_mtime; + statbuf->ctime = sb.st_ctime; + + return TRUE; +} + + +/** + * Internals of directory iterator + */ +struct DBusDirIter +{ + DIR *d; /**< The DIR* from opendir() */ + +}; + +/** + * Open a directory to iterate over. + * + * @param filename the directory name + * @param error exception return object or #NULL + * @returns new iterator, or #NULL on error + */ +DBusDirIter* +_dbus_directory_open (const DBusString *filename, + DBusError *error) +{ + DIR *d; + DBusDirIter *iter; + const char *filename_c; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + filename_c = _dbus_string_get_const_data (filename); + + d = opendir (filename_c); + if (d == NULL) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to read directory \"%s\": %s", + filename_c, + _dbus_strerror (errno)); + return NULL; + } + iter = dbus_new0 (DBusDirIter, 1); + if (iter == NULL) + { + closedir (d); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "Could not allocate memory for directory iterator"); + return NULL; + } + + iter->d = d; + + return iter; +} + +/* Calculate the required buffer size (in bytes) for directory + * entries read from the given directory handle. Return -1 if this + * this cannot be done. + * + * If you use autoconf, include fpathconf and dirfd in your + * AC_CHECK_FUNCS list. Otherwise use some other method to detect + * and use them where available. + */ +static dbus_bool_t +dirent_buf_size(DIR * dirp, size_t *size) +{ + long name_max; +# if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX) +# if defined(HAVE_DIRFD) + name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX); +# elif defined(HAVE_DDFD) + name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX); +# else + name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX); +# endif /* HAVE_DIRFD */ + if (name_max == -1) +# if defined(NAME_MAX) + name_max = NAME_MAX; +# else + return FALSE; +# endif +# elif defined(MAXNAMELEN) + name_max = MAXNAMELEN; +# else +# if defined(NAME_MAX) + name_max = NAME_MAX; +# else +# error "buffer size for readdir_r cannot be determined" +# endif +# endif + if (size) + *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1; + else + return FALSE; + + return TRUE; +} + +/** + * Get next file in the directory. Will not return "." or ".." on + * UNIX. If an error occurs, the contents of "filename" are + * undefined. The error is never set if the function succeeds. + * + * @param iter the iterator + * @param filename string to be set to the next file in the dir + * @param error return location for error + * @returns #TRUE if filename was filled in with a new filename + */ +dbus_bool_t +_dbus_directory_get_next_file (DBusDirIter *iter, + DBusString *filename, + DBusError *error) +{ + struct dirent *d, *ent; + size_t buf_size; + int err; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!dirent_buf_size (iter->d, &buf_size)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Can't calculate buffer size when reading directory"); + return FALSE; + } + + d = (struct dirent *)dbus_malloc (buf_size); + if (!d) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "No memory to read directory entry"); + return FALSE; + } + + again: + err = readdir_r (iter->d, d, &ent); + if (err || !ent) + { + if (err != 0) + dbus_set_error (error, + _dbus_error_from_errno (err), + "%s", _dbus_strerror (err)); + + dbus_free (d); + return FALSE; + } + else if (ent->d_name[0] == '.' && + (ent->d_name[1] == '\0' || + (ent->d_name[1] == '.' && ent->d_name[2] == '\0'))) + goto again; + else + { + _dbus_string_set_length (filename, 0); + if (!_dbus_string_append (filename, ent->d_name)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "No memory to read directory entry"); + dbus_free (d); + return FALSE; + } + else + { + dbus_free (d); + return TRUE; + } + } +} + +/** + * Closes a directory iteration. + */ +void +_dbus_directory_close (DBusDirIter *iter) +{ + closedir (iter->d); + dbus_free (iter); +} + +static dbus_bool_t +fill_user_info_from_group (struct group *g, + DBusGroupInfo *info, + DBusError *error) +{ + _dbus_assert (g->gr_name != NULL); + + info->gid = g->gr_gid; + info->groupname = _dbus_strdup (g->gr_name); + + /* info->members = dbus_strdupv (g->gr_mem) */ + + if (info->groupname == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return FALSE; + } + + return TRUE; +} + +static dbus_bool_t +fill_group_info (DBusGroupInfo *info, + dbus_gid_t gid, + const DBusString *groupname, + DBusError *error) +{ + const char *group_c_str; + + _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET); + _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET); + + if (groupname) + group_c_str = _dbus_string_get_const_data (groupname); + else + group_c_str = NULL; + + /* For now assuming that the getgrnam() and getgrgid() flavors + * always correspond to the pwnam flavors, if not we have + * to add more configure checks. + */ + +#if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R) + { + struct group *g; + int result; + size_t buflen; + char *buf; + struct group g_str; + dbus_bool_t b; + + /* retrieve maximum needed size for buf */ + buflen = sysconf (_SC_GETGR_R_SIZE_MAX); + + /* sysconf actually returns a long, but everything else expects size_t, + * so just recast here. + * https://bugs.freedesktop.org/show_bug.cgi?id=17061 + */ + if ((long) buflen <= 0) + buflen = 1024; + + result = -1; + while (1) + { + buf = dbus_malloc (buflen); + if (buf == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return FALSE; + } + + g = NULL; +#ifdef HAVE_POSIX_GETPWNAM_R + if (group_c_str) + result = getgrnam_r (group_c_str, &g_str, buf, buflen, + &g); + else + result = getgrgid_r (gid, &g_str, buf, buflen, + &g); +#else + g = getgrnam_r (group_c_str, &g_str, buf, buflen); + result = 0; +#endif /* !HAVE_POSIX_GETPWNAM_R */ + /* Try a bigger buffer if ERANGE was returned: + https://bugs.freedesktop.org/show_bug.cgi?id=16727 + */ + if (result == ERANGE && buflen < 512 * 1024) + { + dbus_free (buf); + buflen *= 2; + } + else + { + break; + } + } + + if (result == 0 && g == &g_str) + { + b = fill_user_info_from_group (g, info, error); + dbus_free (buf); + return b; + } + else + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Group %s unknown or failed to look it up\n", + group_c_str ? group_c_str : "???"); + dbus_free (buf); + return FALSE; + } + } +#else /* ! HAVE_GETPWNAM_R */ + { + /* I guess we're screwed on thread safety here */ + struct group *g; + + g = getgrnam (group_c_str); + + if (g != NULL) + { + return fill_user_info_from_group (g, info, error); + } + else + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Group %s unknown or failed to look it up\n", + group_c_str ? group_c_str : "???"); + return FALSE; + } + } +#endif /* ! HAVE_GETPWNAM_R */ +} + +/** + * Initializes the given DBusGroupInfo struct + * with information about the given group name. + * + * @param info the group info struct + * @param groupname name of group + * @param error the error return + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_group_info_fill (DBusGroupInfo *info, + const DBusString *groupname, + DBusError *error) +{ + return fill_group_info (info, DBUS_GID_UNSET, + groupname, error); + +} + +/** + * Initializes the given DBusGroupInfo struct + * with information about the given group ID. + * + * @param info the group info struct + * @param gid group ID + * @param error the error return + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_group_info_fill_gid (DBusGroupInfo *info, + dbus_gid_t gid, + DBusError *error) +{ + return fill_group_info (info, gid, NULL, error); +} + +/** + * Parse a UNIX user from the bus config file. On Windows, this should + * simply always fail (just return #FALSE). + * + * @param username the username text + * @param uid_p place to return the uid + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_parse_unix_user_from_config (const DBusString *username, + dbus_uid_t *uid_p) +{ + return _dbus_get_user_id (username, uid_p); + +} + +/** + * Parse a UNIX group from the bus config file. On Windows, this should + * simply always fail (just return #FALSE). + * + * @param groupname the groupname text + * @param gid_p place to return the gid + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_parse_unix_group_from_config (const DBusString *groupname, + dbus_gid_t *gid_p) +{ + return _dbus_get_group_id (groupname, gid_p); +} + +/** + * Gets all groups corresponding to the given UNIX user ID. On UNIX, + * just calls _dbus_groups_from_uid(). On Windows, should always + * fail since we don't know any UNIX groups. + * + * @param uid the UID + * @param group_ids return location for array of group IDs + * @param n_group_ids return location for length of returned array + * @returns #TRUE if the UID existed and we got some credentials + */ +dbus_bool_t +_dbus_unix_groups_from_uid (dbus_uid_t uid, + dbus_gid_t **group_ids, + int *n_group_ids) +{ + return _dbus_groups_from_uid (uid, group_ids, n_group_ids); +} + +/** + * Checks to see if the UNIX user ID is at the console. + * Should always fail on Windows (set the error to + * #DBUS_ERROR_NOT_SUPPORTED). + * + * @param uid UID of person to check + * @param error return location for errors + * @returns #TRUE if the UID is the same as the console user and there are no errors + */ +dbus_bool_t +_dbus_unix_user_is_at_console (dbus_uid_t uid, + DBusError *error) +{ + return _dbus_is_console_user (uid, error); + +} + +/** + * Checks to see if the UNIX user ID matches the UID of + * the process. Should always return #FALSE on Windows. + * + * @param uid the UNIX user ID + * @returns #TRUE if this uid owns the process. + */ +dbus_bool_t +_dbus_unix_user_is_process_owner (dbus_uid_t uid) +{ + return uid == _dbus_geteuid (); +} + +/** + * Checks to see if the Windows user SID matches the owner of + * the process. Should always return #FALSE on UNIX. + * + * @param windows_sid the Windows user SID + * @returns #TRUE if this user owns the process. + */ +dbus_bool_t +_dbus_windows_user_is_process_owner (const char *windows_sid) +{ + return FALSE; +} + +/** @} */ /* End of DBusInternalsUtils functions */ + +/** + * @addtogroup DBusString + * + * @{ + */ +/** + * Get the directory name from a complete filename + * @param filename the filename + * @param dirname string to append directory name to + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_string_get_dirname (const DBusString *filename, + DBusString *dirname) +{ + int sep; + + _dbus_assert (filename != dirname); + _dbus_assert (filename != NULL); + _dbus_assert (dirname != NULL); + + /* Ignore any separators on the end */ + sep = _dbus_string_get_length (filename); + if (sep == 0) + return _dbus_string_append (dirname, "."); /* empty string passed in */ + + while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/') + --sep; + + _dbus_assert (sep >= 0); + + if (sep == 0) + return _dbus_string_append (dirname, "/"); + + /* Now find the previous separator */ + _dbus_string_find_byte_backward (filename, sep, '/', &sep); + if (sep < 0) + return _dbus_string_append (dirname, "."); + + /* skip multiple separators */ + while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/') + --sep; + + _dbus_assert (sep >= 0); + + if (sep == 0 && + _dbus_string_get_byte (filename, 0) == '/') + return _dbus_string_append (dirname, "/"); + else + return _dbus_string_copy_len (filename, 0, sep - 0, + dirname, _dbus_string_get_length (dirname)); +} +/** @} */ /* DBusString stuff */ + +static void +string_squash_nonprintable (DBusString *str) +{ + char *buf; + int i, len; + + buf = _dbus_string_get_data (str); + len = _dbus_string_get_length (str); + + for (i = 0; i < len; i++) + { + unsigned char c = (unsigned char) buf[i]; + if (c == '\0') + c = ' '; + else if (c < 0x20 || c > 127) + c = '?'; + } +} + +/** + * Get a printable string describing the command used to execute + * the process with pid. This string should only be used for + * informative purposes such as logging; it may not be trusted. + * + * The command is guaranteed to be printable ASCII and no longer + * than max_len. + * + * @param pid Process id + * @param str Append command to this string + * @param max_len Maximum length of returned command + * @param error return location for errors + * @returns #FALSE on error + */ +dbus_bool_t +_dbus_command_for_pid (unsigned long pid, + DBusString *str, + int max_len, + DBusError *error) +{ + /* This is all Linux-specific for now */ + DBusString path; + DBusString cmdline; + int fd; + + if (!_dbus_string_init (&path)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_init (&cmdline)) + { + _DBUS_SET_OOM (error); + _dbus_string_free (&path); + return FALSE; + } + + if (!_dbus_string_append_printf (&path, "/proc/%ld/cmdline", pid)) + goto oom; + + fd = open (_dbus_string_get_const_data (&path), O_RDONLY); + if (fd < 0) + { + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to open \"%s\": %s", + _dbus_string_get_const_data (&path), + _dbus_strerror (errno)); + goto fail; + } + + if (!_dbus_read (fd, &cmdline, max_len)) + { + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to read from \"%s\": %s", + _dbus_string_get_const_data (&path), + _dbus_strerror (errno)); + goto fail; + } + + if (!_dbus_close (fd, error)) + goto fail; + + string_squash_nonprintable (&cmdline); + + if (!_dbus_string_copy (&cmdline, 0, str, _dbus_string_get_length (str))) + goto oom; + + _dbus_string_free (&cmdline); + _dbus_string_free (&path); + return TRUE; +oom: + _DBUS_SET_OOM (error); +fail: + _dbus_string_free (&cmdline); + _dbus_string_free (&path); + return FALSE; +} + diff --git a/dbus/dbus-sysdeps-util.c b/dbus/dbus-sysdeps-util.c new file mode 100644 index 00000000..67e19f7b --- /dev/null +++ b/dbus/dbus-sysdeps-util.c @@ -0,0 +1,176 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-sysdeps-util.c Tests for dbus-sysdeps.h API + * + * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-sysdeps.h" +#include "dbus-internals.h" +#include "dbus-string.h" +#include "dbus-test.h" + +#ifdef DBUS_BUILD_TESTS +#include +static void +check_dirname (const char *filename, + const char *dirname) +{ + DBusString f, d; + + _dbus_string_init_const (&f, filename); + + if (!_dbus_string_init (&d)) + _dbus_assert_not_reached ("no memory"); + + if (!_dbus_string_get_dirname (&f, &d)) + _dbus_assert_not_reached ("no memory"); + + if (!_dbus_string_equal_c_str (&d, dirname)) + { + _dbus_warn ("For filename \"%s\" got dirname \"%s\" and expected \"%s\"\n", + filename, + _dbus_string_get_const_data (&d), + dirname); + exit (1); + } + + _dbus_string_free (&d); +} + +static void +check_path_absolute (const char *path, + dbus_bool_t expected) +{ + DBusString p; + + _dbus_string_init_const (&p, path); + + if (_dbus_path_is_absolute (&p) != expected) + { + _dbus_warn ("For path \"%s\" expected absolute = %d got %d\n", + path, expected, _dbus_path_is_absolute (&p)); + exit (1); + } +} + +/** + * Unit test for dbus-sysdeps.c. + * + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_sysdeps_test (void) +{ + DBusString str; + double val; + int pos; + +#ifdef DBUS_WIN + check_dirname ("foo\\bar", "foo"); + check_dirname ("foo\\\\bar", "foo"); + check_dirname ("foo/\\/bar", "foo"); + check_dirname ("foo\\bar/", "foo"); + check_dirname ("foo//bar\\", "foo"); + check_dirname ("foo\\bar/", "foo"); + check_dirname ("foo/bar\\\\", "foo"); + check_dirname ("\\foo", "\\"); + check_dirname ("\\\\foo", "\\"); + check_dirname ("\\", "\\"); + check_dirname ("\\\\", "\\"); + check_dirname ("\\/", "\\"); + check_dirname ("/\\/", "/"); + check_dirname ("c:\\foo\\bar", "c:\\foo"); + check_dirname ("c:\\foo", "c:\\"); + check_dirname ("c:/foo", "c:/"); + check_dirname ("c:\\", "c:\\"); + check_dirname ("c:/", "c:/"); + check_dirname ("", "."); +#else + check_dirname ("foo", "."); + check_dirname ("foo/bar", "foo"); + check_dirname ("foo//bar", "foo"); + check_dirname ("foo///bar", "foo"); + check_dirname ("foo/bar/", "foo"); + check_dirname ("foo//bar/", "foo"); + check_dirname ("foo///bar/", "foo"); + check_dirname ("foo/bar//", "foo"); + check_dirname ("foo//bar////", "foo"); + check_dirname ("foo///bar///////", "foo"); + check_dirname ("/foo", "/"); + check_dirname ("////foo", "/"); + check_dirname ("/foo/bar", "/foo"); + check_dirname ("/foo//bar", "/foo"); + check_dirname ("/foo///bar", "/foo"); + check_dirname ("/", "/"); + check_dirname ("///", "/"); + check_dirname ("", "."); +#endif + + _dbus_string_init_const (&str, "3.5"); + if (!_dbus_string_parse_double (&str, + 0, &val, &pos)) + { + _dbus_warn ("Failed to parse double"); + exit (1); + } + if (ABS(3.5 - val) > 1e-6) + { + _dbus_warn ("Failed to parse 3.5 correctly, got: %f", val); + exit (1); + } + if (pos != 3) + { + _dbus_warn ("_dbus_string_parse_double of \"3.5\" returned wrong position %d", pos); + exit (1); + } + + _dbus_string_init_const (&str, "0xff"); + if (_dbus_string_parse_double (&str, + 0, &val, &pos)) + { + _dbus_warn ("Should not have parsed hex as double\n"); + exit (1); + } + +#ifdef DBUS_WIN + check_path_absolute ("c:/", TRUE); + check_path_absolute ("c:/foo", TRUE); + check_path_absolute ("", FALSE); + check_path_absolute ("foo", FALSE); + check_path_absolute ("foo/bar", FALSE); + check_path_absolute ("", FALSE); + check_path_absolute ("foo\\bar", FALSE); + check_path_absolute ("c:\\", TRUE); + check_path_absolute ("c:\\foo", TRUE); + check_path_absolute ("c:", TRUE); + check_path_absolute ("c:\\foo\\bar", TRUE); + check_path_absolute ("\\", TRUE); + check_path_absolute ("/", TRUE); +#else + check_path_absolute ("/", TRUE); + check_path_absolute ("/foo", TRUE); + check_path_absolute ("", FALSE); + check_path_absolute ("foo", FALSE); + check_path_absolute ("foo/bar", FALSE); +#endif + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c new file mode 100644 index 00000000..ccd80ccd --- /dev/null +++ b/dbus/dbus-sysdeps.c @@ -0,0 +1,1102 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-sysdeps.c Wrappers around system/libc features shared between UNIX and Windows (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-sysdeps.h" +#include "dbus-threads.h" +#include "dbus-protocol.h" +#include "dbus-string.h" +#include "dbus-list.h" + +/* NOTE: If you include any unix/windows-specific headers here, you are probably doing something + * wrong and should be putting some code in dbus-sysdeps-unix.c or dbus-sysdeps-win.c. + * + * These are the standard ANSI C headers... + */ +#include +#include +#include +#include + +/* This is UNIX-specific (on windows it's just in stdlib.h I believe) + * but OK since the same stuff does exist on Windows in stdlib.h + * and covered by a configure check. + */ +#ifdef HAVE_ERRNO_H +#include +#endif + +_DBUS_DEFINE_GLOBAL_LOCK (win_fds); +_DBUS_DEFINE_GLOBAL_LOCK (sid_atom_cache); +_DBUS_DEFINE_GLOBAL_LOCK (system_users); + +extern char **environ; + +/** + * @defgroup DBusSysdeps Internal system-dependent API + * @ingroup DBusInternals + * @brief Internal system-dependent API available on UNIX and Windows + * + * The system-dependent API has a dual purpose. First, it encapsulates + * all usage of operating system APIs for ease of auditing and to + * avoid cluttering the rest of the code with bizarre OS quirks and + * headers. Second, it abstracts different operating system APIs for + * portability. + * + * @{ + */ + +/** + * Aborts the program with SIGABRT (dumping core). + */ +void +_dbus_abort (void) +{ + const char *s; + + _dbus_print_backtrace (); + + s = _dbus_getenv ("DBUS_BLOCK_ON_ABORT"); + if (s && *s) + { + /* don't use _dbus_warn here since it can _dbus_abort() */ + fprintf (stderr, " Process %lu sleeping for gdb attach\n", _dbus_pid_for_log ()); + _dbus_sleep_milliseconds (1000 * 180); + } + + abort (); + _dbus_exit (1); /* in case someone manages to ignore SIGABRT ? */ +} + +/** + * Wrapper for setenv(). If the value is #NULL, unsets + * the environment variable. + * + * There is an unfixable memleak in that it is unsafe to + * free memory malloced for use with setenv. This is because + * we can not rely on internal implementation details of + * the underlying libc library. + * + * @param varname name of environment variable + * @param value value of environment variable + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_setenv (const char *varname, + const char *value) +{ + _dbus_assert (varname != NULL); + + if (value == NULL) + { +#ifdef HAVE_UNSETENV + unsetenv (varname); + return TRUE; +#else + char *putenv_value; + size_t len; + + len = strlen (varname); + + /* Use system malloc to avoid memleaks that dbus_malloc + * will get upset about. + */ + + putenv_value = malloc (len + 2); + if (putenv_value == NULL) + return FALSE; + + strcpy (putenv_value, varname); +#if defined(DBUS_WIN) + strcat (putenv_value, "="); +#endif + + return (putenv (putenv_value) == 0); +#endif + } + else + { +#ifdef HAVE_SETENV + return (setenv (varname, value, TRUE) == 0); +#else + char *putenv_value; + size_t len; + size_t varname_len; + size_t value_len; + + varname_len = strlen (varname); + value_len = strlen (value); + + len = varname_len + value_len + 1 /* '=' */ ; + + /* Use system malloc to avoid memleaks that dbus_malloc + * will get upset about. + */ + + putenv_value = malloc (len + 1); + if (putenv_value == NULL) + return FALSE; + + strcpy (putenv_value, varname); + strcpy (putenv_value + varname_len, "="); + strcpy (putenv_value + varname_len + 1, value); + + return (putenv (putenv_value) == 0); +#endif + } +} + +/** + * Wrapper for getenv(). + * + * @param varname name of environment variable + * @returns value of environment variable or #NULL if unset + */ +const char* +_dbus_getenv (const char *varname) +{ + return getenv (varname); +} + +/** + * Wrapper for clearenv(). + * + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_clearenv (void) +{ + dbus_bool_t rc = TRUE; + +#ifdef HAVE_CLEARENV + if (clearenv () != 0) + rc = FALSE; +#else + + if (environ != NULL) + environ[0] = NULL; +#endif + + return rc; +} + +/** + * Gets a #NULL-terminated list of key=value pairs from the + * environment. Use dbus_free_string_array to free it. + * + * @returns the environment or #NULL on OOM + */ +char ** +_dbus_get_environment (void) +{ + int i, length; + char **environment; + + _dbus_assert (environ != NULL); + + for (length = 0; environ[length] != NULL; length++); + + /* Add one for NULL */ + length++; + + environment = dbus_new0 (char *, length); + + if (environment == NULL) + return NULL; + + for (i = 0; environ[i] != NULL; i++) + { + environment[i] = _dbus_strdup (environ[i]); + + if (environment[i] == NULL) + break; + } + + if (environ[i] != NULL) + { + dbus_free_string_array (environment); + environment = NULL; + } + + return environment; +} + +/* + * init a pipe instance. + * + * @param pipe the pipe + * @param fd the file descriptor to init from + */ +void +_dbus_pipe_init (DBusPipe *pipe, + int fd) +{ + pipe->fd_or_handle = fd; +} + +/** + * init a pipe with stdout + * + * @param pipe the pipe + */ +void +_dbus_pipe_init_stdout (DBusPipe *pipe) +{ + _dbus_pipe_init (pipe, 1); +} + +/** + * check if a pipe is valid; pipes can be set invalid, similar to + * a -1 file descriptor. + * + * @param pipe the pipe instance + * @returns #FALSE if pipe is not valid + */ +dbus_bool_t +_dbus_pipe_is_valid(DBusPipe *pipe) +{ + return pipe->fd_or_handle >= 0; +} + +/** + * Check if a pipe is stdout or stderr. + * + * @param pipe the pipe instance + * @returns #TRUE if pipe is one of the standard out/err channels + */ +dbus_bool_t +_dbus_pipe_is_stdout_or_stderr (DBusPipe *pipe) +{ + return pipe->fd_or_handle == 1 || pipe->fd_or_handle == 2; +} + +/** + * Initializes a pipe to an invalid value. + * @param pipe the pipe + */ +void +_dbus_pipe_invalidate (DBusPipe *pipe) +{ + pipe->fd_or_handle = -1; +} + +/** + * Split paths into a list of char strings + * + * @param dirs string with pathes + * @param suffix string concated to each path in dirs + * @param dir_list contains a list of splitted pathes + * return #TRUE is pathes could be splittes,#FALSE in oom case + */ +dbus_bool_t +_dbus_split_paths_and_append (DBusString *dirs, + const char *suffix, + DBusList **dir_list) +{ + int start; + int i; + int len; + char *cpath; + DBusString file_suffix; + + start = 0; + i = 0; + + _dbus_string_init_const (&file_suffix, suffix); + + len = _dbus_string_get_length (dirs); + + while (_dbus_string_find (dirs, start, _DBUS_PATH_SEPARATOR, &i)) + { + DBusString path; + + if (!_dbus_string_init (&path)) + goto oom; + + if (!_dbus_string_copy_len (dirs, + start, + i - start, + &path, + 0)) + { + _dbus_string_free (&path); + goto oom; + } + + _dbus_string_chop_white (&path); + + /* check for an empty path */ + if (_dbus_string_get_length (&path) == 0) + goto next; + + if (!_dbus_concat_dir_and_file (&path, + &file_suffix)) + { + _dbus_string_free (&path); + goto oom; + } + + if (!_dbus_string_copy_data(&path, &cpath)) + { + _dbus_string_free (&path); + goto oom; + } + + if (!_dbus_list_append (dir_list, cpath)) + { + _dbus_string_free (&path); + dbus_free (cpath); + goto oom; + } + + next: + _dbus_string_free (&path); + start = i + 1; + } + + if (start != len) + { + DBusString path; + + if (!_dbus_string_init (&path)) + goto oom; + + if (!_dbus_string_copy_len (dirs, + start, + len - start, + &path, + 0)) + { + _dbus_string_free (&path); + goto oom; + } + + if (!_dbus_concat_dir_and_file (&path, + &file_suffix)) + { + _dbus_string_free (&path); + goto oom; + } + + if (!_dbus_string_copy_data(&path, &cpath)) + { + _dbus_string_free (&path); + goto oom; + } + + if (!_dbus_list_append (dir_list, cpath)) + { + _dbus_string_free (&path); + dbus_free (cpath); + goto oom; + } + + _dbus_string_free (&path); + } + + return TRUE; + + oom: + _dbus_list_foreach (dir_list, (DBusForeachFunction)dbus_free, NULL); + _dbus_list_clear (dir_list); + return FALSE; +} + +/** @} */ + +/** + * @addtogroup DBusString + * + * @{ + */ +/** + * Appends an integer to a DBusString. + * + * @param str the string + * @param value the integer value + * @returns #FALSE if not enough memory or other failure. + */ +dbus_bool_t +_dbus_string_append_int (DBusString *str, + long value) +{ + /* this calculation is from comp.lang.c faq */ +#define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1) /* +1 for '-' */ + int orig_len; + int i; + char *buf; + + orig_len = _dbus_string_get_length (str); + + if (!_dbus_string_lengthen (str, MAX_LONG_LEN)) + return FALSE; + + buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN); + + snprintf (buf, MAX_LONG_LEN, "%ld", value); + + i = 0; + while (*buf) + { + ++buf; + ++i; + } + + _dbus_string_shorten (str, MAX_LONG_LEN - i); + + return TRUE; +} + +/** + * Appends an unsigned integer to a DBusString. + * + * @param str the string + * @param value the integer value + * @returns #FALSE if not enough memory or other failure. + */ +dbus_bool_t +_dbus_string_append_uint (DBusString *str, + unsigned long value) +{ + /* this is wrong, but definitely on the high side. */ +#define MAX_ULONG_LEN (MAX_LONG_LEN * 2) + int orig_len; + int i; + char *buf; + + orig_len = _dbus_string_get_length (str); + + if (!_dbus_string_lengthen (str, MAX_ULONG_LEN)) + return FALSE; + + buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN); + + snprintf (buf, MAX_ULONG_LEN, "%lu", value); + + i = 0; + while (*buf) + { + ++buf; + ++i; + } + + _dbus_string_shorten (str, MAX_ULONG_LEN - i); + + return TRUE; +} + +#ifdef DBUS_BUILD_TESTS +/** + * Appends a double to a DBusString. + * + * @param str the string + * @param value the floating point value + * @returns #FALSE if not enough memory or other failure. + */ +dbus_bool_t +_dbus_string_append_double (DBusString *str, + double value) +{ +#define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */ + int orig_len; + char *buf; + int i; + + orig_len = _dbus_string_get_length (str); + + if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN)) + return FALSE; + + buf = _dbus_string_get_data_len (str, orig_len, MAX_DOUBLE_LEN); + + snprintf (buf, MAX_LONG_LEN, "%g", value); + + i = 0; + while (*buf) + { + ++buf; + ++i; + } + + _dbus_string_shorten (str, MAX_DOUBLE_LEN - i); + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Parses an integer contained in a DBusString. Either return parameter + * may be #NULL if you aren't interested in it. The integer is parsed + * and stored in value_return. Return parameters are not initialized + * if the function returns #FALSE. + * + * @param str the string + * @param start the byte index of the start of the integer + * @param value_return return location of the integer value or #NULL + * @param end_return return location of the end of the integer, or #NULL + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_string_parse_int (const DBusString *str, + int start, + long *value_return, + int *end_return) +{ + long v; + const char *p; + char *end; + + p = _dbus_string_get_const_data_len (str, start, + _dbus_string_get_length (str) - start); + + end = NULL; + errno = 0; + v = strtol (p, &end, 0); + if (end == NULL || end == p || errno != 0) + return FALSE; + + if (value_return) + *value_return = v; + if (end_return) + *end_return = start + (end - p); + + return TRUE; +} + +/** + * Parses an unsigned integer contained in a DBusString. Either return + * parameter may be #NULL if you aren't interested in it. The integer + * is parsed and stored in value_return. Return parameters are not + * initialized if the function returns #FALSE. + * + * @param str the string + * @param start the byte index of the start of the integer + * @param value_return return location of the integer value or #NULL + * @param end_return return location of the end of the integer, or #NULL + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_string_parse_uint (const DBusString *str, + int start, + unsigned long *value_return, + int *end_return) +{ + unsigned long v; + const char *p; + char *end; + + p = _dbus_string_get_const_data_len (str, start, + _dbus_string_get_length (str) - start); + + end = NULL; + errno = 0; + v = strtoul (p, &end, 0); + if (end == NULL || end == p || errno != 0) + return FALSE; + + if (value_return) + *value_return = v; + if (end_return) + *end_return = start + (end - p); + + return TRUE; +} + +#ifdef DBUS_BUILD_TESTS +static dbus_bool_t +ascii_isspace (char c) +{ + return (c == ' ' || + c == '\f' || + c == '\n' || + c == '\r' || + c == '\t' || + c == '\v'); +} +#endif /* DBUS_BUILD_TESTS */ + +#ifdef DBUS_BUILD_TESTS +static dbus_bool_t +ascii_isdigit (char c) +{ + return c >= '0' && c <= '9'; +} +#endif /* DBUS_BUILD_TESTS */ + +#ifdef DBUS_BUILD_TESTS +static dbus_bool_t +ascii_isxdigit (char c) +{ + return (ascii_isdigit (c) || + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F')); +} +#endif /* DBUS_BUILD_TESTS */ + +#ifdef DBUS_BUILD_TESTS +/* Calls strtod in a locale-independent fashion, by looking at + * the locale data and patching the decimal comma to a point. + * + * Relicensed from glib. + */ +static double +ascii_strtod (const char *nptr, + char **endptr) +{ + /* FIXME: The Win32 C library's strtod() doesn't handle hex. + * Presumably many Unixes don't either. + */ + + char *fail_pos; + double val; + struct lconv *locale_data; + const char *decimal_point; + int decimal_point_len; + const char *p, *decimal_point_pos; + const char *end = NULL; /* Silence gcc */ + + fail_pos = NULL; + + locale_data = localeconv (); + decimal_point = locale_data->decimal_point; + decimal_point_len = strlen (decimal_point); + + _dbus_assert (decimal_point_len != 0); + + decimal_point_pos = NULL; + if (decimal_point[0] != '.' || + decimal_point[1] != 0) + { + p = nptr; + /* Skip leading space */ + while (ascii_isspace (*p)) + p++; + + /* Skip leading optional sign */ + if (*p == '+' || *p == '-') + p++; + + if (p[0] == '0' && + (p[1] == 'x' || p[1] == 'X')) + { + p += 2; + /* HEX - find the (optional) decimal point */ + + while (ascii_isxdigit (*p)) + p++; + + if (*p == '.') + { + decimal_point_pos = p++; + + while (ascii_isxdigit (*p)) + p++; + + if (*p == 'p' || *p == 'P') + p++; + if (*p == '+' || *p == '-') + p++; + while (ascii_isdigit (*p)) + p++; + end = p; + } + } + else + { + while (ascii_isdigit (*p)) + p++; + + if (*p == '.') + { + decimal_point_pos = p++; + + while (ascii_isdigit (*p)) + p++; + + if (*p == 'e' || *p == 'E') + p++; + if (*p == '+' || *p == '-') + p++; + while (ascii_isdigit (*p)) + p++; + end = p; + } + } + /* For the other cases, we need not convert the decimal point */ + } + + /* Set errno to zero, so that we can distinguish zero results + and underflows */ + errno = 0; + + if (decimal_point_pos) + { + char *copy, *c; + + /* We need to convert the '.' to the locale specific decimal point */ + copy = dbus_malloc (end - nptr + 1 + decimal_point_len); + + c = copy; + memcpy (c, nptr, decimal_point_pos - nptr); + c += decimal_point_pos - nptr; + memcpy (c, decimal_point, decimal_point_len); + c += decimal_point_len; + memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1)); + c += end - (decimal_point_pos + 1); + *c = 0; + + val = strtod (copy, &fail_pos); + + if (fail_pos) + { + if (fail_pos > decimal_point_pos) + fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1); + else + fail_pos = (char *)nptr + (fail_pos - copy); + } + + dbus_free (copy); + + } + else + val = strtod (nptr, &fail_pos); + + if (endptr) + *endptr = fail_pos; + + return val; +} +#endif /* DBUS_BUILD_TESTS */ + +#ifdef DBUS_BUILD_TESTS +/** + * Parses a floating point number contained in a DBusString. Either + * return parameter may be #NULL if you aren't interested in it. The + * integer is parsed and stored in value_return. Return parameters are + * not initialized if the function returns #FALSE. + * + * @param str the string + * @param start the byte index of the start of the float + * @param value_return return location of the float value or #NULL + * @param end_return return location of the end of the float, or #NULL + * @returns #TRUE on success + */ +dbus_bool_t +_dbus_string_parse_double (const DBusString *str, + int start, + double *value_return, + int *end_return) +{ + double v; + const char *p; + char *end; + + p = _dbus_string_get_const_data_len (str, start, + _dbus_string_get_length (str) - start); + + /* parsing hex works on linux but isn't portable, so intercept it + * here to get uniform behavior. + */ + if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) + return FALSE; + + end = NULL; + errno = 0; + v = ascii_strtod (p, &end); + if (end == NULL || end == p || errno != 0) + return FALSE; + + if (value_return) + *value_return = v; + if (end_return) + *end_return = start + (end - p); + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ + +/** @} */ /* DBusString group */ + +/** + * @addtogroup DBusInternalsUtils + * @{ + */ + +void +_dbus_generate_pseudorandom_bytes_buffer (char *buffer, + int n_bytes) +{ + long tv_usec; + int i; + + /* fall back to pseudorandom */ + _dbus_verbose ("Falling back to pseudorandom for %d bytes\n", + n_bytes); + + _dbus_get_current_time (NULL, &tv_usec); + srand (tv_usec); + + i = 0; + while (i < n_bytes) + { + double r; + unsigned int b; + + r = rand (); + b = (r / (double) RAND_MAX) * 255.0; + + buffer[i] = b; + + ++i; + } +} + +/** + * Fills n_bytes of the given buffer with random bytes. + * + * @param buffer an allocated buffer + * @param n_bytes the number of bytes in buffer to write to + */ +void +_dbus_generate_random_bytes_buffer (char *buffer, + int n_bytes) +{ + DBusString str; + + if (!_dbus_string_init (&str)) + { + _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes); + return; + } + + if (!_dbus_generate_random_bytes (&str, n_bytes)) + { + _dbus_string_free (&str); + _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes); + return; + } + + _dbus_string_copy_to_buffer (&str, buffer, n_bytes); + + _dbus_string_free (&str); +} + +/** + * Generates the given number of random bytes, where the bytes are + * chosen from the alphanumeric ASCII subset. + * + * @param str the string + * @param n_bytes the number of random ASCII bytes to append to string + * @returns #TRUE on success, #FALSE if no memory or other failure + */ +dbus_bool_t +_dbus_generate_random_ascii (DBusString *str, + int n_bytes) +{ + static const char letters[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + int len; + + if (!_dbus_generate_random_bytes (str, n_bytes)) + return FALSE; + + len = _dbus_string_get_length (str); + i = len - n_bytes; + while (i < len) + { + _dbus_string_set_byte (str, i, + letters[_dbus_string_get_byte (str, i) % + (sizeof (letters) - 1)]); + + ++i; + } + + _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes, + n_bytes)); + + return TRUE; +} + +/** + * Converts a UNIX or Windows errno + * into a #DBusError name. + * + * @todo should cover more errnos, specifically those + * from open(). + * + * @param error_number the errno. + * @returns an error name + */ +const char* +_dbus_error_from_errno (int error_number) +{ + switch (error_number) + { + case 0: + return DBUS_ERROR_FAILED; + +#ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: + return DBUS_ERROR_NOT_SUPPORTED; +#endif +#ifdef EAFNOSUPPORT + case EAFNOSUPPORT: + return DBUS_ERROR_NOT_SUPPORTED; +#endif +#ifdef ENFILE + case ENFILE: + return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */ +#endif +#ifdef EMFILE + case EMFILE: + return DBUS_ERROR_LIMITS_EXCEEDED; +#endif +#ifdef EACCES + case EACCES: + return DBUS_ERROR_ACCESS_DENIED; +#endif +#ifdef EPERM + case EPERM: + return DBUS_ERROR_ACCESS_DENIED; +#endif +#ifdef ENOBUFS + case ENOBUFS: + return DBUS_ERROR_NO_MEMORY; +#endif +#ifdef ENOMEM + case ENOMEM: + return DBUS_ERROR_NO_MEMORY; +#endif +#ifdef EINVAL + case EINVAL: + return DBUS_ERROR_FAILED; +#endif +#ifdef EBADF + case EBADF: + return DBUS_ERROR_FAILED; +#endif +#ifdef EFAULT + case EFAULT: + return DBUS_ERROR_FAILED; +#endif +#ifdef ENOTSOCK + case ENOTSOCK: + return DBUS_ERROR_FAILED; +#endif +#ifdef EISCONN + case EISCONN: + return DBUS_ERROR_FAILED; +#endif +#ifdef ECONNREFUSED + case ECONNREFUSED: + return DBUS_ERROR_NO_SERVER; +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: + return DBUS_ERROR_TIMEOUT; +#endif +#ifdef ENETUNREACH + case ENETUNREACH: + return DBUS_ERROR_NO_NETWORK; +#endif +#ifdef EADDRINUSE + case EADDRINUSE: + return DBUS_ERROR_ADDRESS_IN_USE; +#endif +#ifdef EEXIST + case EEXIST: + return DBUS_ERROR_FILE_EXISTS; +#endif +#ifdef ENOENT + case ENOENT: + return DBUS_ERROR_FILE_NOT_FOUND; +#endif + } + + return DBUS_ERROR_FAILED; +} + +/** + * Assign 0 to the global errno variable + */ +void +_dbus_set_errno_to_zero (void) +{ + errno = 0; +} + +/** + * See if errno is set + * @returns #TRUE if errno is not 0 + */ +dbus_bool_t +_dbus_get_is_errno_nonzero (void) +{ + return errno != 0; +} + +/** + * See if errno is ENOMEM + * @returns #TRUE if errno == ENOMEM + */ +dbus_bool_t +_dbus_get_is_errno_enomem (void) +{ + return errno == ENOMEM; +} + +/** + * See if errno is EINTR + * @returns #TRUE if errno == EINTR + */ +dbus_bool_t +_dbus_get_is_errno_eintr (void) +{ + return errno == EINTR; +} + +/** + * See if errno is EPIPE + * @returns #TRUE if errno == EPIPE + */ +dbus_bool_t +_dbus_get_is_errno_epipe (void) +{ + return errno == EPIPE; +} + +/** + * Get error message from errno + * @returns _dbus_strerror(errno) + */ +const char* +_dbus_strerror_from_errno (void) +{ + return _dbus_strerror (errno); +} + +/** @} end of sysdeps */ + +/* tests in dbus-sysdeps-util.c */ diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h new file mode 100644 index 00000000..7817e04f --- /dev/null +++ b/dbus/dbus-sysdeps.h @@ -0,0 +1,531 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-sysdeps.h Wrappers around system/libc features (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2003 Red Hat, Inc. + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_SYSDEPS_H +#define DBUS_SYSDEPS_H + +#include + +#include + +/* this is perhaps bogus, but strcmp() etc. are faster if we use the + * stuff straight out of string.h, so have this here for now. + */ +#include +#include + + +/* AIX sys/poll.h does #define events reqevents, and other + * wonderousness, so must include sys/poll before declaring + * DBusPollFD + */ +#ifdef HAVE_POLL +#include +#endif + +DBUS_BEGIN_DECLS + +#ifdef DBUS_WIN +#define _DBUS_PATH_SEPARATOR ";" +#else +#define _DBUS_PATH_SEPARATOR ":" +#endif + +/* Forward declarations */ + +/** An opaque string type */ +typedef struct DBusString DBusString; + +/** An opaque list type */ +typedef struct DBusList DBusList; + +/** Object that contains a list of credentials such as UNIX or Windows user ID */ +typedef struct DBusCredentials DBusCredentials; + +/** + * @addtogroup DBusSysdeps + * + * @{ + */ + +/* The idea of this file is to encapsulate everywhere that we're + * relying on external libc features, for ease of security + * auditing. The idea is from vsftpd. This also gives us a chance to + * make things more convenient to use, e.g. by reading into a + * DBusString. Operating system headers aren't intended to be used + * outside of this file and a limited number of others (such as + * dbus-memory.c) + */ + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +#define _DBUS_GNUC_PRINTF( format_idx, arg_idx ) \ + __attribute__((__format__ (__printf__, format_idx, arg_idx))) +#define _DBUS_GNUC_NORETURN \ + __attribute__((__noreturn__)) +#else /* !__GNUC__ */ +#define _DBUS_GNUC_PRINTF( format_idx, arg_idx ) +#define _DBUS_GNUC_NORETURN +#endif /* !__GNUC__ */ + +/** @def _DBUS_GNUC_PRINTF + * used to tell gcc about printf format strings + */ +/** @def _DBUS_GNUC_NORETURN + * used to tell gcc about functions that never return, such as _dbus_abort() + */ + +void _dbus_abort (void) _DBUS_GNUC_NORETURN; + +const char* _dbus_getenv (const char *varname); +dbus_bool_t _dbus_setenv (const char *varname, + const char *value); +dbus_bool_t _dbus_clearenv (void); +char ** _dbus_get_environment (void); + +/** A process ID */ +typedef unsigned long dbus_pid_t; +/** A user ID */ +typedef unsigned long dbus_uid_t; +/** A group ID */ +typedef unsigned long dbus_gid_t; + +/** an invalid PID used to represent an uninitialized dbus_pid_t field */ +#define DBUS_PID_UNSET ((dbus_pid_t) -1) +/** an invalid UID used to represent an uninitialized dbus_uid_t field */ +#define DBUS_UID_UNSET ((dbus_uid_t) -1) +/** an invalid GID used to represent an uninitialized dbus_gid_t field */ +#define DBUS_GID_UNSET ((dbus_gid_t) -1) + +/** an appropriate printf format for dbus_pid_t */ +#define DBUS_PID_FORMAT "%lu" +/** an appropriate printf format for dbus_uid_t */ +#define DBUS_UID_FORMAT "%lu" +/** an appropriate printf format for dbus_gid_t */ +#define DBUS_GID_FORMAT "%lu" + + +/** + * Socket interface + * + * @todo Use for the file descriptors a struct + * - struct DBusSocket{ int d; }; - + * instead of int to get type-safety which + * will be checked by the compiler. + * + */ + +dbus_bool_t _dbus_open_tcp_socket (int *fd, + DBusError *error); +dbus_bool_t _dbus_close_socket (int fd, + DBusError *error); +int _dbus_read_socket (int fd, + DBusString *buffer, + int count); +int _dbus_write_socket (int fd, + const DBusString *buffer, + int start, + int len); +int _dbus_write_socket_two (int fd, + const DBusString *buffer1, + int start1, + int len1, + const DBusString *buffer2, + int start2, + int len2); +int _dbus_connect_tcp_socket (const char *host, + const char *port, + const char *family, + DBusError *error); +int _dbus_listen_tcp_socket (const char *host, + const char *port, + const char *family, + DBusString *retport, + int **fds_p, + DBusError *error); +int _dbus_accept (int listen_fd); + + +dbus_bool_t _dbus_read_credentials_socket (int client_fd, + DBusCredentials *credentials, + DBusError *error); +dbus_bool_t _dbus_send_credentials_socket (int server_fd, + DBusError *error); + +dbus_bool_t _dbus_credentials_add_from_user (DBusCredentials *credentials, + const DBusString *username); +dbus_bool_t _dbus_credentials_add_from_current_process (DBusCredentials *credentials); +dbus_bool_t _dbus_append_user_from_current_process (DBusString *str); + +dbus_bool_t _dbus_parse_unix_user_from_config (const DBusString *username, + dbus_uid_t *uid_p); +dbus_bool_t _dbus_parse_unix_group_from_config (const DBusString *groupname, + dbus_gid_t *gid_p); +dbus_bool_t _dbus_unix_groups_from_uid (dbus_uid_t uid, + dbus_gid_t **group_ids, + int *n_group_ids); +dbus_bool_t _dbus_unix_user_is_at_console (dbus_uid_t uid, + DBusError *error); +dbus_bool_t _dbus_unix_user_is_process_owner (dbus_uid_t uid); +dbus_bool_t _dbus_windows_user_is_process_owner (const char *windows_sid); + +dbus_bool_t _dbus_append_keyring_directory_for_credentials (DBusString *directory, + DBusCredentials *credentials); + +/** Opaque type representing an atomically-modifiable integer + * that can be used from multiple threads. + */ +typedef struct DBusAtomic DBusAtomic; + +/** + * An atomic integer safe to increment or decrement from multiple threads. + */ +struct DBusAtomic +{ +#ifdef DBUS_WIN + volatile long value; /**< Value of the atomic integer. */ +#else + volatile dbus_int32_t value; /**< Value of the atomic integer. */ +#endif +}; + +/* The value we get from autofoo is in the form of a cpp expression; + * convert that to a conventional defined/undef switch. (We can't get + * the conventional defined/undef because of multiarch builds only running + * ./configure once, on Darwin.) */ +#if DBUS_HAVE_ATOMIC_INT_COND +# define DBUS_HAVE_ATOMIC_INT 1 +#else +# undef DBUS_HAVE_ATOMIC_INT +#endif + +dbus_int32_t _dbus_atomic_inc (DBusAtomic *atomic); +dbus_int32_t _dbus_atomic_dec (DBusAtomic *atomic); + + +/* AIX uses different values for poll */ + +#ifdef _AIX +/** There is data to read */ +#define _DBUS_POLLIN 0x0001 +/** There is urgent data to read */ +#define _DBUS_POLLPRI 0x0004 +/** Writing now will not block */ +#define _DBUS_POLLOUT 0x0002 +/** Error condition */ +#define _DBUS_POLLERR 0x4000 +/** Hung up */ +#define _DBUS_POLLHUP 0x2000 +/** Invalid request: fd not open */ +#define _DBUS_POLLNVAL 0x8000 +#elif defined(__HAIKU__) +/** There is data to read */ +#define _DBUS_POLLIN 0x0001 +/** Writing now will not block */ +#define _DBUS_POLLOUT 0x0002 +/** Error condition */ +#define _DBUS_POLLERR 0x0004 +/** There is urgent data to read */ +#define _DBUS_POLLPRI 0x0020 +/** Hung up */ +#define _DBUS_POLLHUP 0x0080 +/** Invalid request: fd not open */ +#define _DBUS_POLLNVAL 0x1000 +#else +/** There is data to read */ +#define _DBUS_POLLIN 0x0001 +/** There is urgent data to read */ +#define _DBUS_POLLPRI 0x0002 +/** Writing now will not block */ +#define _DBUS_POLLOUT 0x0004 +/** Error condition */ +#define _DBUS_POLLERR 0x0008 +/** Hung up */ +#define _DBUS_POLLHUP 0x0010 +/** Invalid request: fd not open */ +#define _DBUS_POLLNVAL 0x0020 +#endif + +/** + * A portable struct pollfd wrapper. + */ +typedef struct +{ + int fd; /**< File descriptor */ + short events; /**< Events to poll for */ + short revents; /**< Events that occurred */ +} DBusPollFD; + +int _dbus_poll (DBusPollFD *fds, + int n_fds, + int timeout_milliseconds); + +void _dbus_sleep_milliseconds (int milliseconds); + +void _dbus_get_current_time (long *tv_sec, + long *tv_usec); + +/** + * File/directory interface + */ +dbus_bool_t _dbus_file_exists (const char *file); +dbus_bool_t _dbus_file_get_contents (DBusString *str, + const DBusString *filename, + DBusError *error); +dbus_bool_t _dbus_string_save_to_file (const DBusString *str, + const DBusString *filename, + DBusError *error); + +dbus_bool_t _dbus_make_file_world_readable (const DBusString *filename, + DBusError *error); + +dbus_bool_t _dbus_create_file_exclusively (const DBusString *filename, + DBusError *error); +dbus_bool_t _dbus_delete_file (const DBusString *filename, + DBusError *error); +dbus_bool_t _dbus_create_directory (const DBusString *filename, + DBusError *error); +dbus_bool_t _dbus_delete_directory (const DBusString *filename, + DBusError *error); + +dbus_bool_t _dbus_concat_dir_and_file (DBusString *dir, + const DBusString *next_component); +dbus_bool_t _dbus_string_get_dirname (const DBusString *filename, + DBusString *dirname); +dbus_bool_t _dbus_path_is_absolute (const DBusString *filename); + +dbus_bool_t _dbus_get_standard_session_servicedirs (DBusList **dirs); +dbus_bool_t _dbus_get_standard_system_servicedirs (DBusList **dirs); + +dbus_bool_t _dbus_append_system_config_file (DBusString *str); +dbus_bool_t _dbus_append_session_config_file (DBusString *str); + +typedef struct { + int fd_or_handle; +} DBusPipe; + +void _dbus_pipe_init (DBusPipe *pipe, + int fd); +void _dbus_pipe_init_stdout (DBusPipe *pipe); +int _dbus_pipe_write (DBusPipe *pipe, + const DBusString *buffer, + int start, + int len, + DBusError *error); +int _dbus_pipe_close (DBusPipe *pipe, + DBusError *error); +dbus_bool_t _dbus_pipe_is_valid (DBusPipe *pipe); +void _dbus_pipe_invalidate (DBusPipe *pipe); +dbus_bool_t _dbus_pipe_is_stdout_or_stderr (DBusPipe *pipe); + + +/** Opaque type for reading a directory listing */ +typedef struct DBusDirIter DBusDirIter; + +DBusDirIter* _dbus_directory_open (const DBusString *filename, + DBusError *error); +dbus_bool_t _dbus_directory_get_next_file (DBusDirIter *iter, + DBusString *filename, + DBusError *error); +void _dbus_directory_close (DBusDirIter *iter); + +dbus_bool_t _dbus_check_dir_is_private_to_user (DBusString *dir, + DBusError *error); + +void _dbus_fd_set_close_on_exec (int fd); + +const char* _dbus_get_tmpdir (void); + +/** + * Random numbers + */ +void _dbus_generate_pseudorandom_bytes_buffer (char *buffer, + int n_bytes); +void _dbus_generate_random_bytes_buffer (char *buffer, + int n_bytes); +dbus_bool_t _dbus_generate_random_bytes (DBusString *str, + int n_bytes); +dbus_bool_t _dbus_generate_random_ascii (DBusString *str, + int n_bytes); + +const char* _dbus_error_from_errno (int error_number); + +void _dbus_set_errno_to_zero (void); +dbus_bool_t _dbus_get_is_errno_nonzero (void); +dbus_bool_t _dbus_get_is_errno_eagain_or_ewouldblock (void); +dbus_bool_t _dbus_get_is_errno_enomem (void); +dbus_bool_t _dbus_get_is_errno_eintr (void); +dbus_bool_t _dbus_get_is_errno_epipe (void); +const char* _dbus_strerror_from_errno (void); + +void _dbus_disable_sigpipe (void); + + +void _dbus_exit (int code) _DBUS_GNUC_NORETURN; + +int _dbus_printf_string_upper_bound (const char *format, + va_list args); + + +/** + * Portable struct with stat() results + */ +typedef struct +{ + unsigned long mode; /**< File mode */ + unsigned long nlink; /**< Number of hard links */ + dbus_uid_t uid; /**< User owning file */ + dbus_gid_t gid; /**< Group owning file */ + unsigned long size; /**< Size of file */ + unsigned long atime; /**< Access time */ + unsigned long mtime; /**< Modify time */ + unsigned long ctime; /**< Creation time */ +} DBusStat; + +dbus_bool_t _dbus_stat (const DBusString *filename, + DBusStat *statbuf, + DBusError *error); +dbus_bool_t _dbus_full_duplex_pipe (int *fd1, + int *fd2, + dbus_bool_t blocking, + DBusError *error); + +void _dbus_print_backtrace (void); + +dbus_bool_t _dbus_become_daemon (const DBusString *pidfile, + DBusPipe *print_pid_pipe, + DBusError *error, + dbus_bool_t keep_umask); + +dbus_bool_t _dbus_verify_daemon_user (const char *user); + +dbus_bool_t _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile, + DBusPipe *print_pid_pipe, + dbus_pid_t pid_to_write, + DBusError *error); + +dbus_bool_t _dbus_command_for_pid (unsigned long pid, + DBusString *str, + int max_len, + DBusError *error); + +/** A UNIX signal handler */ +typedef void (* DBusSignalHandler) (int sig); + +void _dbus_set_signal_handler (int sig, + DBusSignalHandler handler); + +dbus_bool_t _dbus_user_at_console (const char *username, + DBusError *error); + +void _dbus_init_system_log (void); + +typedef enum { + DBUS_SYSTEM_LOG_INFO, + DBUS_SYSTEM_LOG_SECURITY, + DBUS_SYSTEM_LOG_FATAL +} DBusSystemLogSeverity; + +void _dbus_system_log (DBusSystemLogSeverity severity, const char *msg, ...) _DBUS_GNUC_PRINTF (2, 3); +void _dbus_system_logv (DBusSystemLogSeverity severity, const char *msg, va_list args); + +/* Define DBUS_VA_COPY() to do the right thing for copying va_list variables. + * config.h may have already defined DBUS_VA_COPY as va_copy or __va_copy. + */ +#if !defined (DBUS_VA_COPY) +# if defined (__GNUC__) && defined (__PPC__) && (defined (_CALL_SYSV) || defined (_WIN32)) +# define DBUS_VA_COPY(ap1, ap2) (*(ap1) = *(ap2)) +# elif defined (DBUS_VA_COPY_AS_ARRAY) +# define DBUS_VA_COPY(ap1, ap2) memcpy ((ap1), (ap2), sizeof (va_list)) +# else /* va_list is a pointer */ +# define DBUS_VA_COPY(ap1, ap2) ((ap1) = (ap2)) +# endif /* va_list is a pointer */ +#endif /* !DBUS_VA_COPY */ + + +/** + * Casts a primitive C type to a byte array and then indexes + * a particular byte of the array. + */ +#define _DBUS_BYTE_OF_PRIMITIVE(p, i) \ + (((const char*)&(p))[(i)]) +/** On x86 there is an 80-bit FPU, and if you do "a == b" it may have a + * or b in an 80-bit register, thus failing to compare the two 64-bit + * doubles for bitwise equality. So this macro compares the two doubles + * bitwise. + */ +#define _DBUS_DOUBLES_BITWISE_EQUAL(a, b) \ + (_DBUS_BYTE_OF_PRIMITIVE (a, 0) == _DBUS_BYTE_OF_PRIMITIVE (b, 0) && \ + _DBUS_BYTE_OF_PRIMITIVE (a, 1) == _DBUS_BYTE_OF_PRIMITIVE (b, 1) && \ + _DBUS_BYTE_OF_PRIMITIVE (a, 2) == _DBUS_BYTE_OF_PRIMITIVE (b, 2) && \ + _DBUS_BYTE_OF_PRIMITIVE (a, 3) == _DBUS_BYTE_OF_PRIMITIVE (b, 3) && \ + _DBUS_BYTE_OF_PRIMITIVE (a, 4) == _DBUS_BYTE_OF_PRIMITIVE (b, 4) && \ + _DBUS_BYTE_OF_PRIMITIVE (a, 5) == _DBUS_BYTE_OF_PRIMITIVE (b, 5) && \ + _DBUS_BYTE_OF_PRIMITIVE (a, 6) == _DBUS_BYTE_OF_PRIMITIVE (b, 6) && \ + _DBUS_BYTE_OF_PRIMITIVE (a, 7) == _DBUS_BYTE_OF_PRIMITIVE (b, 7)) + +dbus_bool_t _dbus_get_autolaunch_address (DBusString *address, + DBusError *error); + +dbus_bool_t _dbus_lookup_session_address (dbus_bool_t *supported, + DBusString *address, + DBusError *error); + +/** Type representing a universally unique ID + * @todo rename to UUID instead of GUID + */ +typedef union DBusGUID DBusGUID; + +dbus_bool_t _dbus_read_local_machine_uuid (DBusGUID *machine_id, + dbus_bool_t create_if_not_found, + DBusError *error); + +/** + * Initialize threads as in dbus_threads_init_default(), appropriately + * for the platform. + * @returns #FALSE if no memory + */ +dbus_bool_t _dbus_threads_init_platform_specific (void); + +dbus_bool_t _dbus_split_paths_and_append (DBusString *dirs, + const char *suffix, + DBusList **dir_list); + +unsigned long _dbus_pid_for_log (void); + +/* FIXME move back to dbus-sysdeps-unix.h probably - + * the PID file handling just needs a little more abstraction + * in the bus daemon first. + */ +dbus_pid_t _dbus_getpid (void); + +dbus_bool_t _dbus_change_to_daemon_user (const char *user, + DBusError *error); + +void _dbus_flush_caches (void); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_SYSDEPS_H */ diff --git a/dbus/dbus-test-main.c b/dbus/dbus-test-main.c new file mode 100644 index 00000000..1bb7c904 --- /dev/null +++ b/dbus/dbus-test-main.c @@ -0,0 +1,54 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-test.c Program to run all tests + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#include "dbus-types.h" +#include "dbus-test.h" +#include +#include +#include + +int +main (int argc, + char **argv) +{ + const char *test_data_dir; + const char *specific_test; + + setlocale(LC_ALL, ""); + + + if (argc > 1) + test_data_dir = argv[1]; + else + test_data_dir = NULL; + + if (argc > 2) + specific_test = argv[2]; + else + specific_test = NULL; + + dbus_internal_do_not_use_run_tests (test_data_dir, specific_test); + + return 0; +} diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c new file mode 100644 index 00000000..99becb0e --- /dev/null +++ b/dbus/dbus-test.c @@ -0,0 +1,190 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-test.c Program to run all tests + * + * Copyright (C) 2002, 2003, 2004, 2005 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include "dbus-test.h" +#include "dbus-sysdeps.h" +#include "dbus-internals.h" +#include +#include + +#ifdef DBUS_BUILD_TESTS +static void +die (const char *failure) +{ + fprintf (stderr, "Unit test failed: %s\n", failure); + exit (1); +} + +static void +check_memleaks (void) +{ + dbus_shutdown (); + + printf ("%s: checking for memleaks\n", "dbus-test"); + if (_dbus_get_malloc_blocks_outstanding () != 0) + { + _dbus_warn ("%d dbus_malloc blocks were not freed\n", + _dbus_get_malloc_blocks_outstanding ()); + die ("memleaks"); + } +} + +typedef dbus_bool_t (*TestFunc)(void); +typedef dbus_bool_t (*TestDataFunc)(const char *data); + +static void +run_test (const char *test_name, + const char *specific_test, + TestFunc test) +{ + if (!specific_test || strcmp (specific_test, test_name) == 0) + { + printf ("%s: running %s tests\n", "dbus-test", test_name); + if (!test ()) + die (test_name); + } + + check_memleaks (); +} + +static void +run_data_test (const char *test_name, + const char *specific_test, + TestDataFunc test, + const char *test_data_dir) +{ + if (!specific_test || strcmp (specific_test, test_name) == 0) + { + printf ("%s: running %s tests\n", "dbus-test", test_name); + if (!test (test_data_dir)) + die (test_name); + } + + check_memleaks (); +} + +#endif /* DBUS_BUILD_TESTS */ + +/** + * An exported symbol to be run in order to execute + * unit tests. Should not be used by + * any app other than our test app, this symbol + * won't exist in some builds of the library. + * (with --enable-tests=no) + * + * @param test_data_dir the directory with test data (test/data normally) + */ +void +dbus_internal_do_not_use_run_tests (const char *test_data_dir, const char *specific_test) +{ +#ifdef DBUS_BUILD_TESTS + if (!_dbus_threads_init_debug ()) + die ("debug threads init"); + + if (test_data_dir == NULL) + test_data_dir = _dbus_getenv ("DBUS_TEST_DATA"); + + if (test_data_dir != NULL) + printf ("Test data in %s\n", test_data_dir); + else + printf ("No test data!\n"); + + run_test ("string", specific_test, _dbus_string_test); + + run_test ("sysdeps", specific_test, _dbus_sysdeps_test); + + run_test ("data-slot", specific_test, _dbus_data_slot_test); + + run_test ("misc", specific_test, _dbus_misc_test); + + run_test ("address", specific_test, _dbus_address_test); + + run_test ("server", specific_test, _dbus_server_test); + + run_test ("object-tree", specific_test, _dbus_object_tree_test); + + run_test ("signature", specific_test, _dbus_signature_test); + + run_test ("marshalling", specific_test, _dbus_marshal_test); + +#if 0 + printf ("%s: running recursive marshalling tests\n", "dbus-test"); + if (!_dbus_marshal_recursive_test ()) + die ("recursive marshal"); + + check_memleaks (); +#else + _dbus_warn ("recursive marshal tests disabled\n"); +#endif + + run_test ("byteswap", specific_test, _dbus_marshal_byteswap_test); + + run_test ("memory", specific_test, _dbus_memory_test); + +#if 1 + run_test ("mem-pool", specific_test, _dbus_mem_pool_test); +#endif + + run_test ("list", specific_test, _dbus_list_test); + + run_test ("marshal-validate", specific_test, _dbus_marshal_validate_test); + + run_test ("marshal-header", specific_test, _dbus_marshal_header_test); + + run_data_test ("message", specific_test, _dbus_message_test, test_data_dir); + + run_test ("hash", specific_test, _dbus_hash_test); + +#if !defined(DBUS_WINCE) + run_data_test ("spawn", specific_test, _dbus_spawn_test, test_data_dir); +#endif + + run_data_test ("credentials", specific_test, _dbus_credentials_test, test_data_dir); + +#ifdef DBUS_UNIX + run_data_test ("userdb", specific_test, _dbus_userdb_test, test_data_dir); +#endif + + run_test ("keyring", specific_test, _dbus_keyring_test); + +#if 0 + printf ("%s: running md5 tests\n", "dbus-test"); + if (!_dbus_md5_test ()) + die ("md5"); + + check_memleaks (); +#endif + + run_data_test ("sha", specific_test, _dbus_sha_test, test_data_dir); + + run_data_test ("auth", specific_test, _dbus_auth_test, test_data_dir); + + run_data_test ("pending-call", specific_test, _dbus_pending_call_test, test_data_dir); + + printf ("%s: completed successfully\n", "dbus-test"); +#else + printf ("Not compiled with unit tests, not running any\n"); +#endif +} + diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h new file mode 100644 index 00000000..0238b0ce --- /dev/null +++ b/dbus/dbus-test.h @@ -0,0 +1,83 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-test.h Declarations of test functions. + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_TEST_H +#define DBUS_TEST_H + +#include +#include +#include + +dbus_bool_t _dbus_hash_test (void); +dbus_bool_t _dbus_dict_test (void); +dbus_bool_t _dbus_list_test (void); +dbus_bool_t _dbus_marshal_test (void); +dbus_bool_t _dbus_marshal_recursive_test (void); +dbus_bool_t _dbus_marshal_byteswap_test (void); +dbus_bool_t _dbus_marshal_header_test (void); +dbus_bool_t _dbus_marshal_validate_test (void); +dbus_bool_t _dbus_misc_test (void); +dbus_bool_t _dbus_signature_test (void); +dbus_bool_t _dbus_mem_pool_test (void); +dbus_bool_t _dbus_string_test (void); +dbus_bool_t _dbus_address_test (void); +dbus_bool_t _dbus_server_test (void); +dbus_bool_t _dbus_message_test (const char *test_data_dir); +dbus_bool_t _dbus_auth_test (const char *test_data_dir); +dbus_bool_t _dbus_md5_test (void); +dbus_bool_t _dbus_sha_test (const char *test_data_dir); +dbus_bool_t _dbus_keyring_test (void); +dbus_bool_t _dbus_data_slot_test (void); +dbus_bool_t _dbus_sysdeps_test (void); +dbus_bool_t _dbus_spawn_test (const char *test_data_dir); +dbus_bool_t _dbus_userdb_test (const char *test_data_dir); +dbus_bool_t _dbus_memory_test (void); +dbus_bool_t _dbus_object_tree_test (void); +dbus_bool_t _dbus_pending_call_test (const char *test_data_dir); +dbus_bool_t _dbus_credentials_test (const char *test_data_dir); + +void dbus_internal_do_not_use_run_tests (const char *test_data_dir, + const char *specific_test); +dbus_bool_t dbus_internal_do_not_use_try_message_file (const DBusString *filename, + DBusValidity expected_validity); +dbus_bool_t dbus_internal_do_not_use_try_message_data (const DBusString *data, + DBusValidity expected_validity); +dbus_bool_t dbus_internal_do_not_use_load_message_file (const DBusString *filename, + DBusString *data); + + +/* returns FALSE on fatal failure */ +typedef dbus_bool_t (* DBusForeachMessageFileFunc) (const DBusString *filename, + DBusValidity expected_validity, + void *data); + +dbus_bool_t dbus_internal_do_not_use_foreach_message_file (const char *test_data_dir, + DBusForeachMessageFileFunc func, + void *user_data); +dbus_bool_t dbus_internal_do_not_use_generate_bodies (int sequence, + int byte_order, + DBusString *signature, + DBusString *body); + + +#endif /* DBUS_TEST_H */ diff --git a/dbus/dbus-threads-internal.h b/dbus/dbus-threads-internal.h new file mode 100644 index 00000000..11f9ce20 --- /dev/null +++ b/dbus/dbus-threads-internal.h @@ -0,0 +1,53 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-threads-internal.h D-Bus thread primitives + * + * Copyright (C) 2002, 2005 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_THREADS_INTERNAL_H +#define DBUS_THREADS_INTERNAL_H + +#include +#include +#include + +DBUS_BEGIN_DECLS + +DBusMutex* _dbus_mutex_new (void); +void _dbus_mutex_free (DBusMutex *mutex); +void _dbus_mutex_lock (DBusMutex *mutex); +void _dbus_mutex_unlock (DBusMutex *mutex); +void _dbus_mutex_new_at_location (DBusMutex **location_p); +void _dbus_mutex_free_at_location (DBusMutex **location_p); + +DBusCondVar* _dbus_condvar_new (void); +void _dbus_condvar_free (DBusCondVar *cond); +void _dbus_condvar_wait (DBusCondVar *cond, + DBusMutex *mutex); +dbus_bool_t _dbus_condvar_wait_timeout (DBusCondVar *cond, + DBusMutex *mutex, + int timeout_milliseconds); +void _dbus_condvar_wake_one (DBusCondVar *cond); +void _dbus_condvar_wake_all (DBusCondVar *cond); +void _dbus_condvar_new_at_location (DBusCondVar **location_p); +void _dbus_condvar_free_at_location (DBusCondVar **location_p); + +DBUS_END_DECLS + +#endif /* DBUS_THREADS_INTERNAL_H */ diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c new file mode 100644 index 00000000..c9649646 --- /dev/null +++ b/dbus/dbus-threads.c @@ -0,0 +1,816 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-threads.h D-Bus threads handling + * + * Copyright (C) 2002, 2003, 2006 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-threads.h" +#include "dbus-internals.h" +#include "dbus-threads-internal.h" +#include "dbus-list.h" + +static DBusThreadFunctions thread_functions = +{ + 0, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + + NULL, NULL, NULL, NULL +}; + +static int thread_init_generation = 0; + +static DBusList *uninitialized_mutex_list = NULL; +static DBusList *uninitialized_condvar_list = NULL; + +/** This is used for the no-op default mutex pointer, just to be distinct from #NULL */ +#define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF) + +/** This is used for the no-op default mutex pointer, just to be distinct from #NULL */ +#define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2) + +/** + * @defgroup DBusThreadsInternals Thread functions + * @ingroup DBusInternals + * @brief _dbus_mutex_lock(), etc. + * + * Functions and macros related to threads and thread locks. + * + * @{ + */ + +/** + * Creates a new mutex using the function supplied to dbus_threads_init(), + * or creates a no-op mutex if threads are not initialized. + * May return #NULL even if threads are initialized, indicating + * out-of-memory. + * + * @returns new mutex or #NULL + */ +DBusMutex* +_dbus_mutex_new (void) +{ + if (thread_functions.recursive_mutex_new) + return (* thread_functions.recursive_mutex_new) (); + else if (thread_functions.mutex_new) + return (* thread_functions.mutex_new) (); + else + return _DBUS_DUMMY_MUTEX; +} + +/** + * This does the same thing as _dbus_mutex_new. It however + * gives another level of indirection by allocating a pointer + * to point to the mutex location. This allows the threading + * module to swap out dummy mutexes for real a real mutex so libraries + * can initialize threads even after the D-Bus API has been used. + * + * @param location_p the location of the new mutex, can return #NULL on OOM + */ +void +_dbus_mutex_new_at_location (DBusMutex **location_p) +{ + _dbus_assert (location_p != NULL); + + *location_p = _dbus_mutex_new(); + + if (thread_init_generation != _dbus_current_generation && *location_p) + { + if (!_dbus_list_append (&uninitialized_mutex_list, location_p)) + { + _dbus_mutex_free (*location_p); + *location_p = NULL; + } + } +} + +/** + * Frees a mutex created with dbus_mutex_new(); does + * nothing if passed a #NULL pointer. + */ +void +_dbus_mutex_free (DBusMutex *mutex) +{ + if (mutex) + { + if (mutex && thread_functions.recursive_mutex_free) + (* thread_functions.recursive_mutex_free) (mutex); + else if (mutex && thread_functions.mutex_free) + (* thread_functions.mutex_free) (mutex); + } +} + +/** + * Frees a mutex and removes it from the + * uninitialized_mutex_list; + * does nothing if passed a #NULL pointer. + */ +void +_dbus_mutex_free_at_location (DBusMutex **location_p) +{ + if (location_p) + { + if (thread_init_generation != _dbus_current_generation) + _dbus_list_remove (&uninitialized_mutex_list, location_p); + + _dbus_mutex_free (*location_p); + } +} + +/** + * Locks a mutex. Does nothing if passed a #NULL pointer. + * Locks may be recursive if threading implementation initialized + * recursive locks. + */ +void +_dbus_mutex_lock (DBusMutex *mutex) +{ + if (mutex) + { + if (thread_functions.recursive_mutex_lock) + (* thread_functions.recursive_mutex_lock) (mutex); + else if (thread_functions.mutex_lock) + (* thread_functions.mutex_lock) (mutex); + } +} + +/** + * Unlocks a mutex. Does nothing if passed a #NULL pointer. + * + * @returns #TRUE on success + */ +void +_dbus_mutex_unlock (DBusMutex *mutex) +{ + if (mutex) + { + if (thread_functions.recursive_mutex_unlock) + (* thread_functions.recursive_mutex_unlock) (mutex); + else if (thread_functions.mutex_unlock) + (* thread_functions.mutex_unlock) (mutex); + } +} + +/** + * Creates a new condition variable using the function supplied + * to dbus_threads_init(), or creates a no-op condition variable + * if threads are not initialized. May return #NULL even if + * threads are initialized, indicating out-of-memory. + * + * @returns new mutex or #NULL + */ +DBusCondVar * +_dbus_condvar_new (void) +{ + if (thread_functions.condvar_new) + return (* thread_functions.condvar_new) (); + else + return _DBUS_DUMMY_CONDVAR; +} + + +/** + * This does the same thing as _dbus_condvar_new. It however + * gives another level of indirection by allocating a pointer + * to point to the condvar location. This allows the threading + * module to swap out dummy condvars for real a real condvar so libraries + * can initialize threads even after the D-Bus API has been used. + * + * @returns the location of a new condvar or #NULL on OOM + */ + +void +_dbus_condvar_new_at_location (DBusCondVar **location_p) +{ + *location_p = _dbus_condvar_new(); + + if (thread_init_generation != _dbus_current_generation && *location_p) + { + if (!_dbus_list_append (&uninitialized_condvar_list, location_p)) + { + _dbus_condvar_free (*location_p); + *location_p = NULL; + } + } +} + + +/** + * Frees a conditional variable created with dbus_condvar_new(); does + * nothing if passed a #NULL pointer. + */ +void +_dbus_condvar_free (DBusCondVar *cond) +{ + if (cond && thread_functions.condvar_free) + (* thread_functions.condvar_free) (cond); +} + +/** + * Frees a conditional variable and removes it from the + * uninitialized_condvar_list; + * does nothing if passed a #NULL pointer. + */ +void +_dbus_condvar_free_at_location (DBusCondVar **location_p) +{ + if (location_p) + { + if (thread_init_generation != _dbus_current_generation) + _dbus_list_remove (&uninitialized_condvar_list, location_p); + + _dbus_condvar_free (*location_p); + } +} + +/** + * Atomically unlocks the mutex and waits for the conditions + * variable to be signalled. Locks the mutex again before + * returning. + * Does nothing if passed a #NULL pointer. + */ +void +_dbus_condvar_wait (DBusCondVar *cond, + DBusMutex *mutex) +{ + if (cond && mutex && thread_functions.condvar_wait) + (* thread_functions.condvar_wait) (cond, mutex); +} + +/** + * Atomically unlocks the mutex and waits for the conditions variable + * to be signalled, or for a timeout. Locks the mutex again before + * returning. Does nothing if passed a #NULL pointer. Return value + * is #FALSE if we timed out, #TRUE otherwise. + * + * @param cond the condition variable + * @param mutex the mutex + * @param timeout_milliseconds the maximum time to wait + * @returns #FALSE if the timeout occurred, #TRUE if not + */ +dbus_bool_t +_dbus_condvar_wait_timeout (DBusCondVar *cond, + DBusMutex *mutex, + int timeout_milliseconds) +{ + if (cond && mutex && thread_functions.condvar_wait) + return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds); + else + return TRUE; +} + +/** + * If there are threads waiting on the condition variable, wake + * up exactly one. + * Does nothing if passed a #NULL pointer. + */ +void +_dbus_condvar_wake_one (DBusCondVar *cond) +{ + if (cond && thread_functions.condvar_wake_one) + (* thread_functions.condvar_wake_one) (cond); +} + +/** + * If there are threads waiting on the condition variable, wake + * up all of them. + * Does nothing if passed a #NULL pointer. + */ +void +_dbus_condvar_wake_all (DBusCondVar *cond) +{ + if (cond && thread_functions.condvar_wake_all) + (* thread_functions.condvar_wake_all) (cond); +} + +static void +shutdown_global_locks (void *data) +{ + DBusMutex ***locks = data; + int i; + + i = 0; + while (i < _DBUS_N_GLOBAL_LOCKS) + { + _dbus_mutex_free (*(locks[i])); + *(locks[i]) = NULL; + ++i; + } + + dbus_free (locks); +} + +static void +shutdown_uninitialized_locks (void *data) +{ + _dbus_list_clear (&uninitialized_mutex_list); + _dbus_list_clear (&uninitialized_condvar_list); +} + +static dbus_bool_t +init_uninitialized_locks (void) +{ + DBusList *link; + + _dbus_assert (thread_init_generation != _dbus_current_generation); + + link = uninitialized_mutex_list; + while (link != NULL) + { + DBusMutex **mp; + + mp = (DBusMutex **)link->data; + _dbus_assert (*mp == _DBUS_DUMMY_MUTEX); + + *mp = _dbus_mutex_new (); + if (*mp == NULL) + goto fail_mutex; + + link = _dbus_list_get_next_link (&uninitialized_mutex_list, link); + } + + link = uninitialized_condvar_list; + while (link != NULL) + { + DBusCondVar **cp; + + cp = (DBusCondVar **)link->data; + _dbus_assert (*cp == _DBUS_DUMMY_CONDVAR); + + *cp = _dbus_condvar_new (); + if (*cp == NULL) + goto fail_condvar; + + link = _dbus_list_get_next_link (&uninitialized_condvar_list, link); + } + + _dbus_list_clear (&uninitialized_mutex_list); + _dbus_list_clear (&uninitialized_condvar_list); + + if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks, + NULL)) + goto fail_condvar; + + return TRUE; + + fail_condvar: + link = uninitialized_condvar_list; + while (link != NULL) + { + DBusCondVar **cp; + + cp = (DBusCondVar **)link->data; + + if (*cp != _DBUS_DUMMY_CONDVAR) + _dbus_condvar_free (*cp); + else + break; + + *cp = _DBUS_DUMMY_CONDVAR; + + link = _dbus_list_get_next_link (&uninitialized_condvar_list, link); + } + + fail_mutex: + link = uninitialized_mutex_list; + while (link != NULL) + { + DBusMutex **mp; + + mp = (DBusMutex **)link->data; + + if (*mp != _DBUS_DUMMY_MUTEX) + _dbus_mutex_free (*mp); + else + break; + + *mp = _DBUS_DUMMY_MUTEX; + + link = _dbus_list_get_next_link (&uninitialized_mutex_list, link); + } + + return FALSE; +} + +static dbus_bool_t +init_locks (void) +{ + int i; + DBusMutex ***dynamic_global_locks; + + DBusMutex **global_locks[] = { +#define LOCK_ADDR(name) (& _dbus_lock_##name) + LOCK_ADDR (win_fds), + LOCK_ADDR (sid_atom_cache), + LOCK_ADDR (list), + LOCK_ADDR (connection_slots), + LOCK_ADDR (pending_call_slots), + LOCK_ADDR (server_slots), + LOCK_ADDR (message_slots), + LOCK_ADDR (atomic), + LOCK_ADDR (bus), + LOCK_ADDR (bus_datas), + LOCK_ADDR (shutdown_funcs), + LOCK_ADDR (system_users), + LOCK_ADDR (message_cache), + LOCK_ADDR (shared_connections), + LOCK_ADDR (machine_uuid) +#undef LOCK_ADDR + }; + + _dbus_assert (_DBUS_N_ELEMENTS (global_locks) == + _DBUS_N_GLOBAL_LOCKS); + + i = 0; + + dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS); + if (dynamic_global_locks == NULL) + goto failed; + + while (i < _DBUS_N_ELEMENTS (global_locks)) + { + *global_locks[i] = _dbus_mutex_new (); + + if (*global_locks[i] == NULL) + goto failed; + + dynamic_global_locks[i] = global_locks[i]; + + ++i; + } + + if (!_dbus_register_shutdown_func (shutdown_global_locks, + dynamic_global_locks)) + goto failed; + + if (!init_uninitialized_locks ()) + goto failed; + + return TRUE; + + failed: + dbus_free (dynamic_global_locks); + + for (i = i - 1; i >= 0; i--) + { + _dbus_mutex_free (*global_locks[i]); + *global_locks[i] = NULL; + } + return FALSE; +} + +/** @} */ /* end of internals */ + +/** + * @defgroup DBusThreads Thread functions + * @ingroup DBus + * @brief dbus_threads_init() and dbus_threads_init_default() + * + * Functions and macros related to threads and thread locks. + * + * If threads are initialized, the D-Bus library has locks on all + * global data structures. In addition, each #DBusConnection has a + * lock, so only one thread at a time can touch the connection. (See + * @ref DBusConnection for more on connection locking.) + * + * Most other objects, however, do not have locks - they can only be + * used from a single thread at a time, unless you lock them yourself. + * For example, a #DBusMessage can't be modified from two threads + * at once. + * + * @{ + */ + +/** + * + * Initializes threads. If this function is not called, the D-Bus + * library will not lock any data structures. If it is called, D-Bus + * will do locking, at some cost in efficiency. Note that this + * function must be called BEFORE the second thread is started. + * + * Almost always, you should use dbus_threads_init_default() instead. + * The raw dbus_threads_init() is only useful if you require a + * particular thread implementation for some reason. + * + * A possible reason to use dbus_threads_init() rather than + * dbus_threads_init_default() is to insert debugging checks or print + * statements. + * + * dbus_threads_init() may be called more than once. The first one + * wins and subsequent calls are ignored. (Unless you use + * dbus_shutdown() to reset libdbus, which will let you re-init + * threads.) + * + * Either recursive or nonrecursive mutex functions must be specified, + * but not both. New code should provide only the recursive functions + * - specifying the nonrecursive ones is deprecated. + * + * Because this function effectively sets global state, all code + * running in a given application must agree on the thread + * implementation. Most code won't care which thread implementation is + * used, so there's no problem. However, usually libraries should not + * call dbus_threads_init() or dbus_threads_init_default(), instead + * leaving this policy choice to applications. + * + * The exception is for application frameworks (GLib, Qt, etc.) and + * D-Bus bindings based on application frameworks. These frameworks + * define a cross-platform thread abstraction and can assume + * applications using the framework are OK with using that thread + * abstraction. + * + * However, even these app frameworks may find it easier to simply call + * dbus_threads_init_default(), and there's no reason they shouldn't. + * + * @param functions functions for using threads + * @returns #TRUE on success, #FALSE if no memory + */ +dbus_bool_t +dbus_threads_init (const DBusThreadFunctions *functions) +{ + dbus_bool_t mutex_set; + dbus_bool_t recursive_mutex_set; + + _dbus_assert (functions != NULL); + + /* these base functions are required. Future additions to + * DBusThreadFunctions may be optional. + */ + _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK); + _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK); + _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK); + _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK); + _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK); + _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK); + _dbus_assert (functions->condvar_new != NULL); + _dbus_assert (functions->condvar_free != NULL); + _dbus_assert (functions->condvar_wait != NULL); + _dbus_assert (functions->condvar_wait_timeout != NULL); + _dbus_assert (functions->condvar_wake_one != NULL); + _dbus_assert (functions->condvar_wake_all != NULL); + + /* Either the mutex function set or recursive mutex set needs + * to be available but not both + */ + mutex_set = (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK) && + (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK) && + (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK) && + (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK) && + functions->mutex_new && + functions->mutex_free && + functions->mutex_lock && + functions->mutex_unlock; + + recursive_mutex_set = + (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) && + (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) && + (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) && + (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) && + functions->recursive_mutex_new && + functions->recursive_mutex_free && + functions->recursive_mutex_lock && + functions->recursive_mutex_unlock; + + if (!(mutex_set || recursive_mutex_set)) + _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex " + "functions sets should be passed into " + "dbus_threads_init. Neither sets were passed."); + + if (mutex_set && recursive_mutex_set) + _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex " + "functions sets should be passed into " + "dbus_threads_init. Both sets were passed. " + "You most likely just want to set the recursive " + "mutex functions to avoid deadlocks in D-Bus."); + + /* Check that all bits in the mask actually are valid mask bits. + * ensures people won't write code that breaks when we add + * new bits. + */ + _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0); + + if (thread_init_generation != _dbus_current_generation) + thread_functions.mask = 0; /* allow re-init in new generation */ + + /* Silently allow multiple init + * First init wins and D-Bus will always use its threading system + */ + if (thread_functions.mask != 0) + return TRUE; + + thread_functions.mutex_new = functions->mutex_new; + thread_functions.mutex_free = functions->mutex_free; + thread_functions.mutex_lock = functions->mutex_lock; + thread_functions.mutex_unlock = functions->mutex_unlock; + + thread_functions.condvar_new = functions->condvar_new; + thread_functions.condvar_free = functions->condvar_free; + thread_functions.condvar_wait = functions->condvar_wait; + thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout; + thread_functions.condvar_wake_one = functions->condvar_wake_one; + thread_functions.condvar_wake_all = functions->condvar_wake_all; + + if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) + thread_functions.recursive_mutex_new = functions->recursive_mutex_new; + + if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) + thread_functions.recursive_mutex_free = functions->recursive_mutex_free; + + if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) + thread_functions.recursive_mutex_lock = functions->recursive_mutex_lock; + + if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) + thread_functions.recursive_mutex_unlock = functions->recursive_mutex_unlock; + + thread_functions.mask = functions->mask; + + if (!init_locks ()) + return FALSE; + + thread_init_generation = _dbus_current_generation; + + return TRUE; +} + + + +/* Default thread implemenation */ + +/** + * + * Calls dbus_threads_init() with a default set of + * #DBusThreadFunctions appropriate for the platform. + * + * Most applications should use this rather than dbus_threads_init(). + * + * It's safe to call dbus_threads_init_default() as many times as you + * want, but only the first time will have an effect. + * + * dbus_shutdown() reverses the effects of this function when it + * resets all global state in libdbus. + * + * @returns #TRUE on success, #FALSE if not enough memory + */ +dbus_bool_t +dbus_threads_init_default (void) +{ + return _dbus_threads_init_platform_specific (); +} + + +/** @} */ + +#ifdef DBUS_BUILD_TESTS +/** Fake mutex used for debugging */ +typedef struct DBusFakeMutex DBusFakeMutex; +/** Fake mutex used for debugging */ +struct DBusFakeMutex +{ + dbus_bool_t locked; /**< Mutex is "locked" */ +}; + +static DBusMutex * dbus_fake_mutex_new (void); +static void dbus_fake_mutex_free (DBusMutex *mutex); +static dbus_bool_t dbus_fake_mutex_lock (DBusMutex *mutex); +static dbus_bool_t dbus_fake_mutex_unlock (DBusMutex *mutex); +static DBusCondVar* dbus_fake_condvar_new (void); +static void dbus_fake_condvar_free (DBusCondVar *cond); +static void dbus_fake_condvar_wait (DBusCondVar *cond, + DBusMutex *mutex); +static dbus_bool_t dbus_fake_condvar_wait_timeout (DBusCondVar *cond, + DBusMutex *mutex, + int timeout_msec); +static void dbus_fake_condvar_wake_one (DBusCondVar *cond); +static void dbus_fake_condvar_wake_all (DBusCondVar *cond); + + +static const DBusThreadFunctions fake_functions = +{ + DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK | + DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK | + DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK | + DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK | + DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK| + DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK, + dbus_fake_mutex_new, + dbus_fake_mutex_free, + dbus_fake_mutex_lock, + dbus_fake_mutex_unlock, + dbus_fake_condvar_new, + dbus_fake_condvar_free, + dbus_fake_condvar_wait, + dbus_fake_condvar_wait_timeout, + dbus_fake_condvar_wake_one, + dbus_fake_condvar_wake_all +}; + +static DBusMutex * +dbus_fake_mutex_new (void) +{ + DBusFakeMutex *mutex; + + mutex = dbus_new0 (DBusFakeMutex, 1); + + return (DBusMutex *)mutex; +} + +static void +dbus_fake_mutex_free (DBusMutex *mutex) +{ + DBusFakeMutex *fake = (DBusFakeMutex*) mutex; + + _dbus_assert (!fake->locked); + + dbus_free (fake); +} + +static dbus_bool_t +dbus_fake_mutex_lock (DBusMutex *mutex) +{ + DBusFakeMutex *fake = (DBusFakeMutex*) mutex; + + _dbus_assert (!fake->locked); + + fake->locked = TRUE; + + return TRUE; +} + +static dbus_bool_t +dbus_fake_mutex_unlock (DBusMutex *mutex) +{ + DBusFakeMutex *fake = (DBusFakeMutex*) mutex; + + _dbus_assert (fake->locked); + + fake->locked = FALSE; + + return TRUE; +} + +static DBusCondVar* +dbus_fake_condvar_new (void) +{ + return (DBusCondVar*) _dbus_strdup ("FakeCondvar"); +} + +static void +dbus_fake_condvar_free (DBusCondVar *cond) +{ + dbus_free (cond); +} + +static void +dbus_fake_condvar_wait (DBusCondVar *cond, + DBusMutex *mutex) +{ + +} + +static dbus_bool_t +dbus_fake_condvar_wait_timeout (DBusCondVar *cond, + DBusMutex *mutex, + int timeout_msec) +{ + return TRUE; +} + +static void +dbus_fake_condvar_wake_one (DBusCondVar *cond) +{ + +} + +static void +dbus_fake_condvar_wake_all (DBusCondVar *cond) +{ + +} + +dbus_bool_t +_dbus_threads_init_debug (void) +{ + return dbus_threads_init (&fake_functions); +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/dbus/dbus-threads.h b/dbus/dbus-threads.h new file mode 100644 index 00000000..1fd83f21 --- /dev/null +++ b/dbus/dbus-threads.h @@ -0,0 +1,196 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-threads.h D-Bus threads handling + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_THREADS_H +#define DBUS_THREADS_H + +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusThreads + * @{ + */ + +/** An opaque mutex type provided by the #DBusThreadFunctions implementation installed by dbus_threads_init(). */ +typedef struct DBusMutex DBusMutex; +/** An opaque condition variable type provided by the #DBusThreadFunctions implementation installed by dbus_threads_init(). */ +typedef struct DBusCondVar DBusCondVar; + +/** Deprecated, provide DBusRecursiveMutexNewFunction instead. */ +typedef DBusMutex* (* DBusMutexNewFunction) (void); +/** Deprecated, provide DBusRecursiveMutexFreeFunction instead. */ +typedef void (* DBusMutexFreeFunction) (DBusMutex *mutex); +/** Deprecated, provide DBusRecursiveMutexLockFunction instead. Return value is lock success, but gets ignored in practice. */ +typedef dbus_bool_t (* DBusMutexLockFunction) (DBusMutex *mutex); +/** Deprecated, provide DBusRecursiveMutexUnlockFunction instead. Return value is unlock success, but gets ignored in practice. */ +typedef dbus_bool_t (* DBusMutexUnlockFunction) (DBusMutex *mutex); + +/** Creates a new recursively-lockable mutex, or returns #NULL if not + * enough memory. Can only fail due to lack of memory. Found in + * #DBusThreadFunctions. Do not just use PTHREAD_MUTEX_RECURSIVE for + * this, because it does not save/restore the recursion count when + * waiting on a condition. libdbus requires the Java-style behavior + * where the mutex is fully unlocked to wait on a condition. + */ +typedef DBusMutex* (* DBusRecursiveMutexNewFunction) (void); +/** Frees a recursively-lockable mutex. Found in #DBusThreadFunctions. + */ +typedef void (* DBusRecursiveMutexFreeFunction) (DBusMutex *mutex); +/** Locks a recursively-lockable mutex. Found in #DBusThreadFunctions. + * Can only fail due to lack of memory. + */ +typedef void (* DBusRecursiveMutexLockFunction) (DBusMutex *mutex); +/** Unlocks a recursively-lockable mutex. Found in #DBusThreadFunctions. + * Can only fail due to lack of memory. + */ +typedef void (* DBusRecursiveMutexUnlockFunction) (DBusMutex *mutex); + +/** Creates a new condition variable. Found in #DBusThreadFunctions. + * Can only fail (returning #NULL) due to lack of memory. + */ +typedef DBusCondVar* (* DBusCondVarNewFunction) (void); +/** Frees a condition variable. Found in #DBusThreadFunctions. + */ +typedef void (* DBusCondVarFreeFunction) (DBusCondVar *cond); + +/** Waits on a condition variable. Found in + * #DBusThreadFunctions. Must work with either a recursive or + * nonrecursive mutex, whichever the thread implementation + * provides. Note that PTHREAD_MUTEX_RECURSIVE does not work with + * condition variables (does not save/restore the recursion count) so + * don't try using simply pthread_cond_wait() and a + * PTHREAD_MUTEX_RECURSIVE to implement this, it won't work right. + * + * Has no error conditions. Must succeed if it returns. + */ +typedef void (* DBusCondVarWaitFunction) (DBusCondVar *cond, + DBusMutex *mutex); + +/** Waits on a condition variable with a timeout. Found in + * #DBusThreadFunctions. Returns #TRUE if the wait did not + * time out, and #FALSE if it did. + * + * Has no error conditions. Must succeed if it returns. + */ +typedef dbus_bool_t (* DBusCondVarWaitTimeoutFunction) (DBusCondVar *cond, + DBusMutex *mutex, + int timeout_milliseconds); +/** Wakes one waiting thread on a condition variable. Found in #DBusThreadFunctions. + * + * Has no error conditions. Must succeed if it returns. + */ +typedef void (* DBusCondVarWakeOneFunction) (DBusCondVar *cond); + +/** Wakes all waiting threads on a condition variable. Found in #DBusThreadFunctions. + * + * Has no error conditions. Must succeed if it returns. + */ +typedef void (* DBusCondVarWakeAllFunction) (DBusCondVar *cond); + +/** + * Flags indicating which functions are present in #DBusThreadFunctions. Used to allow + * the library to detect older callers of dbus_threads_init() if new possible functions + * are added to #DBusThreadFunctions. + */ +typedef enum +{ + DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK = 1 << 0, + DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK = 1 << 1, + DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK = 1 << 2, + DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK = 1 << 3, + DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK = 1 << 4, + DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK = 1 << 5, + DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK = 1 << 6, + DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK = 1 << 7, + DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK = 1 << 8, + DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK = 1 << 9, + DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK = 1 << 10, + DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK = 1 << 11, + DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK = 1 << 12, + DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK = 1 << 13, + DBUS_THREAD_FUNCTIONS_ALL_MASK = (1 << 14) - 1 +} DBusThreadFunctionsMask; + +/** + * Functions that must be implemented to make the D-Bus library + * thread-aware. The recursive mutex functions should be specified + * rather than the old, deprecated nonrecursive ones. + * + * The condition variable functions have to work with recursive + * mutexes if you provide those, or with nonrecursive mutexes if you + * provide those. + * + * If implementing threads using pthreads, be aware that + * PTHREAD_MUTEX_RECURSIVE is broken in combination with condition + * variables. libdbus relies on the Java-style behavior that when + * waiting on a condition, the recursion count is saved and restored, + * and the mutex is completely unlocked, not just decremented one + * level of recursion. + * + * Thus with pthreads you probably have to roll your own emulated + * recursive mutexes, you can't use PTHREAD_MUTEX_RECURSIVE. This is + * what dbus_threads_init_default() does on platforms that use + * pthreads. + */ +typedef struct +{ + unsigned int mask; /**< Mask indicating which functions are present. */ + + DBusMutexNewFunction mutex_new; /**< Function to create a mutex; optional and deprecated. */ + DBusMutexFreeFunction mutex_free; /**< Function to free a mutex; optional and deprecated. */ + DBusMutexLockFunction mutex_lock; /**< Function to lock a mutex; optional and deprecated. */ + DBusMutexUnlockFunction mutex_unlock; /**< Function to unlock a mutex; optional and deprecated. */ + + DBusCondVarNewFunction condvar_new; /**< Function to create a condition variable */ + DBusCondVarFreeFunction condvar_free; /**< Function to free a condition variable */ + DBusCondVarWaitFunction condvar_wait; /**< Function to wait on a condition */ + DBusCondVarWaitTimeoutFunction condvar_wait_timeout; /**< Function to wait on a condition with a timeout */ + DBusCondVarWakeOneFunction condvar_wake_one; /**< Function to wake one thread waiting on the condition */ + DBusCondVarWakeAllFunction condvar_wake_all; /**< Function to wake all threads waiting on the condition */ + + DBusRecursiveMutexNewFunction recursive_mutex_new; /**< Function to create a recursive mutex */ + DBusRecursiveMutexFreeFunction recursive_mutex_free; /**< Function to free a recursive mutex */ + DBusRecursiveMutexLockFunction recursive_mutex_lock; /**< Function to lock a recursive mutex */ + DBusRecursiveMutexUnlockFunction recursive_mutex_unlock; /**< Function to unlock a recursive mutex */ + + void (* padding1) (void); /**< Reserved for future expansion */ + void (* padding2) (void); /**< Reserved for future expansion */ + void (* padding3) (void); /**< Reserved for future expansion */ + void (* padding4) (void); /**< Reserved for future expansion */ + +} DBusThreadFunctions; + +dbus_bool_t dbus_threads_init (const DBusThreadFunctions *functions); +dbus_bool_t dbus_threads_init_default (void); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_THREADS_H */ diff --git a/dbus/dbus-timeout.c b/dbus/dbus-timeout.c new file mode 100644 index 00000000..0d92ca11 --- /dev/null +++ b/dbus/dbus-timeout.c @@ -0,0 +1,490 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-timeout.c DBusTimeout implementation + * + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-timeout.h" +#include "dbus-list.h" + +/** + * @defgroup DBusTimeoutInternals DBusTimeout implementation details + * @ingroup DBusInternals + * @brief implementation details for DBusTimeout + * + * @{ + */ + +/** + * Internals of DBusTimeout + */ +struct DBusTimeout +{ + int refcount; /**< Reference count */ + int interval; /**< Timeout interval in milliseconds. */ + + DBusTimeoutHandler handler; /**< Timeout handler. */ + void *handler_data; /**< Timeout handler data. */ + DBusFreeFunction free_handler_data_function; /**< Free the timeout handler data. */ + + void *data; /**< Application data. */ + DBusFreeFunction free_data_function; /**< Free the application data. */ + unsigned int enabled : 1; /**< True if timeout is active. */ +}; + +/** + * Creates a new DBusTimeout, enabled by default. + * @param interval the timeout interval in milliseconds. + * @param handler function to call when the timeout occurs. + * @param data data to pass to the handler + * @param free_data_function function to be called to free the data. + * @returns the new DBusTimeout object, + */ +DBusTimeout* +_dbus_timeout_new (int interval, + DBusTimeoutHandler handler, + void *data, + DBusFreeFunction free_data_function) +{ + DBusTimeout *timeout; + + timeout = dbus_new0 (DBusTimeout, 1); + if (timeout == NULL) + return NULL; + + timeout->refcount = 1; + timeout->interval = interval; + + timeout->handler = handler; + timeout->handler_data = data; + timeout->free_handler_data_function = free_data_function; + + timeout->enabled = TRUE; + + return timeout; +} + +/** + * Increments the reference count of a DBusTimeout object. + * + * @param timeout the timeout object. + * @returns the timeout object. + */ +DBusTimeout * +_dbus_timeout_ref (DBusTimeout *timeout) +{ + timeout->refcount += 1; + + return timeout; +} + +/** + * Decrements the reference count of a DBusTimeout object + * and finalizes the object if the count reaches zero. + * + * @param timeout the timeout object. + */ +void +_dbus_timeout_unref (DBusTimeout *timeout) +{ + _dbus_assert (timeout != NULL); + _dbus_assert (timeout->refcount > 0); + + timeout->refcount -= 1; + if (timeout->refcount == 0) + { + dbus_timeout_set_data (timeout, NULL, NULL); /* call free_data_function */ + + if (timeout->free_handler_data_function) + (* timeout->free_handler_data_function) (timeout->handler_data); + + dbus_free (timeout); + } +} + +/** + * Changes the timeout interval. Note that you have to disable and + * re-enable the timeout using the timeout toggle function + * (_dbus_connection_toggle_timeout_unlocked() etc.) to notify the + * application of this change. + * + * @param timeout the timeout + * @param interval the new interval + */ +void +_dbus_timeout_set_interval (DBusTimeout *timeout, + int interval) +{ + _dbus_assert (interval >= 0); + + timeout->interval = interval; +} + +/** + * Changes the timeout's enabled-ness. Note that you should use + * _dbus_connection_toggle_timeout_unlocked() etc. instead, if + * the timeout is passed out to an application main loop. + * i.e. you can't use this function in the D-Bus library, it's + * only used in the message bus daemon implementation. + * + * @param timeout the timeout + * @param enabled #TRUE if timeout should be enabled. + */ +void +_dbus_timeout_set_enabled (DBusTimeout *timeout, + dbus_bool_t enabled) +{ + timeout->enabled = enabled != FALSE; +} + + +/** + * @typedef DBusTimeoutList + * + * Opaque data type representing a list of timeouts + * and a set of DBusAddTimeoutFunction/DBusRemoveTimeoutFunction. + * Automatically handles removing/re-adding timeouts + * when the DBusAddTimeoutFunction is updated or changed. + * Holds a reference count to each timeout. + * + */ + +/** + * DBusTimeoutList implementation details. All fields + * are private. + * + */ +struct DBusTimeoutList +{ + DBusList *timeouts; /**< Timeout objects. */ + + DBusAddTimeoutFunction add_timeout_function; /**< Callback for adding a timeout. */ + DBusRemoveTimeoutFunction remove_timeout_function; /**< Callback for removing a timeout. */ + DBusTimeoutToggledFunction timeout_toggled_function; /**< Callback when timeout is enabled/disabled or changes interval */ + void *timeout_data; /**< Data for timeout callbacks */ + DBusFreeFunction timeout_free_data_function; /**< Free function for timeout callback data */ +}; + +/** + * Creates a new timeout list. Returns #NULL if insufficient + * memory exists. + * + * @returns the new timeout list, or #NULL on failure. + */ +DBusTimeoutList* +_dbus_timeout_list_new (void) +{ + DBusTimeoutList *timeout_list; + + timeout_list = dbus_new0 (DBusTimeoutList, 1); + if (timeout_list == NULL) + return NULL; + + return timeout_list; +} + +/** + * Frees a DBusTimeoutList. + * + * @param timeout_list the timeout list. + */ +void +_dbus_timeout_list_free (DBusTimeoutList *timeout_list) +{ + /* free timeout_data and remove timeouts as a side effect */ + _dbus_timeout_list_set_functions (timeout_list, + NULL, NULL, NULL, NULL, NULL); + + _dbus_list_foreach (&timeout_list->timeouts, + (DBusForeachFunction) _dbus_timeout_unref, + NULL); + _dbus_list_clear (&timeout_list->timeouts); + + dbus_free (timeout_list); +} + +/** + * Sets the timeout functions. This function is the "backend" + * for dbus_connection_set_timeout_functions(). + * + * @param timeout_list the timeout list + * @param add_function the add timeout function. + * @param remove_function the remove timeout function. + * @param toggled_function toggle notify function, or #NULL + * @param data the data for those functions. + * @param free_data_function the function to free the data. + * @returns #FALSE if no memory + * + */ +dbus_bool_t +_dbus_timeout_list_set_functions (DBusTimeoutList *timeout_list, + DBusAddTimeoutFunction add_function, + DBusRemoveTimeoutFunction remove_function, + DBusTimeoutToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function) +{ + /* Add timeouts with the new function, failing on OOM */ + if (add_function != NULL) + { + DBusList *link; + + link = _dbus_list_get_first_link (&timeout_list->timeouts); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&timeout_list->timeouts, + link); + + if (!(* add_function) (link->data, data)) + { + /* remove it all again and return FALSE */ + DBusList *link2; + + link2 = _dbus_list_get_first_link (&timeout_list->timeouts); + while (link2 != link) + { + DBusList *next = _dbus_list_get_next_link (&timeout_list->timeouts, + link2); + + (* remove_function) (link2->data, data); + + link2 = next; + } + + return FALSE; + } + + link = next; + } + } + + /* Remove all current timeouts from previous timeout handlers */ + + if (timeout_list->remove_timeout_function != NULL) + { + _dbus_list_foreach (&timeout_list->timeouts, + (DBusForeachFunction) timeout_list->remove_timeout_function, + timeout_list->timeout_data); + } + + if (timeout_list->timeout_free_data_function != NULL) + (* timeout_list->timeout_free_data_function) (timeout_list->timeout_data); + + timeout_list->add_timeout_function = add_function; + timeout_list->remove_timeout_function = remove_function; + timeout_list->timeout_toggled_function = toggled_function; + timeout_list->timeout_data = data; + timeout_list->timeout_free_data_function = free_data_function; + + return TRUE; +} + +/** + * Adds a new timeout to the timeout list, invoking the + * application DBusAddTimeoutFunction if appropriate. + * + * @param timeout_list the timeout list. + * @param timeout the timeout to add. + * @returns #TRUE on success, #FALSE If no memory. + */ +dbus_bool_t +_dbus_timeout_list_add_timeout (DBusTimeoutList *timeout_list, + DBusTimeout *timeout) +{ + if (!_dbus_list_append (&timeout_list->timeouts, timeout)) + return FALSE; + + _dbus_timeout_ref (timeout); + + if (timeout_list->add_timeout_function != NULL) + { + if (!(* timeout_list->add_timeout_function) (timeout, + timeout_list->timeout_data)) + { + _dbus_list_remove_last (&timeout_list->timeouts, timeout); + _dbus_timeout_unref (timeout); + return FALSE; + } + } + + return TRUE; +} + +/** + * Removes a timeout from the timeout list, invoking the + * application's DBusRemoveTimeoutFunction if appropriate. + * + * @param timeout_list the timeout list. + * @param timeout the timeout to remove. + */ +void +_dbus_timeout_list_remove_timeout (DBusTimeoutList *timeout_list, + DBusTimeout *timeout) +{ + if (!_dbus_list_remove (&timeout_list->timeouts, timeout)) + _dbus_assert_not_reached ("Nonexistent timeout was removed"); + + if (timeout_list->remove_timeout_function != NULL) + (* timeout_list->remove_timeout_function) (timeout, + timeout_list->timeout_data); + + _dbus_timeout_unref (timeout); +} + +/** + * Sets a timeout to the given enabled state, invoking the + * application's DBusTimeoutToggledFunction if appropriate. + * + * @param timeout_list the timeout list. + * @param timeout the timeout to toggle. + * @param enabled #TRUE to enable + */ +void +_dbus_timeout_list_toggle_timeout (DBusTimeoutList *timeout_list, + DBusTimeout *timeout, + dbus_bool_t enabled) +{ + enabled = !!enabled; + + if (enabled == timeout->enabled) + return; + + timeout->enabled = enabled; + + if (timeout_list->timeout_toggled_function != NULL) + (* timeout_list->timeout_toggled_function) (timeout, + timeout_list->timeout_data); +} + +/** @} */ + +/** + * @defgroup DBusTimeout DBusTimeout + * @ingroup DBus + * @brief Object representing a timeout + * + * Types and functions related to DBusTimeout. A timeout + * represents a timeout that the main loop needs to monitor, + * as in Qt's QTimer or GLib's g_timeout_add(). + * + * Use dbus_connection_set_timeout_functions() or dbus_server_set_timeout_functions() + * to be notified when libdbus needs to add or remove timeouts. + * + * @{ + */ + + +/** + * @typedef DBusTimeout + * + * Opaque object representing a timeout. + */ + +/** + * Gets the timeout interval. The dbus_timeout_handle() + * should be called each time this interval elapses, + * starting after it elapses once. + * + * The interval may change during the life of the + * timeout; if so, the timeout will be disabled and + * re-enabled (calling the "timeout toggled function") + * to notify you of the change. + * + * @param timeout the DBusTimeout object. + * @returns the interval in milliseconds. + */ +int +dbus_timeout_get_interval (DBusTimeout *timeout) +{ + return timeout->interval; +} + +/** + * Gets data previously set with dbus_timeout_set_data() + * or #NULL if none. + * + * @param timeout the DBusTimeout object. + * @returns previously-set data. + */ +void* +dbus_timeout_get_data (DBusTimeout *timeout) +{ + return timeout->data; +} + +/** + * Sets data which can be retrieved with dbus_timeout_get_data(). + * Intended for use by the DBusAddTimeoutFunction and + * DBusRemoveTimeoutFunction to store their own data. For example with + * Qt you might store the QTimer for this timeout and with GLib + * you might store a g_timeout_add result id. + * + * @param timeout the DBusTimeout object. + * @param data the data. + * @param free_data_function function to be called to free the data. + */ +void +dbus_timeout_set_data (DBusTimeout *timeout, + void *data, + DBusFreeFunction free_data_function) +{ + if (timeout->free_data_function != NULL) + (* timeout->free_data_function) (timeout->data); + + timeout->data = data; + timeout->free_data_function = free_data_function; +} + +/** + * Calls the timeout handler for this timeout. + * This function should be called when the timeout + * occurs. + * + * If this function returns #FALSE, then there wasn't + * enough memory to handle the timeout. Typically just + * letting the timeout fire again next time it naturally + * times out is an adequate response to that problem, + * but you could try to do more if you wanted. + * + * @param timeout the DBusTimeout object. + * @returns #FALSE if there wasn't enough memory + */ +dbus_bool_t +dbus_timeout_handle (DBusTimeout *timeout) +{ + return (* timeout->handler) (timeout->handler_data); +} + + +/** + * Returns whether a timeout is enabled or not. If not + * enabled, it should not be polled by the main loop. + * + * @param timeout the DBusTimeout object + * @returns #TRUE if the timeout is enabled + */ +dbus_bool_t +dbus_timeout_get_enabled (DBusTimeout *timeout) +{ + return timeout->enabled; +} + +/** @} end public API docs */ diff --git a/dbus/dbus-timeout.h b/dbus/dbus-timeout.h new file mode 100644 index 00000000..d0a8af4a --- /dev/null +++ b/dbus/dbus-timeout.h @@ -0,0 +1,75 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-timeout.h DBusTimeout internal interfaces + * + * Copyright (C) 2003 CodeFactory AB + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_TIMEOUT_H +#define DBUS_TIMEOUT_H + +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusTimeoutInternals + * @{ + */ + +/* Public methods on DBusTimeout are in dbus-connection.h */ + +typedef struct DBusTimeoutList DBusTimeoutList; + +/** function to run when the timeout is handled */ +typedef dbus_bool_t (* DBusTimeoutHandler) (void *data); + +DBusTimeout* _dbus_timeout_new (int interval, + DBusTimeoutHandler handler, + void *data, + DBusFreeFunction free_data_function); +DBusTimeout* _dbus_timeout_ref (DBusTimeout *timeout); +void _dbus_timeout_unref (DBusTimeout *timeout); +void _dbus_timeout_set_interval (DBusTimeout *timeout, + int interval); +void _dbus_timeout_set_enabled (DBusTimeout *timeout, + dbus_bool_t enabled); + +DBusTimeoutList *_dbus_timeout_list_new (void); +void _dbus_timeout_list_free (DBusTimeoutList *timeout_list); +dbus_bool_t _dbus_timeout_list_set_functions (DBusTimeoutList *timeout_list, + DBusAddTimeoutFunction add_function, + DBusRemoveTimeoutFunction remove_function, + DBusTimeoutToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t _dbus_timeout_list_add_timeout (DBusTimeoutList *timeout_list, + DBusTimeout *timeout); +void _dbus_timeout_list_remove_timeout (DBusTimeoutList *timeout_list, + DBusTimeout *timeout); +void _dbus_timeout_list_toggle_timeout (DBusTimeoutList *timeout_list, + DBusTimeout *timeout, + dbus_bool_t enabled); + + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_TIMEOUT_H */ diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h new file mode 100644 index 00000000..280bbd3d --- /dev/null +++ b/dbus/dbus-transport-protected.h @@ -0,0 +1,143 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-transport-protected.h Used by subclasses of DBusTransport object (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2004 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_TRANSPORT_PROTECTED_H +#define DBUS_TRANSPORT_PROTECTED_H + +#include +#include +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +typedef struct DBusTransportVTable DBusTransportVTable; + +/** + * The virtual table that must be implemented to + * create a new kind of transport. + */ +struct DBusTransportVTable +{ + void (* finalize) (DBusTransport *transport); + /**< The finalize method must free the transport. */ + + dbus_bool_t (* handle_watch) (DBusTransport *transport, + DBusWatch *watch, + unsigned int flags); + /**< The handle_watch method handles reading/writing + * data as indicated by the flags. + */ + + void (* disconnect) (DBusTransport *transport); + /**< Disconnect this transport. */ + + dbus_bool_t (* connection_set) (DBusTransport *transport); + /**< Called when transport->connection has been filled in */ + + void (* do_iteration) (DBusTransport *transport, + unsigned int flags, + int timeout_milliseconds); + /**< Called to do a single "iteration" (block on select/poll + * followed by reading or writing data). + */ + + void (* live_messages_changed) (DBusTransport *transport); + /**< Outstanding messages counter changed */ + + dbus_bool_t (* get_socket_fd) (DBusTransport *transport, + int *fd_p); + /**< Get socket file descriptor */ +}; + +/** + * Object representing a transport such as a socket. + * A transport can shuttle messages from point A to point B, + * and is the backend for a #DBusConnection. + * + */ +struct DBusTransport +{ + int refcount; /**< Reference count. */ + + const DBusTransportVTable *vtable; /**< Virtual methods for this instance. */ + + DBusConnection *connection; /**< Connection owning this transport. */ + + DBusMessageLoader *loader; /**< Message-loading buffer. */ + + DBusAuth *auth; /**< Authentication conversation */ + + DBusCredentials *credentials; /**< Credentials of other end read from the socket */ + + long max_live_messages_size; /**< Max total size of received messages. */ + + DBusCounter *live_messages_size; /**< Counter for size of all live messages. */ + + + char *address; /**< Address of the server we are connecting to (#NULL for the server side of a transport) */ + + char *expected_guid; /**< GUID we expect the server to have, #NULL on server side or if we don't have an expectation */ + + DBusAllowUnixUserFunction unix_user_function; /**< Function for checking whether a user is authorized. */ + void *unix_user_data; /**< Data for unix_user_function */ + + DBusFreeFunction free_unix_user_data; /**< Function to free unix_user_data */ + + DBusAllowWindowsUserFunction windows_user_function; /**< Function for checking whether a user is authorized. */ + void *windows_user_data; /**< Data for windows_user_function */ + + DBusFreeFunction free_windows_user_data; /**< Function to free windows_user_data */ + + unsigned int disconnected : 1; /**< #TRUE if we are disconnected. */ + unsigned int authenticated : 1; /**< Cache of auth state; use _dbus_transport_get_is_authenticated() to query value */ + unsigned int send_credentials_pending : 1; /**< #TRUE if we need to send credentials */ + unsigned int receive_credentials_pending : 1; /**< #TRUE if we need to receive credentials */ + unsigned int is_server : 1; /**< #TRUE if on the server side */ + unsigned int unused_bytes_recovered : 1; /**< #TRUE if we've recovered unused bytes from auth */ + unsigned int allow_anonymous : 1; /**< #TRUE if an anonymous client can connect */ +}; + +dbus_bool_t _dbus_transport_init_base (DBusTransport *transport, + const DBusTransportVTable *vtable, + const DBusString *server_guid, + const DBusString *address); +void _dbus_transport_finalize_base (DBusTransport *transport); + + +typedef enum +{ + DBUS_TRANSPORT_OPEN_NOT_HANDLED, /**< we aren't in charge of this address type */ + DBUS_TRANSPORT_OPEN_OK, /**< we set up the listen */ + DBUS_TRANSPORT_OPEN_BAD_ADDRESS, /**< malformed address */ + DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT /**< well-formed address but failed to set it up */ +} DBusTransportOpenResult; + +DBusTransportOpenResult _dbus_transport_open_platform_specific (DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error); + +DBUS_END_DECLS + +#endif /* DBUS_TRANSPORT_PROTECTED_H */ diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c new file mode 100644 index 00000000..05d7d91f --- /dev/null +++ b/dbus/dbus-transport-socket.c @@ -0,0 +1,1357 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-transport-socket.c Socket subclasses of DBusTransport + * + * Copyright (C) 2002, 2003, 2004, 2006 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-connection-internal.h" +#include "dbus-transport-socket.h" +#include "dbus-transport-protected.h" +#include "dbus-watch.h" +#include "dbus-credentials.h" + + +/** + * @defgroup DBusTransportSocket DBusTransport implementations for sockets + * @ingroup DBusInternals + * @brief Implementation details of DBusTransport on sockets + * + * @{ + */ + +/** + * Opaque object representing a socket file descriptor transport. + */ +typedef struct DBusTransportSocket DBusTransportSocket; + +/** + * Implementation details of DBusTransportSocket. All members are private. + */ +struct DBusTransportSocket +{ + DBusTransport base; /**< Parent instance */ + int fd; /**< File descriptor. */ + DBusWatch *read_watch; /**< Watch for readability. */ + DBusWatch *write_watch; /**< Watch for writability. */ + + int max_bytes_read_per_iteration; /**< To avoid blocking too long. */ + int max_bytes_written_per_iteration; /**< To avoid blocking too long. */ + + int message_bytes_written; /**< Number of bytes of current + * outgoing message that have + * been written. + */ + DBusString encoded_outgoing; /**< Encoded version of current + * outgoing message. + */ + DBusString encoded_incoming; /**< Encoded version of current + * incoming data. + */ +}; + +static void +free_watches (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + + if (socket_transport->read_watch) + { + if (transport->connection) + _dbus_connection_remove_watch_unlocked (transport->connection, + socket_transport->read_watch); + _dbus_watch_invalidate (socket_transport->read_watch); + _dbus_watch_unref (socket_transport->read_watch); + socket_transport->read_watch = NULL; + } + + if (socket_transport->write_watch) + { + if (transport->connection) + _dbus_connection_remove_watch_unlocked (transport->connection, + socket_transport->write_watch); + _dbus_watch_invalidate (socket_transport->write_watch); + _dbus_watch_unref (socket_transport->write_watch); + socket_transport->write_watch = NULL; + } + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); +} + +static void +socket_finalize (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + + free_watches (transport); + + _dbus_string_free (&socket_transport->encoded_outgoing); + _dbus_string_free (&socket_transport->encoded_incoming); + + _dbus_transport_finalize_base (transport); + + _dbus_assert (socket_transport->read_watch == NULL); + _dbus_assert (socket_transport->write_watch == NULL); + + dbus_free (transport); +} + +static void +check_write_watch (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + dbus_bool_t needed; + + if (transport->connection == NULL) + return; + + if (transport->disconnected) + { + _dbus_assert (socket_transport->write_watch == NULL); + return; + } + + _dbus_transport_ref (transport); + + if (_dbus_transport_get_is_authenticated (transport)) + needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection); + else + { + if (transport->send_credentials_pending) + needed = TRUE; + else + { + DBusAuthState auth_state; + + auth_state = _dbus_auth_do_work (transport->auth); + + /* If we need memory we install the write watch just in case, + * if there's no need for it, it will get de-installed + * next time we try reading. + */ + if (auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND || + auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY) + needed = TRUE; + else + needed = FALSE; + } + } + + _dbus_verbose ("check_write_watch(): needed = %d on connection %p watch %p fd = %d outgoing messages exist %d\n", + needed, transport->connection, socket_transport->write_watch, + socket_transport->fd, + _dbus_connection_has_messages_to_send_unlocked (transport->connection)); + + _dbus_connection_toggle_watch_unlocked (transport->connection, + socket_transport->write_watch, + needed); + + _dbus_transport_unref (transport); +} + +static void +check_read_watch (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + dbus_bool_t need_read_watch; + + _dbus_verbose ("%s: fd = %d\n", + _DBUS_FUNCTION_NAME, socket_transport->fd); + + if (transport->connection == NULL) + return; + + if (transport->disconnected) + { + _dbus_assert (socket_transport->read_watch == NULL); + return; + } + + _dbus_transport_ref (transport); + + if (_dbus_transport_get_is_authenticated (transport)) + need_read_watch = + _dbus_counter_get_value (transport->live_messages_size) < transport->max_live_messages_size; + else + { + if (transport->receive_credentials_pending) + need_read_watch = TRUE; + else + { + /* The reason to disable need_read_watch when not WAITING_FOR_INPUT + * is to avoid spinning on the file descriptor when we're waiting + * to write or for some other part of the auth process + */ + DBusAuthState auth_state; + + auth_state = _dbus_auth_do_work (transport->auth); + + /* If we need memory we install the read watch just in case, + * if there's no need for it, it will get de-installed + * next time we try reading. If we're authenticated we + * install it since we normally have it installed while + * authenticated. + */ + if (auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT || + auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY || + auth_state == DBUS_AUTH_STATE_AUTHENTICATED) + need_read_watch = TRUE; + else + need_read_watch = FALSE; + } + } + + _dbus_verbose (" setting read watch enabled = %d\n", need_read_watch); + _dbus_connection_toggle_watch_unlocked (transport->connection, + socket_transport->read_watch, + need_read_watch); + + _dbus_transport_unref (transport); +} + +static void +do_io_error (DBusTransport *transport) +{ + _dbus_transport_ref (transport); + _dbus_transport_disconnect (transport); + _dbus_transport_unref (transport); +} + +/* return value is whether we successfully read any new data. */ +static dbus_bool_t +read_data_into_auth (DBusTransport *transport, + dbus_bool_t *oom) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + DBusString *buffer; + int bytes_read; + + *oom = FALSE; + + _dbus_auth_get_buffer (transport->auth, &buffer); + + bytes_read = _dbus_read_socket (socket_transport->fd, + buffer, socket_transport->max_bytes_read_per_iteration); + + _dbus_auth_return_buffer (transport->auth, buffer, + bytes_read > 0 ? bytes_read : 0); + + if (bytes_read > 0) + { + _dbus_verbose (" read %d bytes in auth phase\n", bytes_read); + + return TRUE; + } + else if (bytes_read < 0) + { + /* EINTR already handled for us */ + + if (_dbus_get_is_errno_enomem ()) + { + *oom = TRUE; + } + else if (_dbus_get_is_errno_eagain_or_ewouldblock ()) + ; /* do nothing, just return FALSE below */ + else + { + _dbus_verbose ("Error reading from remote app: %s\n", + _dbus_strerror_from_errno ()); + do_io_error (transport); + } + + return FALSE; + } + else + { + _dbus_assert (bytes_read == 0); + + _dbus_verbose ("Disconnected from remote app\n"); + do_io_error (transport); + + return FALSE; + } +} + +/* Return value is whether we successfully wrote any bytes */ +static dbus_bool_t +write_data_from_auth (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + int bytes_written; + const DBusString *buffer; + + if (!_dbus_auth_get_bytes_to_send (transport->auth, + &buffer)) + return FALSE; + + bytes_written = _dbus_write_socket (socket_transport->fd, + buffer, + 0, _dbus_string_get_length (buffer)); + + if (bytes_written > 0) + { + _dbus_auth_bytes_sent (transport->auth, bytes_written); + return TRUE; + } + else if (bytes_written < 0) + { + /* EINTR already handled for us */ + + if (_dbus_get_is_errno_eagain_or_ewouldblock ()) + ; + else + { + _dbus_verbose ("Error writing to remote app: %s\n", + _dbus_strerror_from_errno ()); + do_io_error (transport); + } + } + + return FALSE; +} + +/* FALSE on OOM */ +static dbus_bool_t +exchange_credentials (DBusTransport *transport, + dbus_bool_t do_reading, + dbus_bool_t do_writing) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + DBusError error = DBUS_ERROR_INIT; + + _dbus_verbose ("exchange_credentials: do_reading = %d, do_writing = %d\n", + do_reading, do_writing); + + if (do_writing && transport->send_credentials_pending) + { + if (_dbus_send_credentials_socket (socket_transport->fd, + &error)) + { + transport->send_credentials_pending = FALSE; + } + else + { + _dbus_verbose ("Failed to write credentials: %s\n", error.message); + dbus_error_free (&error); + do_io_error (transport); + } + } + + if (do_reading && transport->receive_credentials_pending) + { + /* FIXME this can fail due to IO error _or_ OOM, broken + * (somewhat tricky to fix since the OOM error can be set after + * we already read the credentials byte, so basically we need to + * separate reading the byte and storing it in the + * transport->credentials). Does not really matter for now + * because storing in credentials never actually fails on unix. + */ + if (_dbus_read_credentials_socket (socket_transport->fd, + transport->credentials, + &error)) + { + transport->receive_credentials_pending = FALSE; + } + else + { + _dbus_verbose ("Failed to read credentials %s\n", error.message); + dbus_error_free (&error); + do_io_error (transport); + } + } + + if (!(transport->send_credentials_pending || + transport->receive_credentials_pending)) + { + if (!_dbus_auth_set_credentials (transport->auth, + transport->credentials)) + return FALSE; + } + + return TRUE; +} + +static dbus_bool_t +do_authentication (DBusTransport *transport, + dbus_bool_t do_reading, + dbus_bool_t do_writing, + dbus_bool_t *auth_completed) +{ + dbus_bool_t oom; + dbus_bool_t orig_auth_state; + + oom = FALSE; + + orig_auth_state = _dbus_transport_get_is_authenticated (transport); + + /* This is essential to avoid the check_write_watch() at the end, + * we don't want to add a write watch in do_iteration before + * we try writing and get EAGAIN + */ + if (orig_auth_state) + { + if (auth_completed) + *auth_completed = FALSE; + return TRUE; + } + + _dbus_transport_ref (transport); + + while (!_dbus_transport_get_is_authenticated (transport) && + _dbus_transport_get_is_connected (transport)) + { + if (!exchange_credentials (transport, do_reading, do_writing)) + { + /* OOM */ + oom = TRUE; + goto out; + } + + if (transport->send_credentials_pending || + transport->receive_credentials_pending) + { + _dbus_verbose ("send_credentials_pending = %d receive_credentials_pending = %d\n", + transport->send_credentials_pending, + transport->receive_credentials_pending); + goto out; + } + +#define TRANSPORT_SIDE(t) ((t)->is_server ? "server" : "client") + switch (_dbus_auth_do_work (transport->auth)) + { + case DBUS_AUTH_STATE_WAITING_FOR_INPUT: + _dbus_verbose (" %s auth state: waiting for input\n", + TRANSPORT_SIDE (transport)); + if (!do_reading || !read_data_into_auth (transport, &oom)) + goto out; + break; + + case DBUS_AUTH_STATE_WAITING_FOR_MEMORY: + _dbus_verbose (" %s auth state: waiting for memory\n", + TRANSPORT_SIDE (transport)); + oom = TRUE; + goto out; + break; + + case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND: + _dbus_verbose (" %s auth state: bytes to send\n", + TRANSPORT_SIDE (transport)); + if (!do_writing || !write_data_from_auth (transport)) + goto out; + break; + + case DBUS_AUTH_STATE_NEED_DISCONNECT: + _dbus_verbose (" %s auth state: need to disconnect\n", + TRANSPORT_SIDE (transport)); + do_io_error (transport); + break; + + case DBUS_AUTH_STATE_AUTHENTICATED: + _dbus_verbose (" %s auth state: authenticated\n", + TRANSPORT_SIDE (transport)); + break; + } + } + + out: + if (auth_completed) + *auth_completed = (orig_auth_state != _dbus_transport_get_is_authenticated (transport)); + + check_read_watch (transport); + check_write_watch (transport); + _dbus_transport_unref (transport); + + if (oom) + return FALSE; + else + return TRUE; +} + +/* returns false on oom */ +static dbus_bool_t +do_writing (DBusTransport *transport) +{ + int total; + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + dbus_bool_t oom; + + /* No messages without authentication! */ + if (!_dbus_transport_get_is_authenticated (transport)) + { + _dbus_verbose ("Not authenticated, not writing anything\n"); + return TRUE; + } + + if (transport->disconnected) + { + _dbus_verbose ("Not connected, not writing anything\n"); + return TRUE; + } + +#if 1 + _dbus_verbose ("do_writing(), have_messages = %d, fd = %d\n", + _dbus_connection_has_messages_to_send_unlocked (transport->connection), + socket_transport->fd); +#endif + + oom = FALSE; + total = 0; + + while (!transport->disconnected && + _dbus_connection_has_messages_to_send_unlocked (transport->connection)) + { + int bytes_written; + DBusMessage *message; + const DBusString *header; + const DBusString *body; + int header_len, body_len; + int total_bytes_to_write; + + if (total > socket_transport->max_bytes_written_per_iteration) + { + _dbus_verbose ("%d bytes exceeds %d bytes written per iteration, returning\n", + total, socket_transport->max_bytes_written_per_iteration); + goto out; + } + + message = _dbus_connection_get_message_to_send (transport->connection); + _dbus_assert (message != NULL); + dbus_message_lock (message); + +#if 0 + _dbus_verbose ("writing message %p\n", message); +#endif + + _dbus_message_get_network_data (message, + &header, &body); + + header_len = _dbus_string_get_length (header); + body_len = _dbus_string_get_length (body); + + if (_dbus_auth_needs_encoding (transport->auth)) + { + if (_dbus_string_get_length (&socket_transport->encoded_outgoing) == 0) + { + if (!_dbus_auth_encode_data (transport->auth, + header, &socket_transport->encoded_outgoing)) + { + oom = TRUE; + goto out; + } + + if (!_dbus_auth_encode_data (transport->auth, + body, &socket_transport->encoded_outgoing)) + { + _dbus_string_set_length (&socket_transport->encoded_outgoing, 0); + oom = TRUE; + goto out; + } + } + + total_bytes_to_write = _dbus_string_get_length (&socket_transport->encoded_outgoing); + +#if 0 + _dbus_verbose ("encoded message is %d bytes\n", + total_bytes_to_write); +#endif + + bytes_written = + _dbus_write_socket (socket_transport->fd, + &socket_transport->encoded_outgoing, + socket_transport->message_bytes_written, + total_bytes_to_write - socket_transport->message_bytes_written); + } + else + { + total_bytes_to_write = header_len + body_len; + +#if 0 + _dbus_verbose ("message is %d bytes\n", + total_bytes_to_write); +#endif + + if (socket_transport->message_bytes_written < header_len) + { + bytes_written = + _dbus_write_socket_two (socket_transport->fd, + header, + socket_transport->message_bytes_written, + header_len - socket_transport->message_bytes_written, + body, + 0, body_len); + } + else + { + bytes_written = + _dbus_write_socket (socket_transport->fd, + body, + (socket_transport->message_bytes_written - header_len), + body_len - + (socket_transport->message_bytes_written - header_len)); + } + } + + if (bytes_written < 0) + { + /* EINTR already handled for us */ + + /* For some discussion of why we also ignore EPIPE here, see + * http://lists.freedesktop.org/archives/dbus/2008-March/009526.html + */ + + if (_dbus_get_is_errno_eagain_or_ewouldblock () || _dbus_get_is_errno_epipe ()) + goto out; + else + { + _dbus_verbose ("Error writing to remote app: %s\n", + _dbus_strerror_from_errno ()); + do_io_error (transport); + goto out; + } + } + else + { + _dbus_verbose (" wrote %d bytes of %d\n", bytes_written, + total_bytes_to_write); + + total += bytes_written; + socket_transport->message_bytes_written += bytes_written; + + _dbus_assert (socket_transport->message_bytes_written <= + total_bytes_to_write); + + if (socket_transport->message_bytes_written == total_bytes_to_write) + { + socket_transport->message_bytes_written = 0; + _dbus_string_set_length (&socket_transport->encoded_outgoing, 0); + _dbus_string_compact (&socket_transport->encoded_outgoing, 2048); + + _dbus_connection_message_sent (transport->connection, + message); + } + } + } + + out: + if (oom) + return FALSE; + else + return TRUE; +} + +/* returns false on out-of-memory */ +static dbus_bool_t +do_reading (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + DBusString *buffer; + int bytes_read; + int total; + dbus_bool_t oom; + + _dbus_verbose ("%s: fd = %d\n", _DBUS_FUNCTION_NAME, + socket_transport->fd); + + /* No messages without authentication! */ + if (!_dbus_transport_get_is_authenticated (transport)) + return TRUE; + + oom = FALSE; + + total = 0; + + again: + + /* See if we've exceeded max messages and need to disable reading */ + check_read_watch (transport); + + if (total > socket_transport->max_bytes_read_per_iteration) + { + _dbus_verbose ("%d bytes exceeds %d bytes read per iteration, returning\n", + total, socket_transport->max_bytes_read_per_iteration); + goto out; + } + + _dbus_assert (socket_transport->read_watch != NULL || + transport->disconnected); + + if (transport->disconnected) + goto out; + + if (!dbus_watch_get_enabled (socket_transport->read_watch)) + return TRUE; + + if (_dbus_auth_needs_decoding (transport->auth)) + { + if (_dbus_string_get_length (&socket_transport->encoded_incoming) > 0) + bytes_read = _dbus_string_get_length (&socket_transport->encoded_incoming); + else + bytes_read = _dbus_read_socket (socket_transport->fd, + &socket_transport->encoded_incoming, + socket_transport->max_bytes_read_per_iteration); + + _dbus_assert (_dbus_string_get_length (&socket_transport->encoded_incoming) == + bytes_read); + + if (bytes_read > 0) + { + int orig_len; + + _dbus_message_loader_get_buffer (transport->loader, + &buffer); + + orig_len = _dbus_string_get_length (buffer); + + if (!_dbus_auth_decode_data (transport->auth, + &socket_transport->encoded_incoming, + buffer)) + { + _dbus_verbose ("Out of memory decoding incoming data\n"); + _dbus_message_loader_return_buffer (transport->loader, + buffer, + _dbus_string_get_length (buffer) - orig_len); + + oom = TRUE; + goto out; + } + + _dbus_message_loader_return_buffer (transport->loader, + buffer, + _dbus_string_get_length (buffer) - orig_len); + + _dbus_string_set_length (&socket_transport->encoded_incoming, 0); + _dbus_string_compact (&socket_transport->encoded_incoming, 2048); + } + } + else + { + _dbus_message_loader_get_buffer (transport->loader, + &buffer); + + bytes_read = _dbus_read_socket (socket_transport->fd, + buffer, socket_transport->max_bytes_read_per_iteration); + + _dbus_message_loader_return_buffer (transport->loader, + buffer, + bytes_read < 0 ? 0 : bytes_read); + } + + if (bytes_read < 0) + { + /* EINTR already handled for us */ + + if (_dbus_get_is_errno_enomem ()) + { + _dbus_verbose ("Out of memory in read()/do_reading()\n"); + oom = TRUE; + goto out; + } + else if (_dbus_get_is_errno_eagain_or_ewouldblock ()) + goto out; + else + { + _dbus_verbose ("Error reading from remote app: %s\n", + _dbus_strerror_from_errno ()); + do_io_error (transport); + goto out; + } + } + else if (bytes_read == 0) + { + _dbus_verbose ("Disconnected from remote app\n"); + do_io_error (transport); + goto out; + } + else + { + _dbus_verbose (" read %d bytes\n", bytes_read); + + total += bytes_read; + + if (!_dbus_transport_queue_messages (transport)) + { + oom = TRUE; + _dbus_verbose (" out of memory when queueing messages we just read in the transport\n"); + goto out; + } + + /* Try reading more data until we get EAGAIN and return, or + * exceed max bytes per iteration. If in blocking mode of + * course we'll block instead of returning. + */ + goto again; + } + + out: + if (oom) + return FALSE; + else + return TRUE; +} + +static dbus_bool_t +unix_error_with_read_to_come (DBusTransport *itransport, + DBusWatch *watch, + unsigned int flags) +{ + DBusTransportSocket *transport = (DBusTransportSocket *) itransport; + + if (!(flags & DBUS_WATCH_HANGUP || flags & DBUS_WATCH_ERROR)) + return FALSE; + + /* If we have a read watch enabled ... + we -might have data incoming ... => handle the HANGUP there */ + if (watch != transport->read_watch && + _dbus_watch_get_enabled (transport->read_watch)) + return FALSE; + + return TRUE; +} + +static dbus_bool_t +socket_handle_watch (DBusTransport *transport, + DBusWatch *watch, + unsigned int flags) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + _dbus_assert (watch == socket_transport->read_watch || + watch == socket_transport->write_watch); + _dbus_assert (watch != NULL); + + /* If we hit an error here on a write watch, don't disconnect the transport yet because data can + * still be in the buffer and do_reading may need several iteration to read + * it all (because of its max_bytes_read_per_iteration limit). + */ + if (!(flags & DBUS_WATCH_READABLE) && unix_error_with_read_to_come (transport, watch, flags)) + { + _dbus_verbose ("Hang up or error on watch\n"); + _dbus_transport_disconnect (transport); + return TRUE; + } + + if (watch == socket_transport->read_watch && + (flags & DBUS_WATCH_READABLE)) + { + dbus_bool_t auth_finished; +#if 1 + _dbus_verbose ("handling read watch %p flags = %x\n", + watch, flags); +#endif + if (!do_authentication (transport, TRUE, FALSE, &auth_finished)) + return FALSE; + + /* We don't want to do a read immediately following + * a successful authentication. This is so we + * have a chance to propagate the authentication + * state further up. Specifically, we need to + * process any pending data from the auth object. + */ + if (!auth_finished) + { + if (!do_reading (transport)) + { + _dbus_verbose ("no memory to read\n"); + return FALSE; + } + } + else + { + _dbus_verbose ("Not reading anything since we just completed the authentication\n"); + } + } + else if (watch == socket_transport->write_watch && + (flags & DBUS_WATCH_WRITABLE)) + { +#if 1 + _dbus_verbose ("handling write watch, have_outgoing_messages = %d\n", + _dbus_connection_has_messages_to_send_unlocked (transport->connection)); +#endif + if (!do_authentication (transport, FALSE, TRUE, NULL)) + return FALSE; + + if (!do_writing (transport)) + { + _dbus_verbose ("no memory to write\n"); + return FALSE; + } + + /* See if we still need the write watch */ + check_write_watch (transport); + } +#ifdef DBUS_ENABLE_VERBOSE_MODE + else + { + if (watch == socket_transport->read_watch) + _dbus_verbose ("asked to handle read watch with non-read condition 0x%x\n", + flags); + else if (watch == socket_transport->write_watch) + _dbus_verbose ("asked to handle write watch with non-write condition 0x%x\n", + flags); + else + _dbus_verbose ("asked to handle watch %p on fd %d that we don't recognize\n", + watch, dbus_watch_get_socket (watch)); + } +#endif /* DBUS_ENABLE_VERBOSE_MODE */ + + return TRUE; +} + +static void +socket_disconnect (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME); + + free_watches (transport); + + _dbus_close_socket (socket_transport->fd, NULL); + socket_transport->fd = -1; +} + +static dbus_bool_t +socket_connection_set (DBusTransport *transport) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + _dbus_watch_set_handler (socket_transport->write_watch, + _dbus_connection_handle_watch, + transport->connection, NULL); + + _dbus_watch_set_handler (socket_transport->read_watch, + _dbus_connection_handle_watch, + transport->connection, NULL); + + if (!_dbus_connection_add_watch_unlocked (transport->connection, + socket_transport->write_watch)) + return FALSE; + + if (!_dbus_connection_add_watch_unlocked (transport->connection, + socket_transport->read_watch)) + { + _dbus_connection_remove_watch_unlocked (transport->connection, + socket_transport->write_watch); + return FALSE; + } + + check_read_watch (transport); + check_write_watch (transport); + + return TRUE; +} + +/** + * @todo We need to have a way to wake up the select sleep if + * a new iteration request comes in with a flag (read/write) that + * we're not currently serving. Otherwise a call that just reads + * could block a write call forever (if there are no incoming + * messages). + */ +static void +socket_do_iteration (DBusTransport *transport, + unsigned int flags, + int timeout_milliseconds) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + DBusPollFD poll_fd; + int poll_res; + int poll_timeout; + + _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p fd = %d\n", + flags & DBUS_ITERATION_DO_READING ? "read" : "", + flags & DBUS_ITERATION_DO_WRITING ? "write" : "", + timeout_milliseconds, + socket_transport->read_watch, + socket_transport->write_watch, + socket_transport->fd); + + /* the passed in DO_READING/DO_WRITING flags indicate whether to + * read/write messages, but regardless of those we may need to block + * for reading/writing to do auth. But if we do reading for auth, + * we don't want to read any messages yet if not given DO_READING. + */ + + poll_fd.fd = socket_transport->fd; + poll_fd.events = 0; + + if (_dbus_transport_get_is_authenticated (transport)) + { + /* This is kind of a hack; if we have stuff to write, then try + * to avoid the poll. This is probably about a 5% speedup on an + * echo client/server. + * + * If both reading and writing were requested, we want to avoid this + * since it could have funky effects: + * - both ends spinning waiting for the other one to read + * data so they can finish writing + * - prioritizing all writing ahead of reading + */ + if ((flags & DBUS_ITERATION_DO_WRITING) && + !(flags & (DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK)) && + !transport->disconnected && + _dbus_connection_has_messages_to_send_unlocked (transport->connection)) + { + do_writing (transport); + + if (transport->disconnected || + !_dbus_connection_has_messages_to_send_unlocked (transport->connection)) + goto out; + } + + /* If we get here, we decided to do the poll() after all */ + _dbus_assert (socket_transport->read_watch); + if (flags & DBUS_ITERATION_DO_READING) + poll_fd.events |= _DBUS_POLLIN; + + _dbus_assert (socket_transport->write_watch); + if (flags & DBUS_ITERATION_DO_WRITING) + poll_fd.events |= _DBUS_POLLOUT; + } + else + { + DBusAuthState auth_state; + + auth_state = _dbus_auth_do_work (transport->auth); + + if (transport->receive_credentials_pending || + auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT) + poll_fd.events |= _DBUS_POLLIN; + + if (transport->send_credentials_pending || + auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND) + poll_fd.events |= _DBUS_POLLOUT; + } + + if (poll_fd.events) + { + if (flags & DBUS_ITERATION_BLOCK) + poll_timeout = timeout_milliseconds; + else + poll_timeout = 0; + + /* For blocking selects we drop the connection lock here + * to avoid blocking out connection access during a potentially + * indefinite blocking call. The io path is still protected + * by the io_path_cond condvar, so we won't reenter this. + */ + if (flags & DBUS_ITERATION_BLOCK) + { + _dbus_verbose ("unlock %s pre poll\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (transport->connection); + } + + again: + poll_res = _dbus_poll (&poll_fd, 1, poll_timeout); + + if (poll_res < 0 && _dbus_get_is_errno_eintr ()) + goto again; + + if (flags & DBUS_ITERATION_BLOCK) + { + _dbus_verbose ("lock %s post poll\n", _DBUS_FUNCTION_NAME); + _dbus_connection_lock (transport->connection); + } + + if (poll_res >= 0) + { + if (poll_res == 0) + poll_fd.revents = 0; /* some concern that posix does not guarantee this; + * valgrind flags it as an error. though it probably + * is guaranteed on linux at least. + */ + + if (poll_fd.revents & _DBUS_POLLERR) + do_io_error (transport); + else + { + dbus_bool_t need_read = (poll_fd.revents & _DBUS_POLLIN) > 0; + dbus_bool_t need_write = (poll_fd.revents & _DBUS_POLLOUT) > 0; + dbus_bool_t authentication_completed; + + _dbus_verbose ("in iteration, need_read=%d need_write=%d\n", + need_read, need_write); + do_authentication (transport, need_read, need_write, + &authentication_completed); + + /* See comment in socket_handle_watch. */ + if (authentication_completed) + goto out; + + if (need_read && (flags & DBUS_ITERATION_DO_READING)) + do_reading (transport); + if (need_write && (flags & DBUS_ITERATION_DO_WRITING)) + do_writing (transport); + } + } + else + { + _dbus_verbose ("Error from _dbus_poll(): %s\n", + _dbus_strerror_from_errno ()); + } + } + + + out: + /* We need to install the write watch only if we did not + * successfully write everything. Note we need to be careful that we + * don't call check_write_watch *before* do_writing, since it's + * inefficient to add the write watch, and we can avoid it most of + * the time since we can write immediately. + * + * However, we MUST always call check_write_watch(); DBusConnection code + * relies on the fact that running an iteration will notice that + * messages are pending. + */ + check_write_watch (transport); + + _dbus_verbose (" ... leaving do_iteration()\n"); +} + +static void +socket_live_messages_changed (DBusTransport *transport) +{ + /* See if we should look for incoming messages again */ + check_read_watch (transport); +} + + +static dbus_bool_t +socket_get_socket_fd (DBusTransport *transport, + int *fd_p) +{ + DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; + + *fd_p = socket_transport->fd; + + return TRUE; +} + +static const DBusTransportVTable socket_vtable = { + socket_finalize, + socket_handle_watch, + socket_disconnect, + socket_connection_set, + socket_do_iteration, + socket_live_messages_changed, + socket_get_socket_fd +}; + +/** + * Creates a new transport for the given socket file descriptor. The file + * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to + * make it so). This function is shared by various transports that + * boil down to a full duplex file descriptor. + * + * @param fd the file descriptor. + * @param server_guid non-#NULL if this transport is on the server side of a connection + * @param address the transport's address + * @returns the new transport, or #NULL if no memory. + */ +DBusTransport* +_dbus_transport_new_for_socket (int fd, + const DBusString *server_guid, + const DBusString *address) +{ + DBusTransportSocket *socket_transport; + + socket_transport = dbus_new0 (DBusTransportSocket, 1); + if (socket_transport == NULL) + return NULL; + + if (!_dbus_string_init (&socket_transport->encoded_outgoing)) + goto failed_0; + + if (!_dbus_string_init (&socket_transport->encoded_incoming)) + goto failed_1; + + socket_transport->write_watch = _dbus_watch_new (fd, + DBUS_WATCH_WRITABLE, + FALSE, + NULL, NULL, NULL); + if (socket_transport->write_watch == NULL) + goto failed_2; + + socket_transport->read_watch = _dbus_watch_new (fd, + DBUS_WATCH_READABLE, + FALSE, + NULL, NULL, NULL); + if (socket_transport->read_watch == NULL) + goto failed_3; + + if (!_dbus_transport_init_base (&socket_transport->base, + &socket_vtable, + server_guid, address)) + goto failed_4; + + socket_transport->fd = fd; + socket_transport->message_bytes_written = 0; + + /* These values should probably be tunable or something. */ + socket_transport->max_bytes_read_per_iteration = 2048; + socket_transport->max_bytes_written_per_iteration = 2048; + + return (DBusTransport*) socket_transport; + + failed_4: + _dbus_watch_unref (socket_transport->read_watch); + failed_3: + _dbus_watch_unref (socket_transport->write_watch); + failed_2: + _dbus_string_free (&socket_transport->encoded_incoming); + failed_1: + _dbus_string_free (&socket_transport->encoded_outgoing); + failed_0: + dbus_free (socket_transport); + return NULL; +} + +/** + * Creates a new transport for the given hostname and port. + * If host is NULL, it will default to localhost + * + * @param host the host to connect to + * @param port the port to connect to + * @param family the address family to connect to + * @param error location to store reason for failure. + * @returns a new transport, or #NULL on failure. + */ +DBusTransport* +_dbus_transport_new_for_tcp_socket (const char *host, + const char *port, + const char *family, + DBusError *error) +{ + int fd; + DBusTransport *transport; + DBusString address; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (host == NULL) + host = "localhost"; + + if (!_dbus_string_append (&address, "tcp:")) + goto error; + + if (!_dbus_string_append (&address, "host=") || + !_dbus_string_append (&address, host)) + goto error; + + if (!_dbus_string_append (&address, ",port=") || + !_dbus_string_append (&address, port)) + goto error; + + if (family != NULL && + (!_dbus_string_append (&address, "family=") || + !_dbus_string_append (&address, family))) + goto error; + + fd = _dbus_connect_tcp_socket (host, port, family, error); + if (fd < 0) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_string_free (&address); + return NULL; + } + + _dbus_fd_set_close_on_exec (fd); + + _dbus_verbose ("Successfully connected to tcp socket %s:%s\n", + host, port); + + transport = _dbus_transport_new_for_socket (fd, NULL, &address); + _dbus_string_free (&address); + if (transport == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_close_socket (fd, NULL); + fd = -1; + } + + return transport; + +error: + _dbus_string_free (&address); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; +} + +/** + * Opens a TCP socket transport. + * + * @param entry the address entry to try opening as a tcp transport. + * @param transport_p return location for the opened transport + * @param error error to be set + * @returns result of the attempt + */ +DBusTransportOpenResult +_dbus_transport_open_socket(DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error) +{ + const char *method; + + method = dbus_address_entry_get_method (entry); + _dbus_assert (method != NULL); + + if (strcmp (method, "tcp") == 0) + { + const char *host = dbus_address_entry_get_value (entry, "host"); + const char *port = dbus_address_entry_get_value (entry, "port"); + const char *family = dbus_address_entry_get_value (entry, "family"); + + if (port == NULL) + { + _dbus_set_bad_address (error, "tcp", "port", NULL); + return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; + } + + *transport_p = _dbus_transport_new_for_tcp_socket (host, port, family, error); + if (*transport_p == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return DBUS_TRANSPORT_OPEN_OK; + } + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return DBUS_TRANSPORT_OPEN_NOT_HANDLED; + } +} + +/** @} */ + diff --git a/dbus/dbus-transport-socket.h b/dbus/dbus-transport-socket.h new file mode 100644 index 00000000..eb833263 --- /dev/null +++ b/dbus/dbus-transport-socket.h @@ -0,0 +1,45 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-transport-socket.h Socket subclasses of DBusTransport + * + * Copyright (C) 2002, 2006 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_TRANSPORT_SOCKET_H +#define DBUS_TRANSPORT_SOCKET_H + +#include + +DBUS_BEGIN_DECLS + +DBusTransport* _dbus_transport_new_for_socket (int fd, + const DBusString *server_guid, + const DBusString *address); +DBusTransport* _dbus_transport_new_for_tcp_socket (const char *host, + const char *port, + const char *family, + DBusError *error); +DBusTransportOpenResult _dbus_transport_open_socket (DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error); + + + +DBUS_END_DECLS + +#endif /* DBUS_TRANSPORT_SOCKET_H */ diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c new file mode 100644 index 00000000..a4452aa1 --- /dev/null +++ b/dbus/dbus-transport-unix.c @@ -0,0 +1,181 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-transport-unix.c UNIX socket subclasses of DBusTransport + * + * Copyright (C) 2002, 2003, 2004 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-connection-internal.h" +#include "dbus-transport-unix.h" +#include "dbus-transport-socket.h" +#include "dbus-transport-protected.h" +#include "dbus-watch.h" +#include "dbus-sysdeps-unix.h" + +/** + * @defgroup DBusTransportUnix DBusTransport implementations for UNIX + * @ingroup DBusInternals + * @brief Implementation details of DBusTransport on UNIX + * + * @{ + */ + +/** + * Creates a new transport for the given Unix domain socket + * path. This creates a client-side of a transport. + * + * @todo once we add a way to escape paths in a dbus + * address, this function needs to do escaping. + * + * @param path the path to the domain socket. + * @param abstract #TRUE to use abstract socket namespace + * @param error address where an error can be returned. + * @returns a new transport, or #NULL on failure. + */ +DBusTransport* +_dbus_transport_new_for_domain_socket (const char *path, + dbus_bool_t abstract, + DBusError *error) +{ + int fd; + DBusTransport *transport; + DBusString address; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + fd = -1; + + if ((abstract && + !_dbus_string_append (&address, "unix:abstract=")) || + (!abstract && + !_dbus_string_append (&address, "unix:path=")) || + !_dbus_string_append (&address, path)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed_0; + } + + fd = _dbus_connect_unix_socket (path, abstract, error); + if (fd < 0) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto failed_0; + } + + _dbus_fd_set_close_on_exec (fd); + + _dbus_verbose ("Successfully connected to unix socket %s\n", + path); + + transport = _dbus_transport_new_for_socket (fd, NULL, &address); + if (transport == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + goto failed_1; + } + + _dbus_string_free (&address); + + return transport; + + failed_1: + _dbus_close_socket (fd, NULL); + failed_0: + _dbus_string_free (&address); + return NULL; +} + +/** + * Opens platform specific transport types. + * + * @param entry the address entry to try opening + * @param transport_p return location for the opened transport + * @param error error to be set + * @returns result of the attempt + */ +DBusTransportOpenResult +_dbus_transport_open_platform_specific (DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error) +{ + const char *method; + + method = dbus_address_entry_get_method (entry); + _dbus_assert (method != NULL); + + if (strcmp (method, "unix") == 0) + { + const char *path = dbus_address_entry_get_value (entry, "path"); + const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); + const char *abstract = dbus_address_entry_get_value (entry, "abstract"); + + if (tmpdir != NULL) + { + _dbus_set_bad_address (error, NULL, NULL, + "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on"); + return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; + } + + if (path == NULL && abstract == NULL) + { + _dbus_set_bad_address (error, "unix", + "path or abstract", + NULL); + return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; + } + + if (path != NULL && abstract != NULL) + { + _dbus_set_bad_address (error, NULL, NULL, + "can't specify both \"path\" and \"abstract\" options in an address"); + return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; + } + + if (path) + *transport_p = _dbus_transport_new_for_domain_socket (path, FALSE, + error); + else + *transport_p = _dbus_transport_new_for_domain_socket (abstract, TRUE, + error); + if (*transport_p == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return DBUS_TRANSPORT_OPEN_OK; + } + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return DBUS_TRANSPORT_OPEN_NOT_HANDLED; + } +} + +/** @} */ diff --git a/dbus/dbus-transport-unix.h b/dbus/dbus-transport-unix.h new file mode 100644 index 00000000..783a8313 --- /dev/null +++ b/dbus/dbus-transport-unix.h @@ -0,0 +1,37 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-transport-unix.h UNIX socket subclasses of DBusTransport + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_TRANSPORT_UNIX_H +#define DBUS_TRANSPORT_UNIX_H + +#include + +DBUS_BEGIN_DECLS + +DBusTransport* _dbus_transport_new_for_domain_socket (const char *path, + dbus_bool_t abstract, + DBusError *error); + + +DBUS_END_DECLS + +#endif /* DBUS_TRANSPORT_UNIX_H */ diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c new file mode 100644 index 00000000..53289ad0 --- /dev/null +++ b/dbus/dbus-transport.c @@ -0,0 +1,1411 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-transport.c DBusTransport object (internal to D-Bus implementation) + * + * Copyright (C) 2002, 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-transport-protected.h" +#include "dbus-transport-unix.h" +#include "dbus-transport-socket.h" +#include "dbus-connection-internal.h" +#include "dbus-watch.h" +#include "dbus-auth.h" +#include "dbus-address.h" +#include "dbus-credentials.h" +#ifdef DBUS_BUILD_TESTS +#include "dbus-server-debug-pipe.h" +#endif + +/** + * @defgroup DBusTransport DBusTransport object + * @ingroup DBusInternals + * @brief "Backend" for a DBusConnection. + * + * Types and functions related to DBusTransport. A transport is an + * abstraction that can send and receive data via various kinds of + * network connections or other IPC mechanisms. + * + * @{ + */ + +/** + * @typedef DBusTransport + * + * Opaque object representing a way message stream. + * DBusTransport abstracts various kinds of actual + * transport mechanism, such as different network protocols, + * or encryption schemes. + */ + +static void +live_messages_size_notify (DBusCounter *counter, + void *user_data) +{ + DBusTransport *transport = user_data; + + _dbus_transport_ref (transport); + +#if 0 + _dbus_verbose ("Counter value is now %d\n", + (int) _dbus_counter_get_value (counter)); +#endif + + /* disable or re-enable the read watch for the transport if + * required. + */ + if (transport->vtable->live_messages_changed) + (* transport->vtable->live_messages_changed) (transport); + + _dbus_transport_unref (transport); +} + +/** + * Initializes the base class members of DBusTransport. Chained up to + * by subclasses in their constructor. The server GUID is the + * globally unique ID for the server creating this connection + * and will be #NULL for the client side of a connection. The GUID + * is in hex format. + * + * @param transport the transport being created. + * @param vtable the subclass vtable. + * @param server_guid non-#NULL if this transport is on the server side of a connection + * @param address the address of the transport + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_transport_init_base (DBusTransport *transport, + const DBusTransportVTable *vtable, + const DBusString *server_guid, + const DBusString *address) +{ + DBusMessageLoader *loader; + DBusAuth *auth; + DBusCounter *counter; + char *address_copy; + DBusCredentials *creds; + + loader = _dbus_message_loader_new (); + if (loader == NULL) + return FALSE; + + if (server_guid) + auth = _dbus_auth_server_new (server_guid); + else + auth = _dbus_auth_client_new (); + if (auth == NULL) + { + _dbus_message_loader_unref (loader); + return FALSE; + } + + counter = _dbus_counter_new (); + if (counter == NULL) + { + _dbus_auth_unref (auth); + _dbus_message_loader_unref (loader); + return FALSE; + } + + creds = _dbus_credentials_new (); + if (creds == NULL) + { + _dbus_counter_unref (counter); + _dbus_auth_unref (auth); + _dbus_message_loader_unref (loader); + return FALSE; + } + + if (server_guid) + { + _dbus_assert (address == NULL); + address_copy = NULL; + } + else + { + _dbus_assert (address != NULL); + + if (!_dbus_string_copy_data (address, &address_copy)) + { + _dbus_credentials_unref (creds); + _dbus_counter_unref (counter); + _dbus_auth_unref (auth); + _dbus_message_loader_unref (loader); + return FALSE; + } + } + + transport->refcount = 1; + transport->vtable = vtable; + transport->loader = loader; + transport->auth = auth; + transport->live_messages_size = counter; + transport->authenticated = FALSE; + transport->disconnected = FALSE; + transport->is_server = (server_guid != NULL); + transport->send_credentials_pending = !transport->is_server; + transport->receive_credentials_pending = transport->is_server; + transport->address = address_copy; + + transport->unix_user_function = NULL; + transport->unix_user_data = NULL; + transport->free_unix_user_data = NULL; + + transport->windows_user_function = NULL; + transport->windows_user_data = NULL; + transport->free_windows_user_data = NULL; + + transport->expected_guid = NULL; + + /* Try to default to something that won't totally hose the system, + * but doesn't impose too much of a limitation. + */ + transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63; + + /* credentials read from socket if any */ + transport->credentials = creds; + + _dbus_counter_set_notify (transport->live_messages_size, + transport->max_live_messages_size, + live_messages_size_notify, + transport); + + if (transport->address) + _dbus_verbose ("Initialized transport on address %s\n", transport->address); + + return TRUE; +} + +/** + * Finalizes base class members of DBusTransport. + * Chained up to from subclass finalizers. + * + * @param transport the transport. + */ +void +_dbus_transport_finalize_base (DBusTransport *transport) +{ + if (!transport->disconnected) + _dbus_transport_disconnect (transport); + + if (transport->free_unix_user_data != NULL) + (* transport->free_unix_user_data) (transport->unix_user_data); + + if (transport->free_windows_user_data != NULL) + (* transport->free_windows_user_data) (transport->windows_user_data); + + _dbus_message_loader_unref (transport->loader); + _dbus_auth_unref (transport->auth); + _dbus_counter_set_notify (transport->live_messages_size, + 0, NULL, NULL); + _dbus_counter_unref (transport->live_messages_size); + dbus_free (transport->address); + dbus_free (transport->expected_guid); + if (transport->credentials) + _dbus_credentials_unref (transport->credentials); +} + + +/** + * Verifies if a given D-Bus address is a valid address + * by attempting to connect to it. If it is, returns the + * opened DBusTransport object. If it isn't, returns #NULL + * and sets @p error. + * + * @param error address where an error can be returned. + * @returns a new transport, or #NULL on failure. + */ +static DBusTransport* +check_address (const char *address, DBusError *error) +{ + DBusAddressEntry **entries; + DBusTransport *transport = NULL; + int len, i; + + _dbus_assert (address != NULL); + _dbus_assert (*address != '\0'); + + if (!dbus_parse_address (address, &entries, &len, error)) + return NULL; /* not a valid address */ + + for (i = 0; i < len; i++) + { + transport = _dbus_transport_open (entries[i], error); + if (transport != NULL) + break; + } + + dbus_address_entries_free (entries); + return transport; +} + +/** + * Creates a new transport for the "autostart" method. + * This creates a client-side of a transport. + * + * @param error address where an error can be returned. + * @returns a new transport, or #NULL on failure. + */ +static DBusTransport* +_dbus_transport_new_for_autolaunch (DBusError *error) +{ + DBusString address; + DBusTransport *result = NULL; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + if (!_dbus_string_init (&address)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (!_dbus_get_autolaunch_address (&address, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto out; + } + + result = check_address (_dbus_string_get_const_data (&address), error); + if (result == NULL) + _DBUS_ASSERT_ERROR_IS_SET (error); + else + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + out: + _dbus_string_free (&address); + return result; +} + +static DBusTransportOpenResult +_dbus_transport_open_autolaunch (DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error) +{ + const char *method; + + method = dbus_address_entry_get_method (entry); + _dbus_assert (method != NULL); + + if (strcmp (method, "autolaunch") == 0) + { + *transport_p = _dbus_transport_new_for_autolaunch (error); + + if (*transport_p == NULL) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return DBUS_TRANSPORT_OPEN_OK; + } + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + return DBUS_TRANSPORT_OPEN_NOT_HANDLED; + } +} + +static const struct { + DBusTransportOpenResult (* func) (DBusAddressEntry *entry, + DBusTransport **transport_p, + DBusError *error); +} open_funcs[] = { + { _dbus_transport_open_socket }, + { _dbus_transport_open_platform_specific }, + { _dbus_transport_open_autolaunch } +#ifdef DBUS_BUILD_TESTS + , { _dbus_transport_open_debug_pipe } +#endif +}; + +/** + * Try to open a new transport for the given address entry. (This + * opens a client-side-of-the-connection transport.) + * + * @param entry the address entry + * @param error location to store reason for failure. + * @returns new transport of #NULL on failure. + */ +DBusTransport* +_dbus_transport_open (DBusAddressEntry *entry, + DBusError *error) +{ + DBusTransport *transport; + const char *expected_guid_orig; + char *expected_guid; + int i; + DBusError tmp_error = DBUS_ERROR_INIT; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + transport = NULL; + expected_guid_orig = dbus_address_entry_get_value (entry, "guid"); + expected_guid = _dbus_strdup (expected_guid_orig); + + if (expected_guid_orig != NULL && expected_guid == NULL) + { + _DBUS_SET_OOM (error); + return NULL; + } + + for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i) + { + DBusTransportOpenResult result; + + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); + result = (* open_funcs[i].func) (entry, &transport, &tmp_error); + + switch (result) + { + case DBUS_TRANSPORT_OPEN_OK: + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); + goto out; + break; + case DBUS_TRANSPORT_OPEN_NOT_HANDLED: + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); + /* keep going through the loop of open funcs */ + break; + case DBUS_TRANSPORT_OPEN_BAD_ADDRESS: + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + goto out; + break; + case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT: + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + goto out; + break; + } + } + + out: + + if (transport == NULL) + { + if (!dbus_error_is_set (&tmp_error)) + _dbus_set_bad_address (&tmp_error, + NULL, NULL, + "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")"); + + _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); + dbus_move_error(&tmp_error, error); + dbus_free (expected_guid); + } + else + { + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); + + /* In the case of autostart the initial guid is NULL + * and the autostart transport recursively calls + * _dbus_open_transport wich returns a transport + * with a guid. That guid is the definitive one. + * + * FIXME: if more transports are added they may have + * an effect on the expected_guid semantics (i.e. + * expected_guid and transport->expected_guid may + * both have values). This is very unlikely though + * we should either throw asserts here for those + * corner cases or refactor the code so it is + * clearer on what is expected and what is not + */ + if(expected_guid) + transport->expected_guid = expected_guid; + } + + return transport; +} + +/** + * Increments the reference count for the transport. + * + * @param transport the transport. + * @returns the transport. + */ +DBusTransport * +_dbus_transport_ref (DBusTransport *transport) +{ + _dbus_assert (transport->refcount > 0); + + transport->refcount += 1; + + return transport; +} + +/** + * Decrements the reference count for the transport. + * Disconnects and finalizes the transport if + * the reference count reaches zero. + * + * @param transport the transport. + */ +void +_dbus_transport_unref (DBusTransport *transport) +{ + _dbus_assert (transport != NULL); + _dbus_assert (transport->refcount > 0); + + transport->refcount -= 1; + if (transport->refcount == 0) + { + _dbus_verbose ("%s: finalizing\n", _DBUS_FUNCTION_NAME); + + _dbus_assert (transport->vtable->finalize != NULL); + + (* transport->vtable->finalize) (transport); + } +} + +/** + * Closes our end of the connection to a remote application. Further + * attempts to use this transport will fail. Only the first call to + * _dbus_transport_disconnect() will have an effect. + * + * @param transport the transport. + * + */ +void +_dbus_transport_disconnect (DBusTransport *transport) +{ + _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME); + + _dbus_assert (transport->vtable->disconnect != NULL); + + if (transport->disconnected) + return; + + (* transport->vtable->disconnect) (transport); + + transport->disconnected = TRUE; + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); +} + +/** + * Returns #TRUE if the transport has not been disconnected. + * Disconnection can result from _dbus_transport_disconnect() + * or because the server drops its end of the connection. + * + * @param transport the transport. + * @returns whether we're connected + */ +dbus_bool_t +_dbus_transport_get_is_connected (DBusTransport *transport) +{ + return !transport->disconnected; +} + +static dbus_bool_t +auth_via_unix_user_function (DBusTransport *transport) +{ + DBusCredentials *auth_identity; + dbus_bool_t allow; + DBusConnection *connection; + DBusAllowUnixUserFunction unix_user_function; + void *unix_user_data; + dbus_uid_t uid; + + /* Dropping the lock here probably isn't that safe. */ + + auth_identity = _dbus_auth_get_identity (transport->auth); + _dbus_assert (auth_identity != NULL); + + connection = transport->connection; + unix_user_function = transport->unix_user_function; + unix_user_data = transport->unix_user_data; + uid = _dbus_credentials_get_unix_uid (auth_identity); + + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (connection); + + allow = (* unix_user_function) (connection, + uid, + unix_user_data); + + _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME); + _dbus_connection_lock (connection); + + if (allow) + { + _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid); + } + else + { + _dbus_verbose ("Client UID "DBUS_UID_FORMAT + " was rejected, disconnecting\n", + _dbus_credentials_get_unix_uid (auth_identity)); + _dbus_transport_disconnect (transport); + } + + return allow; +} + +static dbus_bool_t +auth_via_windows_user_function (DBusTransport *transport) +{ + DBusCredentials *auth_identity; + dbus_bool_t allow; + DBusConnection *connection; + DBusAllowWindowsUserFunction windows_user_function; + void *windows_user_data; + char *windows_sid; + + /* Dropping the lock here probably isn't that safe. */ + + auth_identity = _dbus_auth_get_identity (transport->auth); + _dbus_assert (auth_identity != NULL); + + connection = transport->connection; + windows_user_function = transport->windows_user_function; + windows_user_data = transport->unix_user_data; + windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity)); + + if (windows_sid == NULL) + { + /* OOM */ + return FALSE; + } + + _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME); + _dbus_connection_unlock (connection); + + allow = (* windows_user_function) (connection, + windows_sid, + windows_user_data); + + _dbus_verbose ("lock %s post windows user function\n", _DBUS_FUNCTION_NAME); + _dbus_connection_lock (connection); + + if (allow) + { + _dbus_verbose ("Client SID '%s' authorized\n", windows_sid); + } + else + { + _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n", + _dbus_credentials_get_windows_sid (auth_identity)); + _dbus_transport_disconnect (transport); + } + + return allow; +} + +static dbus_bool_t +auth_via_default_rules (DBusTransport *transport) +{ + DBusCredentials *auth_identity; + DBusCredentials *our_identity; + dbus_bool_t allow; + + auth_identity = _dbus_auth_get_identity (transport->auth); + _dbus_assert (auth_identity != NULL); + + /* By default, connection is allowed if the client is 1) root or 2) + * has the same UID as us or 3) anonymous is allowed. + */ + + our_identity = _dbus_credentials_new_from_current_process (); + if (our_identity == NULL) + { + /* OOM */ + return FALSE; + } + + if (transport->allow_anonymous || + _dbus_credentials_get_unix_uid (auth_identity) == 0 || + _dbus_credentials_same_user (our_identity, + auth_identity)) + { + if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID)) + _dbus_verbose ("Client authorized as SID '%s'" + "matching our SID '%s'\n", + _dbus_credentials_get_windows_sid(auth_identity), + _dbus_credentials_get_windows_sid(our_identity)); + else + _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT + " matching our UID "DBUS_UID_FORMAT"\n", + _dbus_credentials_get_unix_uid(auth_identity), + _dbus_credentials_get_unix_uid(our_identity)); + /* We have authenticated! */ + allow = TRUE; + } + else + { + if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID)) + _dbus_verbose ("Client authorized as SID '%s'" + " but our SID is '%s', disconnecting\n", + _dbus_credentials_get_windows_sid(auth_identity), + _dbus_credentials_get_windows_sid(our_identity)); + else + _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT + " but our UID is "DBUS_UID_FORMAT", disconnecting\n", + _dbus_credentials_get_unix_uid(auth_identity), + _dbus_credentials_get_unix_uid(our_identity)); + _dbus_transport_disconnect (transport); + allow = FALSE; + } + + _dbus_credentials_unref (our_identity); + + return allow; +} + + +/** + * Returns #TRUE if we have been authenticated. Will return #TRUE + * even if the transport is disconnected. + * + * @todo we drop connection->mutex when calling the unix_user_function, + * and windows_user_function, which may not be safe really. + * + * @param transport the transport + * @returns whether we're authenticated + */ +dbus_bool_t +_dbus_transport_get_is_authenticated (DBusTransport *transport) +{ + if (transport->authenticated) + return TRUE; + else + { + dbus_bool_t maybe_authenticated; + + if (transport->disconnected) + return FALSE; + + /* paranoia ref since we call user callbacks sometimes */ + _dbus_connection_ref_unlocked (transport->connection); + + maybe_authenticated = + (!(transport->send_credentials_pending || + transport->receive_credentials_pending)); + + if (maybe_authenticated) + { + switch (_dbus_auth_do_work (transport->auth)) + { + case DBUS_AUTH_STATE_AUTHENTICATED: + /* leave as maybe_authenticated */ + break; + default: + maybe_authenticated = FALSE; + } + } + + /* If we're the client, verify the GUID + */ + if (maybe_authenticated && !transport->is_server) + { + const char *server_guid; + + server_guid = _dbus_auth_get_guid_from_server (transport->auth); + _dbus_assert (server_guid != NULL); + + if (transport->expected_guid && + strcmp (transport->expected_guid, server_guid) != 0) + { + _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n", + transport->expected_guid, server_guid); + _dbus_transport_disconnect (transport); + _dbus_connection_unref_unlocked (transport->connection); + return FALSE; + } + + if (transport->expected_guid == NULL) + { + transport->expected_guid = _dbus_strdup (server_guid); + + if (transport->expected_guid == NULL) + { + _dbus_verbose ("No memory to complete auth in %s\n", _DBUS_FUNCTION_NAME); + return FALSE; + } + } + } + + /* If we're the server, see if we want to allow this identity to proceed. + */ + if (maybe_authenticated && transport->is_server) + { + dbus_bool_t allow; + DBusCredentials *auth_identity; + + auth_identity = _dbus_auth_get_identity (transport->auth); + _dbus_assert (auth_identity != NULL); + + /* If we have an auth'd user and a user function, delegate + * deciding whether auth credentials are good enough to the + * app; otherwise, use our default decision process. + */ + if (transport->unix_user_function != NULL && + _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID)) + { + allow = auth_via_unix_user_function (transport); + } + else if (transport->windows_user_function != NULL && + _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID)) + { + allow = auth_via_windows_user_function (transport); + } + else + { + allow = auth_via_default_rules (transport); + } + + if (!allow) + maybe_authenticated = FALSE; + } + + transport->authenticated = maybe_authenticated; + + _dbus_connection_unref_unlocked (transport->connection); + return maybe_authenticated; + } +} + +/** + * See dbus_connection_get_is_anonymous(). + * + * @param transport the transport + * @returns #TRUE if not authenticated or authenticated as anonymous + */ +dbus_bool_t +_dbus_transport_get_is_anonymous (DBusTransport *transport) +{ + DBusCredentials *auth_identity; + + if (!transport->authenticated) + return TRUE; + + auth_identity = _dbus_auth_get_identity (transport->auth); + + if (_dbus_credentials_are_anonymous (auth_identity)) + return TRUE; + else + return FALSE; +} + +/** + * Gets the address of a transport. It will be + * #NULL for a server-side transport. + * + * @param transport the transport + * @returns transport's address + */ +const char* +_dbus_transport_get_address (DBusTransport *transport) +{ + return transport->address; +} + +/** + * Gets the id of the server we are connected to (see + * dbus_server_get_id()). Only works on client side. + * + * @param transport the transport + * @returns transport's server's id or #NULL if we are the server side + */ +const char* +_dbus_transport_get_server_id (DBusTransport *transport) +{ + if (transport->is_server) + return NULL; + else + return transport->expected_guid; +} + +/** + * Handles a watch by reading data, writing data, or disconnecting + * the transport, as appropriate for the given condition. + * + * @param transport the transport. + * @param watch the watch. + * @param condition the current state of the watched file descriptor. + * @returns #FALSE if not enough memory to fully handle the watch + */ +dbus_bool_t +_dbus_transport_handle_watch (DBusTransport *transport, + DBusWatch *watch, + unsigned int condition) +{ + dbus_bool_t retval; + + _dbus_assert (transport->vtable->handle_watch != NULL); + + if (transport->disconnected) + return TRUE; + + if (dbus_watch_get_socket (watch) < 0) + { + _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n"); + return TRUE; + } + + _dbus_watch_sanitize_condition (watch, &condition); + + _dbus_transport_ref (transport); + _dbus_watch_ref (watch); + retval = (* transport->vtable->handle_watch) (transport, watch, condition); + _dbus_watch_unref (watch); + _dbus_transport_unref (transport); + + return retval; +} + +/** + * Sets the connection using this transport. Allows the transport + * to add watches to the connection, queue incoming messages, + * and pull outgoing messages. + * + * @param transport the transport. + * @param connection the connection. + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_transport_set_connection (DBusTransport *transport, + DBusConnection *connection) +{ + _dbus_assert (transport->vtable->connection_set != NULL); + _dbus_assert (transport->connection == NULL); + + transport->connection = connection; + + _dbus_transport_ref (transport); + if (!(* transport->vtable->connection_set) (transport)) + transport->connection = NULL; + _dbus_transport_unref (transport); + + return transport->connection != NULL; +} + +/** + * Get the socket file descriptor, if any. + * + * @param transport the transport + * @param fd_p pointer to fill in with the descriptor + * @returns #TRUE if a descriptor was available + */ +dbus_bool_t +_dbus_transport_get_socket_fd (DBusTransport *transport, + int *fd_p) +{ + dbus_bool_t retval; + + if (transport->vtable->get_socket_fd == NULL) + return FALSE; + + if (transport->disconnected) + return FALSE; + + _dbus_transport_ref (transport); + + retval = (* transport->vtable->get_socket_fd) (transport, + fd_p); + + _dbus_transport_unref (transport); + + return retval; +} + +/** + * Performs a single poll()/select() on the transport's file + * descriptors and then reads/writes data as appropriate, + * queueing incoming messages and sending outgoing messages. + * This is the backend for _dbus_connection_do_iteration(). + * See _dbus_connection_do_iteration() for full details. + * + * @param transport the transport. + * @param flags indicates whether to read or write, and whether to block. + * @param timeout_milliseconds if blocking, timeout or -1 for no timeout. + */ +void +_dbus_transport_do_iteration (DBusTransport *transport, + unsigned int flags, + int timeout_milliseconds) +{ + _dbus_assert (transport->vtable->do_iteration != NULL); + + _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n", + flags, timeout_milliseconds, !transport->disconnected); + + if ((flags & (DBUS_ITERATION_DO_WRITING | + DBUS_ITERATION_DO_READING)) == 0) + return; /* Nothing to do */ + + if (transport->disconnected) + return; + + _dbus_transport_ref (transport); + (* transport->vtable->do_iteration) (transport, flags, + timeout_milliseconds); + _dbus_transport_unref (transport); + + _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); +} + +static dbus_bool_t +recover_unused_bytes (DBusTransport *transport) +{ + if (_dbus_auth_needs_decoding (transport->auth)) + { + DBusString plaintext; + const DBusString *encoded; + DBusString *buffer; + int orig_len; + + if (!_dbus_string_init (&plaintext)) + goto nomem; + + _dbus_auth_get_unused_bytes (transport->auth, + &encoded); + + if (!_dbus_auth_decode_data (transport->auth, + encoded, &plaintext)) + { + _dbus_string_free (&plaintext); + goto nomem; + } + + _dbus_message_loader_get_buffer (transport->loader, + &buffer); + + orig_len = _dbus_string_get_length (buffer); + + if (!_dbus_string_move (&plaintext, 0, buffer, + orig_len)) + { + _dbus_string_free (&plaintext); + goto nomem; + } + + _dbus_verbose (" %d unused bytes sent to message loader\n", + _dbus_string_get_length (buffer) - + orig_len); + + _dbus_message_loader_return_buffer (transport->loader, + buffer, + _dbus_string_get_length (buffer) - + orig_len); + + _dbus_auth_delete_unused_bytes (transport->auth); + + _dbus_string_free (&plaintext); + } + else + { + const DBusString *bytes; + DBusString *buffer; + int orig_len; + dbus_bool_t succeeded; + + _dbus_message_loader_get_buffer (transport->loader, + &buffer); + + orig_len = _dbus_string_get_length (buffer); + + _dbus_auth_get_unused_bytes (transport->auth, + &bytes); + + succeeded = TRUE; + if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer))) + succeeded = FALSE; + + _dbus_verbose (" %d unused bytes sent to message loader\n", + _dbus_string_get_length (buffer) - + orig_len); + + _dbus_message_loader_return_buffer (transport->loader, + buffer, + _dbus_string_get_length (buffer) - + orig_len); + + if (succeeded) + _dbus_auth_delete_unused_bytes (transport->auth); + else + goto nomem; + } + + return TRUE; + + nomem: + _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n"); + return FALSE; +} + +/** + * Reports our current dispatch status (whether there's buffered + * data to be queued as messages, or not, or we need memory). + * + * @param transport the transport + * @returns current status + */ +DBusDispatchStatus +_dbus_transport_get_dispatch_status (DBusTransport *transport) +{ + if (_dbus_counter_get_value (transport->live_messages_size) >= transport->max_live_messages_size) + return DBUS_DISPATCH_COMPLETE; /* complete for now */ + + if (!_dbus_transport_get_is_authenticated (transport)) + { + if (_dbus_auth_do_work (transport->auth) == + DBUS_AUTH_STATE_WAITING_FOR_MEMORY) + return DBUS_DISPATCH_NEED_MEMORY; + else if (!_dbus_transport_get_is_authenticated (transport)) + return DBUS_DISPATCH_COMPLETE; + } + + if (!transport->unused_bytes_recovered && + !recover_unused_bytes (transport)) + return DBUS_DISPATCH_NEED_MEMORY; + + transport->unused_bytes_recovered = TRUE; + + if (!_dbus_message_loader_queue_messages (transport->loader)) + return DBUS_DISPATCH_NEED_MEMORY; + + if (_dbus_message_loader_peek_message (transport->loader) != NULL) + return DBUS_DISPATCH_DATA_REMAINS; + else + return DBUS_DISPATCH_COMPLETE; +} + +/** + * Processes data we've read while handling a watch, potentially + * converting some of it to messages and queueing those messages on + * the connection. + * + * @param transport the transport + * @returns #TRUE if we had enough memory to queue all messages + */ +dbus_bool_t +_dbus_transport_queue_messages (DBusTransport *transport) +{ + DBusDispatchStatus status; + +#if 0 + _dbus_verbose ("_dbus_transport_queue_messages()\n"); +#endif + + /* Queue any messages */ + while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS) + { + DBusMessage *message; + DBusList *link; + + link = _dbus_message_loader_pop_message_link (transport->loader); + _dbus_assert (link != NULL); + + message = link->data; + + _dbus_verbose ("queueing received message %p\n", message); + + if (!_dbus_message_add_size_counter (message, transport->live_messages_size)) + { + _dbus_message_loader_putback_message_link (transport->loader, + link); + status = DBUS_DISPATCH_NEED_MEMORY; + break; + } + else + { + /* pass ownership of link and message ref to connection */ + _dbus_connection_queue_received_message_link (transport->connection, + link); + } + } + + if (_dbus_message_loader_get_is_corrupted (transport->loader)) + { + _dbus_verbose ("Corrupted message stream, disconnecting\n"); + _dbus_transport_disconnect (transport); + } + + return status != DBUS_DISPATCH_NEED_MEMORY; +} + +/** + * See dbus_connection_set_max_message_size(). + * + * @param transport the transport + * @param size the max size of a single message + */ +void +_dbus_transport_set_max_message_size (DBusTransport *transport, + long size) +{ + _dbus_message_loader_set_max_message_size (transport->loader, size); +} + +/** + * See dbus_connection_get_max_message_size(). + * + * @param transport the transport + * @returns max message size + */ +long +_dbus_transport_get_max_message_size (DBusTransport *transport) +{ + return _dbus_message_loader_get_max_message_size (transport->loader); +} + +/** + * See dbus_connection_set_max_received_size(). + * + * @param transport the transport + * @param size the max size of all incoming messages + */ +void +_dbus_transport_set_max_received_size (DBusTransport *transport, + long size) +{ + transport->max_live_messages_size = size; + _dbus_counter_set_notify (transport->live_messages_size, + transport->max_live_messages_size, + live_messages_size_notify, + transport); +} + + +/** + * See dbus_connection_get_max_received_size(). + * + * @param transport the transport + * @returns max bytes for all live messages + */ +long +_dbus_transport_get_max_received_size (DBusTransport *transport) +{ + return transport->max_live_messages_size; +} + +/** + * See dbus_connection_get_unix_user(). + * + * @param transport the transport + * @param uid return location for the user ID + * @returns #TRUE if uid is filled in with a valid user ID + */ +dbus_bool_t +_dbus_transport_get_unix_user (DBusTransport *transport, + unsigned long *uid) +{ + DBusCredentials *auth_identity; + + *uid = _DBUS_INT32_MAX; /* better than some root or system user in + * case of bugs in the caller. Caller should + * never use this value on purpose, however. + */ + + if (!transport->authenticated) + return FALSE; + + auth_identity = _dbus_auth_get_identity (transport->auth); + + if (_dbus_credentials_include (auth_identity, + DBUS_CREDENTIAL_UNIX_USER_ID)) + { + *uid = _dbus_credentials_get_unix_uid (auth_identity); + return TRUE; + } + else + return FALSE; +} + +/** + * See dbus_connection_get_unix_process_id(). + * + * @param transport the transport + * @param pid return location for the process ID + * @returns #TRUE if uid is filled in with a valid process ID + */ +dbus_bool_t +_dbus_transport_get_unix_process_id (DBusTransport *transport, + unsigned long *pid) +{ + DBusCredentials *auth_identity; + + *pid = DBUS_PID_UNSET; /* Caller should never use this value on purpose, + * but we set it to a safe number, INT_MAX, + * just to root out possible bugs in bad callers. + */ + + if (!transport->authenticated) + return FALSE; + + auth_identity = _dbus_auth_get_identity (transport->auth); + + if (_dbus_credentials_include (auth_identity, + DBUS_CREDENTIAL_UNIX_PROCESS_ID)) + { + *pid = _dbus_credentials_get_unix_pid (auth_identity); + return TRUE; + } + else + return FALSE; +} + +/** + * See dbus_connection_get_adt_audit_session_data(). + * + * @param transport the transport + * @param data return location for the ADT audit data + * @param data_size return length of audit data + * @returns #TRUE if audit data is filled in with a valid ucred + */ +dbus_bool_t +_dbus_transport_get_adt_audit_session_data (DBusTransport *transport, + void **data, + int *data_size) +{ + DBusCredentials *auth_identity; + + *data = NULL; + *data_size = 0; + + if (!transport->authenticated) + return FALSE; + + auth_identity = _dbus_auth_get_identity (transport->auth); + + if (_dbus_credentials_include (auth_identity, + DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID)) + { + *data = (void *) _dbus_credentials_get_adt_audit_data (auth_identity); + *data_size = _dbus_credentials_get_adt_audit_data_size (auth_identity); + return TRUE; + } + else + return FALSE; +} + +/** + * See dbus_connection_set_unix_user_function(). + * + * @param transport the transport + * @param function the predicate + * @param data data to pass to the predicate + * @param free_data_function function to free the data + * @param old_data the old user data to be freed + * @param old_free_data_function old free data function to free it with + */ +void +_dbus_transport_set_unix_user_function (DBusTransport *transport, + DBusAllowUnixUserFunction function, + void *data, + DBusFreeFunction free_data_function, + void **old_data, + DBusFreeFunction *old_free_data_function) +{ + *old_data = transport->unix_user_data; + *old_free_data_function = transport->free_unix_user_data; + + transport->unix_user_function = function; + transport->unix_user_data = data; + transport->free_unix_user_data = free_data_function; +} + +/** + * See dbus_connection_get_windows_user(). + * + * @param transport the transport + * @param windows_sid_p return location for the user ID + * @returns #TRUE if user is available; the returned value may still be #NULL if no memory to copy it + */ +dbus_bool_t +_dbus_transport_get_windows_user (DBusTransport *transport, + char **windows_sid_p) +{ + DBusCredentials *auth_identity; + + *windows_sid_p = NULL; + + if (!transport->authenticated) + return FALSE; + + auth_identity = _dbus_auth_get_identity (transport->auth); + + if (_dbus_credentials_include (auth_identity, + DBUS_CREDENTIAL_WINDOWS_SID)) + { + /* If no memory, we are supposed to return TRUE and set NULL */ + *windows_sid_p = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity)); + + return TRUE; + } + else + return FALSE; +} + +/** + * See dbus_connection_set_windows_user_function(). + * + * @param transport the transport + * @param function the predicate + * @param data data to pass to the predicate + * @param free_data_function function to free the data + * @param old_data the old user data to be freed + * @param old_free_data_function old free data function to free it with + */ + +void +_dbus_transport_set_windows_user_function (DBusTransport *transport, + DBusAllowWindowsUserFunction function, + void *data, + DBusFreeFunction free_data_function, + void **old_data, + DBusFreeFunction *old_free_data_function) +{ + *old_data = transport->windows_user_data; + *old_free_data_function = transport->free_windows_user_data; + + transport->windows_user_function = function; + transport->windows_user_data = data; + transport->free_windows_user_data = free_data_function; +} + +/** + * Sets the SASL authentication mechanisms supported by this transport. + * + * @param transport the transport + * @param mechanisms the #NULL-terminated array of mechanisms + * + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_transport_set_auth_mechanisms (DBusTransport *transport, + const char **mechanisms) +{ + return _dbus_auth_set_mechanisms (transport->auth, mechanisms); +} + +/** + * See dbus_connection_set_allow_anonymous() + * + * @param transport the transport + * @param value #TRUE to allow anonymous connection + */ +void +_dbus_transport_set_allow_anonymous (DBusTransport *transport, + dbus_bool_t value) +{ + transport->allow_anonymous = value != FALSE; +} + +/** @} */ diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h new file mode 100644 index 00000000..f2915f33 --- /dev/null +++ b/dbus/dbus-transport.h @@ -0,0 +1,92 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-transport.h DBusTransport object (internal to D-BUS implementation) + * + * Copyright (C) 2002, 2004 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_TRANSPORT_H +#define DBUS_TRANSPORT_H + +#include +#include +#include +#include + +DBUS_BEGIN_DECLS + +typedef struct DBusTransport DBusTransport; + +DBusTransport* _dbus_transport_open (DBusAddressEntry *entry, + DBusError *error); +DBusTransport* _dbus_transport_ref (DBusTransport *transport); +void _dbus_transport_unref (DBusTransport *transport); +void _dbus_transport_disconnect (DBusTransport *transport); +dbus_bool_t _dbus_transport_get_is_connected (DBusTransport *transport); +dbus_bool_t _dbus_transport_get_is_authenticated (DBusTransport *transport); +dbus_bool_t _dbus_transport_get_is_anonymous (DBusTransport *transport); +const char* _dbus_transport_get_address (DBusTransport *transport); +const char* _dbus_transport_get_server_id (DBusTransport *transport); +dbus_bool_t _dbus_transport_handle_watch (DBusTransport *transport, + DBusWatch *watch, + unsigned int condition); +dbus_bool_t _dbus_transport_set_connection (DBusTransport *transport, + DBusConnection *connection); +void _dbus_transport_do_iteration (DBusTransport *transport, + unsigned int flags, + int timeout_milliseconds); +DBusDispatchStatus _dbus_transport_get_dispatch_status (DBusTransport *transport); +dbus_bool_t _dbus_transport_queue_messages (DBusTransport *transport); +void _dbus_transport_set_max_message_size (DBusTransport *transport, + long size); +long _dbus_transport_get_max_message_size (DBusTransport *transport); +void _dbus_transport_set_max_received_size (DBusTransport *transport, + long size); +long _dbus_transport_get_max_received_size (DBusTransport *transport); +dbus_bool_t _dbus_transport_get_socket_fd (DBusTransport *transport, + int *fd_p); +dbus_bool_t _dbus_transport_get_unix_user (DBusTransport *transport, + unsigned long *uid); +dbus_bool_t _dbus_transport_get_unix_process_id (DBusTransport *transport, + unsigned long *pid); +dbus_bool_t _dbus_transport_get_adt_audit_session_data (DBusTransport *transport, + void **data, + int *data_size); +void _dbus_transport_set_unix_user_function (DBusTransport *transport, + DBusAllowUnixUserFunction function, + void *data, + DBusFreeFunction free_data_function, + void **old_data, + DBusFreeFunction *old_free_data_function); +dbus_bool_t _dbus_transport_get_windows_user (DBusTransport *transport, + char **windows_sid_p); +void _dbus_transport_set_windows_user_function (DBusTransport *transport, + DBusAllowWindowsUserFunction function, + void *data, + DBusFreeFunction free_data_function, + void **old_data, + DBusFreeFunction *old_free_data_function); +dbus_bool_t _dbus_transport_set_auth_mechanisms (DBusTransport *transport, + const char **mechanisms); +void _dbus_transport_set_allow_anonymous (DBusTransport *transport, + dbus_bool_t value); + + +DBUS_END_DECLS + +#endif /* DBUS_TRANSPORT_H */ diff --git a/dbus/dbus-types.h b/dbus/dbus-types.h new file mode 100644 index 00000000..54f348f3 --- /dev/null +++ b/dbus/dbus-types.h @@ -0,0 +1,139 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-types.h types such as dbus_bool_t + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION) +#error "Only can be included directly, this file may disappear or change contents." +#endif + +#ifndef DBUS_TYPES_H +#define DBUS_TYPES_H + +#include +#include + +typedef dbus_uint32_t dbus_unichar_t; +/* boolean size must be fixed at 4 bytes due to wire protocol! */ +typedef dbus_uint32_t dbus_bool_t; + +/* Normally docs are in .c files, but there isn't a .c file for this. */ +/** + * @defgroup DBusTypes Basic types + * @ingroup DBus + * @brief dbus_bool_t, dbus_int32_t, etc. + * + * Typedefs for common primitive types. + * + * @{ + */ + +/** + * @typedef dbus_bool_t + * + * A boolean, valid values are #TRUE and #FALSE. + */ + +/** + * @typedef dbus_uint32_t + * + * A 32-bit unsigned integer on all platforms. + */ + +/** + * @typedef dbus_int32_t + * + * A 32-bit signed integer on all platforms. + */ + +/** + * @typedef dbus_uint16_t + * + * A 16-bit unsigned integer on all platforms. + */ + +/** + * @typedef dbus_int16_t + * + * A 16-bit signed integer on all platforms. + */ + + +/** + * @typedef dbus_uint64_t + * + * A 64-bit unsigned integer on all platforms that support it. + * If supported, #DBUS_HAVE_INT64 will be defined. + * + * C99 requires a 64-bit type and most likely all interesting + * compilers support one. GLib for example flat-out requires + * a 64-bit type. + * + * You probably want to just assume #DBUS_HAVE_INT64 is always defined. + */ + +/** + * @typedef dbus_int64_t + * + * A 64-bit signed integer on all platforms that support it. + * If supported, #DBUS_HAVE_INT64 will be defined. + * + * C99 requires a 64-bit type and most likely all interesting + * compilers support one. GLib for example flat-out requires + * a 64-bit type. + * + * You probably want to just assume #DBUS_HAVE_INT64 is always defined. + */ + +/** + * @def DBUS_HAVE_INT64 + * + * Defined if 64-bit integers are available. Will be defined + * on any platform you care about, unless you care about + * some truly ancient UNIX, or some bizarre embedded platform. + * + * C99 requires a 64-bit type and most likely all interesting + * compilers support one. GLib for example flat-out requires + * a 64-bit type. + * + * You should feel comfortable ignoring this macro and just using + * int64 unconditionally. + * + */ + +/** + * @def DBUS_INT64_CONSTANT + * + * Declare a 64-bit signed integer constant. The macro + * adds the necessary "LL" or whatever after the integer, + * giving a literal such as "325145246765LL" + */ + +/** + * @def DBUS_UINT64_CONSTANT + * + * Declare a 64-bit unsigned integer constant. The macro + * adds the necessary "ULL" or whatever after the integer, + * giving a literal such as "325145246765ULL" + */ + +/** @} */ + +#endif /* DBUS_TYPES_H */ diff --git a/dbus/dbus-userdb-util.c b/dbus/dbus-userdb-util.c new file mode 100644 index 00000000..f75d1bc0 --- /dev/null +++ b/dbus/dbus-userdb-util.c @@ -0,0 +1,442 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-userdb-util.c Would be in dbus-userdb.c, but not used in libdbus + * + * Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#define DBUS_USERDB_INCLUDES_PRIVATE 1 +#include "dbus-userdb.h" +#include "dbus-test.h" +#include "dbus-internals.h" +#include "dbus-protocol.h" +#include + +/** + * @addtogroup DBusInternalsUtils + * @{ + */ + +/** + * Checks to see if the UID sent in is the console user + * + * @param uid UID of person to check + * @param error return location for errors + * @returns #TRUE if the UID is the same as the console user and there are no errors + */ +dbus_bool_t +_dbus_is_console_user (dbus_uid_t uid, + DBusError *error) +{ + + DBusUserDatabase *db; + const DBusUserInfo *info; + dbus_bool_t result = FALSE; + +#ifdef HAVE_CONSOLE_OWNER_FILE + + DBusString f; + DBusStat st; + + if (!_dbus_string_init (&f)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_string_append(&f, DBUS_CONSOLE_OWNER_FILE)) + { + _dbus_string_free(&f); + _DBUS_SET_OOM (error); + return FALSE; + } + + if (_dbus_stat(&f, &st, NULL) && (st.uid == uid)) + { + _dbus_string_free(&f); + return TRUE; + } + + _dbus_string_free(&f); + +#endif /* HAVE_CONSOLE_OWNER_FILE */ + + _dbus_user_database_lock_system (); + + db = _dbus_user_database_get_system (); + if (db == NULL) + { + dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get system database."); + _dbus_user_database_unlock_system (); + return FALSE; + } + + /* TPTD: this should be cache-safe, we've locked the DB and + _dbus_user_at_console doesn't pass it on. */ + info = _dbus_user_database_lookup (db, uid, NULL, error); + + if (info == NULL) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + result = _dbus_user_at_console (info->username, error); + + _dbus_user_database_unlock_system (); + + return result; +} + +/** + * Gets user ID given username + * + * @param username the username + * @param uid return location for UID + * @returns #TRUE if username existed and we got the UID + */ +dbus_bool_t +_dbus_get_user_id (const DBusString *username, + dbus_uid_t *uid) +{ + return _dbus_get_user_id_and_primary_group (username, uid, NULL); +} + +/** + * Gets group ID given groupname + * + * @param groupname the groupname + * @param gid return location for GID + * @returns #TRUE if group name existed and we got the GID + */ +dbus_bool_t +_dbus_get_group_id (const DBusString *groupname, + dbus_gid_t *gid) +{ + DBusUserDatabase *db; + const DBusGroupInfo *info; + _dbus_user_database_lock_system (); + + db = _dbus_user_database_get_system (); + if (db == NULL) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + if (!_dbus_user_database_get_groupname (db, groupname, + &info, NULL)) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + *gid = info->gid; + + _dbus_user_database_unlock_system (); + return TRUE; +} + +/** + * Gets user ID and primary group given username + * + * @param username the username + * @param uid_p return location for UID + * @param gid_p return location for GID + * @returns #TRUE if username existed and we got the UID and GID + */ +dbus_bool_t +_dbus_get_user_id_and_primary_group (const DBusString *username, + dbus_uid_t *uid_p, + dbus_gid_t *gid_p) +{ + DBusUserDatabase *db; + const DBusUserInfo *info; + _dbus_user_database_lock_system (); + + db = _dbus_user_database_get_system (); + if (db == NULL) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + if (!_dbus_user_database_get_username (db, username, + &info, NULL)) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + if (uid_p) + *uid_p = info->uid; + if (gid_p) + *gid_p = info->primary_gid; + + _dbus_user_database_unlock_system (); + return TRUE; +} + +/** + * Looks up a gid or group name in the user database. Only one of + * name or GID can be provided. There are wrapper functions for this + * that are better to use, this one does no locking or anything on the + * database and otherwise sort of sucks. + * + * @param db the database + * @param gid the group ID or #DBUS_GID_UNSET + * @param groupname group name or #NULL + * @param error error to fill in + * @returns the entry in the database + */ +DBusGroupInfo* +_dbus_user_database_lookup_group (DBusUserDatabase *db, + dbus_gid_t gid, + const DBusString *groupname, + DBusError *error) +{ + DBusGroupInfo *info; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + /* See if the group is really a number */ + if (gid == DBUS_UID_UNSET) + { + unsigned long n; + + if (_dbus_is_a_number (groupname, &n)) + gid = n; + } + +#ifdef DBUS_ENABLE_USERDB_CACHE + if (gid != DBUS_GID_UNSET) + info = _dbus_hash_table_lookup_ulong (db->groups, gid); + else + info = _dbus_hash_table_lookup_string (db->groups_by_name, + _dbus_string_get_const_data (groupname)); + if (info) + { + _dbus_verbose ("Using cache for GID "DBUS_GID_FORMAT" information\n", + info->gid); + return info; + } + else +#else + if (1) +#endif + { + if (gid != DBUS_GID_UNSET) + _dbus_verbose ("No cache for GID "DBUS_GID_FORMAT"\n", + gid); + else + _dbus_verbose ("No cache for groupname \"%s\"\n", + _dbus_string_get_const_data (groupname)); + + info = dbus_new0 (DBusGroupInfo, 1); + if (info == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (gid != DBUS_GID_UNSET) + { + if (!_dbus_group_info_fill_gid (info, gid, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_group_info_free_allocated (info); + return NULL; + } + } + else + { + if (!_dbus_group_info_fill (info, groupname, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_group_info_free_allocated (info); + return NULL; + } + } + + /* don't use these past here */ + gid = DBUS_GID_UNSET; + groupname = NULL; + + if (!_dbus_hash_table_insert_ulong (db->groups, info->gid, info)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_group_info_free_allocated (info); + return NULL; + } + + + if (!_dbus_hash_table_insert_string (db->groups_by_name, + info->groupname, + info)) + { + _dbus_hash_table_remove_ulong (db->groups, info->gid); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + return info; + } +} + + +/** + * Gets the user information for the given group name, + * returned group info should not be freed. + * + * @param db user database + * @param groupname the group name + * @param info return location for const ref to group info + * @param error error location + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_user_database_get_groupname (DBusUserDatabase *db, + const DBusString *groupname, + const DBusGroupInfo **info, + DBusError *error) +{ + *info = _dbus_user_database_lookup_group (db, DBUS_GID_UNSET, groupname, error); + return *info != NULL; +} + +/** + * Gets the user information for the given GID, + * returned group info should not be freed. + * + * @param db user database + * @param gid the group ID + * @param info return location for const ref to group info + * @param error error location + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_user_database_get_gid (DBusUserDatabase *db, + dbus_gid_t gid, + const DBusGroupInfo **info, + DBusError *error) +{ + *info = _dbus_user_database_lookup_group (db, gid, NULL, error); + return *info != NULL; +} + + +/** + * Gets all groups corresponding to the given UID. Returns #FALSE + * if no memory, or user isn't known, but always initializes + * group_ids to a NULL array. + * + * @param uid the UID + * @param group_ids return location for array of group IDs + * @param n_group_ids return location for length of returned array + * @returns #TRUE if the UID existed and we got some credentials + */ +dbus_bool_t +_dbus_groups_from_uid (dbus_uid_t uid, + dbus_gid_t **group_ids, + int *n_group_ids) +{ + DBusUserDatabase *db; + const DBusUserInfo *info; + *group_ids = NULL; + *n_group_ids = 0; + + _dbus_user_database_lock_system (); + + db = _dbus_user_database_get_system (); + if (db == NULL) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + if (!_dbus_user_database_get_uid (db, uid, + &info, NULL)) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + _dbus_assert (info->uid == uid); + + if (info->n_group_ids > 0) + { + *group_ids = dbus_new (dbus_gid_t, info->n_group_ids); + if (*group_ids == NULL) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + *n_group_ids = info->n_group_ids; + + memcpy (*group_ids, info->group_ids, info->n_group_ids * sizeof (dbus_gid_t)); + } + + _dbus_user_database_unlock_system (); + return TRUE; +} +/** @} */ + +#ifdef DBUS_BUILD_TESTS +#include + +/** + * Unit test for dbus-userdb.c. + * + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_userdb_test (const char *test_data_dir) +{ + const DBusString *username; + const DBusString *homedir; + dbus_uid_t uid; + unsigned long *group_ids; + int n_group_ids, i; + + if (!_dbus_username_from_current_process (&username)) + _dbus_assert_not_reached ("didn't get username"); + + if (!_dbus_homedir_from_current_process (&homedir)) + _dbus_assert_not_reached ("didn't get homedir"); + + if (!_dbus_get_user_id (username, &uid)) + _dbus_assert_not_reached ("didn't get uid"); + + if (!_dbus_groups_from_uid (uid, &group_ids, &n_group_ids)) + _dbus_assert_not_reached ("didn't get groups"); + + printf (" Current user: %s homedir: %s gids:", + _dbus_string_get_const_data (username), + _dbus_string_get_const_data (homedir)); + + for (i=0; i + +/** + * @addtogroup DBusInternalsUtils + * @{ + */ + +/** + * Frees the given #DBusUserInfo's members with _dbus_user_info_free() + * and also calls dbus_free() on the block itself + * + * @param info the info + */ +void +_dbus_user_info_free_allocated (DBusUserInfo *info) +{ + if (info == NULL) /* hash table will pass NULL */ + return; + + _dbus_user_info_free (info); + dbus_free (info); +} + +/** + * Frees the given #DBusGroupInfo's members with _dbus_group_info_free() + * and also calls dbus_free() on the block itself + * + * @param info the info + */ +void +_dbus_group_info_free_allocated (DBusGroupInfo *info) +{ + if (info == NULL) /* hash table will pass NULL */ + return; + + _dbus_group_info_free (info); + dbus_free (info); +} + +/** + * Frees the members of info + * (but not info itself) + * @param info the user info struct + */ +void +_dbus_user_info_free (DBusUserInfo *info) +{ + dbus_free (info->group_ids); + dbus_free (info->username); + dbus_free (info->homedir); +} + +/** + * Frees the members of info (but not info itself). + * + * @param info the group info + */ +void +_dbus_group_info_free (DBusGroupInfo *info) +{ + dbus_free (info->groupname); +} + +/** + * Checks if a given string is actually a number + * and converts it if it is + * + * @param str the string to check + * @param num the memory location of the unsigned long to fill in + * @returns TRUE if str is a number and num is filled in + */ +dbus_bool_t +_dbus_is_a_number (const DBusString *str, + unsigned long *num) +{ + int end; + + if (_dbus_string_parse_uint (str, 0, num, &end) && + end == _dbus_string_get_length (str)) + return TRUE; + else + return FALSE; +} + +/** + * Looks up a uid or username in the user database. Only one of name + * or UID can be provided. There are wrapper functions for this that + * are better to use, this one does no locking or anything on the + * database and otherwise sort of sucks. + * + * @param db the database + * @param uid the user ID or #DBUS_UID_UNSET + * @param username username or #NULL + * @param error error to fill in + * @returns the entry in the database + */ +DBusUserInfo* +_dbus_user_database_lookup (DBusUserDatabase *db, + dbus_uid_t uid, + const DBusString *username, + DBusError *error) +{ + DBusUserInfo *info; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + _dbus_assert (uid != DBUS_UID_UNSET || username != NULL); + + /* See if the username is really a number */ + if (uid == DBUS_UID_UNSET) + { + unsigned long n; + + if (_dbus_is_a_number (username, &n)) + uid = n; + } + +#ifdef DBUS_ENABLE_USERDB_CACHE + if (uid != DBUS_UID_UNSET) + info = _dbus_hash_table_lookup_ulong (db->users, uid); + else + info = _dbus_hash_table_lookup_string (db->users_by_name, _dbus_string_get_const_data (username)); + + if (info) + { + _dbus_verbose ("Using cache for UID "DBUS_UID_FORMAT" information\n", + info->uid); + return info; + } + else +#else + if (1) +#endif + { + if (uid != DBUS_UID_UNSET) + _dbus_verbose ("No cache for UID "DBUS_UID_FORMAT"\n", + uid); + else + _dbus_verbose ("No cache for user \"%s\"\n", + _dbus_string_get_const_data (username)); + + info = dbus_new0 (DBusUserInfo, 1); + if (info == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + if (uid != DBUS_UID_UNSET) + { + if (!_dbus_user_info_fill_uid (info, uid, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_user_info_free_allocated (info); + return NULL; + } + } + else + { + if (!_dbus_user_info_fill (info, username, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + _dbus_user_info_free_allocated (info); + return NULL; + } + } + + /* be sure we don't use these after here */ + uid = DBUS_UID_UNSET; + username = NULL; + + /* insert into hash */ + if (!_dbus_hash_table_insert_ulong (db->users, info->uid, info)) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + _dbus_user_info_free_allocated (info); + return NULL; + } + + if (!_dbus_hash_table_insert_string (db->users_by_name, + info->username, + info)) + { + _dbus_hash_table_remove_ulong (db->users, info->uid); + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return NULL; + } + + return info; + } +} + +static dbus_bool_t database_locked = FALSE; +static DBusUserDatabase *system_db = NULL; +static DBusString process_username; +static DBusString process_homedir; + +static void +shutdown_system_db (void *data) +{ + if (system_db != NULL) + _dbus_user_database_unref (system_db); + system_db = NULL; + _dbus_string_free (&process_username); + _dbus_string_free (&process_homedir); +} + +static dbus_bool_t +init_system_db (void) +{ + _dbus_assert (database_locked); + + if (system_db == NULL) + { + DBusError error = DBUS_ERROR_INIT; + const DBusUserInfo *info; + + system_db = _dbus_user_database_new (); + if (system_db == NULL) + return FALSE; + + if (!_dbus_user_database_get_uid (system_db, + _dbus_getuid (), + &info, + &error)) + { + _dbus_user_database_unref (system_db); + system_db = NULL; + + if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) + { + dbus_error_free (&error); + return FALSE; + } + else + { + /* This really should not happen. */ + _dbus_warn ("Could not get password database information for UID of current process: %s\n", + error.message); + dbus_error_free (&error); + return FALSE; + } + } + + if (!_dbus_string_init (&process_username)) + { + _dbus_user_database_unref (system_db); + system_db = NULL; + return FALSE; + } + + if (!_dbus_string_init (&process_homedir)) + { + _dbus_string_free (&process_username); + _dbus_user_database_unref (system_db); + system_db = NULL; + return FALSE; + } + + if (!_dbus_string_append (&process_username, + info->username) || + !_dbus_string_append (&process_homedir, + info->homedir) || + !_dbus_register_shutdown_func (shutdown_system_db, NULL)) + { + _dbus_string_free (&process_username); + _dbus_string_free (&process_homedir); + _dbus_user_database_unref (system_db); + system_db = NULL; + return FALSE; + } + } + + return TRUE; +} + +/** + * Locks global system user database. + */ +void +_dbus_user_database_lock_system (void) +{ + _DBUS_LOCK (system_users); + database_locked = TRUE; +} + +/** + * Unlocks global system user database. + */ +void +_dbus_user_database_unlock_system (void) +{ + database_locked = FALSE; + _DBUS_UNLOCK (system_users); +} + +/** + * Gets the system global user database; + * must be called with lock held (_dbus_user_database_lock_system()). + * + * @returns the database or #NULL if no memory + */ +DBusUserDatabase* +_dbus_user_database_get_system (void) +{ + _dbus_assert (database_locked); + + init_system_db (); + + return system_db; +} + +/** + * Flushes the system global user database; + */ +void +_dbus_user_database_flush_system (void) +{ + _dbus_user_database_lock_system (); + + if (system_db != NULL) + _dbus_user_database_flush (system_db); + + _dbus_user_database_unlock_system (); +} + +/** + * Gets username of user owning current process. The returned string + * is valid until dbus_shutdown() is called. + * + * @param username place to store pointer to username + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_username_from_current_process (const DBusString **username) +{ + _dbus_user_database_lock_system (); + if (!init_system_db ()) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + *username = &process_username; + _dbus_user_database_unlock_system (); + + return TRUE; +} + +/** + * Gets homedir of user owning current process. The returned string + * is valid until dbus_shutdown() is called. + * + * @param homedir place to store pointer to homedir + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_homedir_from_current_process (const DBusString **homedir) +{ + _dbus_user_database_lock_system (); + if (!init_system_db ()) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + *homedir = &process_homedir; + _dbus_user_database_unlock_system (); + + return TRUE; +} + +/** + * Gets the home directory for the given user. + * + * @param username the username + * @param homedir string to append home directory to + * @returns #TRUE if user existed and we appended their homedir + */ +dbus_bool_t +_dbus_homedir_from_username (const DBusString *username, + DBusString *homedir) +{ + DBusUserDatabase *db; + const DBusUserInfo *info; + _dbus_user_database_lock_system (); + + db = _dbus_user_database_get_system (); + if (db == NULL) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + if (!_dbus_user_database_get_username (db, username, + &info, NULL)) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + if (!_dbus_string_append (homedir, info->homedir)) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + _dbus_user_database_unlock_system (); + return TRUE; +} + +/** + * Gets the home directory for the given user. + * + * @param uid the uid + * @param homedir string to append home directory to + * @returns #TRUE if user existed and we appended their homedir + */ +dbus_bool_t +_dbus_homedir_from_uid (dbus_uid_t uid, + DBusString *homedir) +{ + DBusUserDatabase *db; + const DBusUserInfo *info; + _dbus_user_database_lock_system (); + + db = _dbus_user_database_get_system (); + if (db == NULL) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + if (!_dbus_user_database_get_uid (db, uid, + &info, NULL)) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + if (!_dbus_string_append (homedir, info->homedir)) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + _dbus_user_database_unlock_system (); + return TRUE; +} + +/** + * Adds the credentials corresponding to the given username. + * + * Used among other purposes to parses a desired identity provided + * from a client in the auth protocol. On UNIX this means parsing a + * UID, on Windows probably parsing an SID string. + * + * @todo this is broken because it treats OOM and parse error + * the same way. Needs a #DBusError. + * + * @param credentials credentials to fill in + * @param username the username + * @returns #TRUE if the username existed and we got some credentials + */ +dbus_bool_t +_dbus_credentials_add_from_user (DBusCredentials *credentials, + const DBusString *username) +{ + DBusUserDatabase *db; + const DBusUserInfo *info; + + _dbus_user_database_lock_system (); + + db = _dbus_user_database_get_system (); + if (db == NULL) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + if (!_dbus_user_database_get_username (db, username, + &info, NULL)) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + if (!_dbus_credentials_add_unix_uid(credentials, info->uid)) + { + _dbus_user_database_unlock_system (); + return FALSE; + } + + _dbus_user_database_unlock_system (); + return TRUE; +} + +/** + * Creates a new user database object used to look up and + * cache user information. + * @returns new database, or #NULL on out of memory + */ +DBusUserDatabase* +_dbus_user_database_new (void) +{ + DBusUserDatabase *db; + + db = dbus_new0 (DBusUserDatabase, 1); + if (db == NULL) + return NULL; + + db->refcount = 1; + + db->users = _dbus_hash_table_new (DBUS_HASH_ULONG, + NULL, (DBusFreeFunction) _dbus_user_info_free_allocated); + + if (db->users == NULL) + goto failed; + + db->groups = _dbus_hash_table_new (DBUS_HASH_ULONG, + NULL, (DBusFreeFunction) _dbus_group_info_free_allocated); + + if (db->groups == NULL) + goto failed; + + db->users_by_name = _dbus_hash_table_new (DBUS_HASH_STRING, + NULL, NULL); + if (db->users_by_name == NULL) + goto failed; + + db->groups_by_name = _dbus_hash_table_new (DBUS_HASH_STRING, + NULL, NULL); + if (db->groups_by_name == NULL) + goto failed; + + return db; + + failed: + _dbus_user_database_unref (db); + return NULL; +} + +/** + * Flush all information out of the user database. + */ +void +_dbus_user_database_flush (DBusUserDatabase *db) +{ + _dbus_hash_table_remove_all(db->users_by_name); + _dbus_hash_table_remove_all(db->groups_by_name); + _dbus_hash_table_remove_all(db->users); + _dbus_hash_table_remove_all(db->groups); +} + +#ifdef DBUS_BUILD_TESTS +/** + * Increments refcount of user database. + * @param db the database + * @returns the database + */ +DBusUserDatabase * +_dbus_user_database_ref (DBusUserDatabase *db) +{ + _dbus_assert (db->refcount > 0); + + db->refcount += 1; + + return db; +} +#endif /* DBUS_BUILD_TESTS */ + +/** + * Decrements refcount of user database. + * @param db the database + */ +void +_dbus_user_database_unref (DBusUserDatabase *db) +{ + _dbus_assert (db->refcount > 0); + + db->refcount -= 1; + if (db->refcount == 0) + { + if (db->users) + _dbus_hash_table_unref (db->users); + + if (db->groups) + _dbus_hash_table_unref (db->groups); + + if (db->users_by_name) + _dbus_hash_table_unref (db->users_by_name); + + if (db->groups_by_name) + _dbus_hash_table_unref (db->groups_by_name); + + dbus_free (db); + } +} + +/** + * Gets the user information for the given UID, + * returned user info should not be freed. + * + * @param db user database + * @param uid the user ID + * @param info return location for const ref to user info + * @param error error location + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_user_database_get_uid (DBusUserDatabase *db, + dbus_uid_t uid, + const DBusUserInfo **info, + DBusError *error) +{ + *info = _dbus_user_database_lookup (db, uid, NULL, error); + return *info != NULL; +} + +/** + * Gets the user information for the given username. + * + * @param db user database + * @param username the user name + * @param info return location for const ref to user info + * @param error error location + * @returns #FALSE if error is set + */ +dbus_bool_t +_dbus_user_database_get_username (DBusUserDatabase *db, + const DBusString *username, + const DBusUserInfo **info, + DBusError *error) +{ + *info = _dbus_user_database_lookup (db, DBUS_UID_UNSET, username, error); + return *info != NULL; +} + +/** @} */ + +/* Tests in dbus-userdb-util.c */ diff --git a/dbus/dbus-userdb.h b/dbus/dbus-userdb.h new file mode 100644 index 00000000..cb49d9e7 --- /dev/null +++ b/dbus/dbus-userdb.h @@ -0,0 +1,121 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-userdb.h User database abstraction + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_USERDB_H +#define DBUS_USERDB_H + +#include + +#ifdef DBUS_WIN +#error "Don't include this on Windows" +#endif + +DBUS_BEGIN_DECLS + +typedef struct DBusUserDatabase DBusUserDatabase; + +#ifdef DBUS_USERDB_INCLUDES_PRIVATE +#include + +/** + * Internals of DBusUserDatabase + */ +struct DBusUserDatabase +{ + int refcount; /**< Reference count */ + + DBusHashTable *users; /**< Users in the database by UID */ + DBusHashTable *groups; /**< Groups in the database by GID */ + DBusHashTable *users_by_name; /**< Users in the database by name */ + DBusHashTable *groups_by_name; /**< Groups in the database by name */ + +}; + + +DBusUserDatabase* _dbus_user_database_new (void); +DBusUserDatabase* _dbus_user_database_ref (DBusUserDatabase *db); +void _dbus_user_database_flush (DBusUserDatabase *db); +void _dbus_user_database_unref (DBusUserDatabase *db); +dbus_bool_t _dbus_user_database_get_uid (DBusUserDatabase *db, + dbus_uid_t uid, + const DBusUserInfo **info, + DBusError *error); +dbus_bool_t _dbus_user_database_get_gid (DBusUserDatabase *db, + dbus_gid_t gid, + const DBusGroupInfo **info, + DBusError *error); +dbus_bool_t _dbus_user_database_get_username (DBusUserDatabase *db, + const DBusString *username, + const DBusUserInfo **info, + DBusError *error); +dbus_bool_t _dbus_user_database_get_groupname (DBusUserDatabase *db, + const DBusString *groupname, + const DBusGroupInfo **info, + DBusError *error); + +DBusUserInfo* _dbus_user_database_lookup (DBusUserDatabase *db, + dbus_uid_t uid, + const DBusString *username, + DBusError *error); +DBusGroupInfo* _dbus_user_database_lookup_group (DBusUserDatabase *db, + dbus_gid_t gid, + const DBusString *groupname, + DBusError *error); +void _dbus_user_info_free_allocated (DBusUserInfo *info); +void _dbus_group_info_free_allocated (DBusGroupInfo *info); +#endif /* DBUS_USERDB_INCLUDES_PRIVATE */ + +DBusUserDatabase* _dbus_user_database_get_system (void); +void _dbus_user_database_lock_system (void); +void _dbus_user_database_unlock_system (void); +void _dbus_user_database_flush_system (void); + +dbus_bool_t _dbus_get_user_id (const DBusString *username, + dbus_uid_t *uid); +dbus_bool_t _dbus_get_group_id (const DBusString *group_name, + dbus_gid_t *gid); +dbus_bool_t _dbus_get_user_id_and_primary_group (const DBusString *username, + dbus_uid_t *uid_p, + dbus_gid_t *gid_p); +dbus_bool_t _dbus_credentials_from_uid (dbus_uid_t user_id, + DBusCredentials *credentials); +dbus_bool_t _dbus_groups_from_uid (dbus_uid_t uid, + dbus_gid_t **group_ids, + int *n_group_ids); +dbus_bool_t _dbus_is_console_user (dbus_uid_t uid, + DBusError *error); + +dbus_bool_t _dbus_is_a_number (const DBusString *str, + unsigned long *num); + +dbus_bool_t _dbus_username_from_current_process (const DBusString **username); +dbus_bool_t _dbus_homedir_from_current_process (const DBusString **homedir); +dbus_bool_t _dbus_homedir_from_username (const DBusString *username, + DBusString *homedir); + +dbus_bool_t _dbus_homedir_from_uid (dbus_uid_t uid, + DBusString *homedir); + +DBUS_END_DECLS + +#endif /* DBUS_USERDB_H */ diff --git a/dbus/dbus-uuidgen.c b/dbus/dbus-uuidgen.c new file mode 100644 index 00000000..5c571e88 --- /dev/null +++ b/dbus/dbus-uuidgen.c @@ -0,0 +1,129 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-uuidgen.c The guts of the dbus-uuidgen binary live in libdbus, in this file. + * + * Copyright (C) 2006 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-uuidgen.h" +#include "dbus-internals.h" +#include "dbus-string.h" +#include "dbus-protocol.h" + +#ifdef DBUS_WIN +#error "dbus-uuidgen should not be needed on Windows" +#endif + +/** + * @defgroup DBusInternalsUuidgen dbus-uuidgen implementation + * @ingroup DBusInternals + * @brief Functions for dbus-uuidgen binary + * + * These are not considered part of the ABI, and if you call them + * you will get screwed by future changes. + * + * @{ + */ + +static dbus_bool_t +return_uuid (DBusGUID *uuid, + char **uuid_p, + DBusError *error) +{ + if (uuid_p) + { + DBusString encoded; + + if (!_dbus_string_init (&encoded)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + + if (!_dbus_uuid_encode (uuid, &encoded) || + !_dbus_string_steal_data (&encoded, uuid_p)) + { + _DBUS_SET_OOM (error); + _dbus_string_free (&encoded); + return FALSE; + } + _dbus_string_free (&encoded); + } + return TRUE; +} + +/** + * For use by the dbus-uuidgen binary ONLY, do not call this. + * We can and will change this function without modifying + * the libdbus soname. + * + * @param filename the file or #NULL for the machine ID file + * @param uuid_p out param to return the uuid + * @param create_if_not_found whether to create it if not already there + * @param error error return + * @returns #FALSE if error is set + */ +dbus_bool_t +dbus_internal_do_not_use_get_uuid (const char *filename, + char **uuid_p, + dbus_bool_t create_if_not_found, + DBusError *error) +{ + DBusGUID uuid; + + if (filename) + { + DBusString filename_str; + _dbus_string_init_const (&filename_str, filename); + if (!_dbus_read_uuid_file (&filename_str, &uuid, create_if_not_found, error)) + goto error; + } + else + { + if (!_dbus_read_local_machine_uuid (&uuid, create_if_not_found, error)) + goto error; + } + + if (!return_uuid(&uuid, uuid_p, error)) + goto error; + + return TRUE; + + error: + _DBUS_ASSERT_ERROR_IS_SET (error); + return FALSE; +} + +/** + * For use by the dbus-uuidgen binary ONLY, do not call this. + * We can and will change this function without modifying + * the libdbus soname. + * + * @param uuid_p out param to return the uuid + * @returns #FALSE if no memory + */ +dbus_bool_t +dbus_internal_do_not_use_create_uuid (char **uuid_p) +{ + DBusGUID uuid; + + _dbus_generate_uuid (&uuid); + return return_uuid (&uuid, uuid_p, NULL); +} + +/** @} */ diff --git a/dbus/dbus-uuidgen.h b/dbus/dbus-uuidgen.h new file mode 100644 index 00000000..9c1b8595 --- /dev/null +++ b/dbus/dbus-uuidgen.h @@ -0,0 +1,47 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-uuidgen.h The guts of the dbus-uuidgen binary live in libdbus, in this file. + * + * Copyright (C) 2006 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifdef DBUS_INSIDE_DBUS_H +#error "You can't include dbus-uuidgen.h in the public header dbus.h" +#endif + +#ifndef DBUS_UUIDGEN_H +#define DBUS_UUIDGEN_H + +#include +#include + +DBUS_BEGIN_DECLS + +dbus_bool_t dbus_internal_do_not_use_get_uuid (const char *filename, + char **uuid_p, + dbus_bool_t create_if_not_found, + DBusError *error); +dbus_bool_t dbus_internal_do_not_use_ensure_uuid (const char *filename, + char **uuid_p, + DBusError *error); +dbus_bool_t dbus_internal_do_not_use_create_uuid (char **uuid_p); + + +DBUS_END_DECLS + +#endif /* DBUS_UUIDGEN_H */ diff --git a/dbus/dbus-watch.c b/dbus/dbus-watch.c new file mode 100644 index 00000000..bca699fd --- /dev/null +++ b/dbus/dbus-watch.c @@ -0,0 +1,674 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-watch.c DBusWatch implementation + * + * Copyright (C) 2002, 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "dbus-internals.h" +#include "dbus-watch.h" +#include "dbus-list.h" + +/** + * @defgroup DBusWatchInternals DBusWatch implementation details + * @ingroup DBusInternals + * @brief implementation details for DBusWatch + * + * @{ + */ + +/** + * Implementation of DBusWatch + */ +struct DBusWatch +{ + int refcount; /**< Reference count */ + int fd; /**< File descriptor. */ + unsigned int flags; /**< Conditions to watch. */ + + DBusWatchHandler handler; /**< Watch handler. */ + void *handler_data; /**< Watch handler data. */ + DBusFreeFunction free_handler_data_function; /**< Free the watch handler data. */ + + void *data; /**< Application data. */ + DBusFreeFunction free_data_function; /**< Free the application data. */ + unsigned int enabled : 1; /**< Whether it's enabled. */ +}; + +dbus_bool_t +_dbus_watch_get_enabled (DBusWatch *watch) +{ + return watch->enabled; +} + +/** + * Creates a new DBusWatch. Used to add a file descriptor to be polled + * by a main loop. + * + * @param fd the file descriptor to be watched. + * @param flags the conditions to watch for on the descriptor. + * @param enabled the initial enabled state + * @param handler the handler function + * @param data data for handler function + * @param free_data_function function to free the data + * @returns the new DBusWatch object. + */ +DBusWatch* +_dbus_watch_new (int fd, + unsigned int flags, + dbus_bool_t enabled, + DBusWatchHandler handler, + void *data, + DBusFreeFunction free_data_function) +{ + DBusWatch *watch; + +#define VALID_WATCH_FLAGS (DBUS_WATCH_WRITABLE | DBUS_WATCH_READABLE) + + _dbus_assert ((flags & VALID_WATCH_FLAGS) == flags); + + watch = dbus_new0 (DBusWatch, 1); + if (watch == NULL) + return NULL; + + watch->refcount = 1; + watch->fd = fd; + watch->flags = flags; + watch->enabled = enabled; + + watch->handler = handler; + watch->handler_data = data; + watch->free_handler_data_function = free_data_function; + + return watch; +} + +/** + * Increments the reference count of a DBusWatch object. + * + * @param watch the watch object. + * @returns the watch object. + */ +DBusWatch * +_dbus_watch_ref (DBusWatch *watch) +{ + watch->refcount += 1; + + return watch; +} + +/** + * Decrements the reference count of a DBusWatch object + * and finalizes the object if the count reaches zero. + * + * @param watch the watch object. + */ +void +_dbus_watch_unref (DBusWatch *watch) +{ + _dbus_assert (watch != NULL); + _dbus_assert (watch->refcount > 0); + + watch->refcount -= 1; + if (watch->refcount == 0) + { + dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */ + + if (watch->free_handler_data_function) + (* watch->free_handler_data_function) (watch->handler_data); + + dbus_free (watch); + } +} + +/** + * Clears the file descriptor from a now-invalid watch object so that + * no one tries to use it. This is because a watch may stay alive due + * to reference counts after the file descriptor is closed. + * Invalidation makes it easier to catch bugs. It also + * keeps people from doing dorky things like assuming file descriptors + * are unique (never recycled). + * + * @param watch the watch object. + */ +void +_dbus_watch_invalidate (DBusWatch *watch) +{ + watch->fd = -1; + watch->flags = 0; +} + +/** + * Sanitizes the given condition so that it only contains + * flags that the DBusWatch requested. e.g. if the + * watch is a DBUS_WATCH_READABLE watch then + * DBUS_WATCH_WRITABLE will be stripped from the condition. + * + * @param watch the watch object. + * @param condition address of the condition to sanitize. + */ +void +_dbus_watch_sanitize_condition (DBusWatch *watch, + unsigned int *condition) +{ + if (!(watch->flags & DBUS_WATCH_READABLE)) + *condition &= ~DBUS_WATCH_READABLE; + if (!(watch->flags & DBUS_WATCH_WRITABLE)) + *condition &= ~DBUS_WATCH_WRITABLE; +} + + +/** + * @typedef DBusWatchList + * + * Opaque data type representing a list of watches + * and a set of DBusAddWatchFunction/DBusRemoveWatchFunction. + * Automatically handles removing/re-adding watches + * when the DBusAddWatchFunction is updated or changed. + * Holds a reference count to each watch. + * + * Used in the implementation of both DBusServer and + * DBusClient. + * + */ + +/** + * DBusWatchList implementation details. All fields + * are private. + * + */ +struct DBusWatchList +{ + DBusList *watches; /**< Watch objects. */ + + DBusAddWatchFunction add_watch_function; /**< Callback for adding a watch. */ + DBusRemoveWatchFunction remove_watch_function; /**< Callback for removing a watch. */ + DBusWatchToggledFunction watch_toggled_function; /**< Callback on toggling enablement */ + void *watch_data; /**< Data for watch callbacks */ + DBusFreeFunction watch_free_data_function; /**< Free function for watch callback data */ +}; + +/** + * Creates a new watch list. Returns #NULL if insufficient + * memory exists. + * + * @returns the new watch list, or #NULL on failure. + */ +DBusWatchList* +_dbus_watch_list_new (void) +{ + DBusWatchList *watch_list; + + watch_list = dbus_new0 (DBusWatchList, 1); + if (watch_list == NULL) + return NULL; + + return watch_list; +} + +/** + * Frees a DBusWatchList. + * + * @param watch_list the watch list. + */ +void +_dbus_watch_list_free (DBusWatchList *watch_list) +{ + /* free watch_data and removes watches as a side effect */ + _dbus_watch_list_set_functions (watch_list, + NULL, NULL, NULL, NULL, NULL); + _dbus_list_foreach (&watch_list->watches, + (DBusForeachFunction) _dbus_watch_unref, + NULL); + _dbus_list_clear (&watch_list->watches); + + dbus_free (watch_list); +} + +/** + * Sets the watch functions. This function is the "backend" + * for dbus_connection_set_watch_functions() and + * dbus_server_set_watch_functions(). + * + * @param watch_list the watch list. + * @param add_function the add watch function. + * @param remove_function the remove watch function. + * @param toggled_function function on toggling enabled flag, or #NULL + * @param data the data for those functions. + * @param free_data_function the function to free the data. + * @returns #FALSE if not enough memory + * + */ +dbus_bool_t +_dbus_watch_list_set_functions (DBusWatchList *watch_list, + DBusAddWatchFunction add_function, + DBusRemoveWatchFunction remove_function, + DBusWatchToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function) +{ + /* Add watches with the new watch function, failing on OOM */ + if (add_function != NULL) + { + DBusList *link; + + link = _dbus_list_get_first_link (&watch_list->watches); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&watch_list->watches, + link); + +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + const char *watch_type; + int flags; + + flags = dbus_watch_get_flags (link->data); + if ((flags & DBUS_WATCH_READABLE) && + (flags & DBUS_WATCH_WRITABLE)) + watch_type = "readwrite"; + else if (flags & DBUS_WATCH_READABLE) + watch_type = "read"; + else if (flags & DBUS_WATCH_WRITABLE) + watch_type = "write"; + else + watch_type = "not read or write"; + + _dbus_verbose ("Adding a %s watch on fd %d using newly-set add watch function\n", + watch_type, + dbus_watch_get_socket (link->data)); + } +#endif /* DBUS_ENABLE_VERBOSE_MODE */ + + if (!(* add_function) (link->data, data)) + { + /* remove it all again and return FALSE */ + DBusList *link2; + + link2 = _dbus_list_get_first_link (&watch_list->watches); + while (link2 != link) + { + DBusList *next = _dbus_list_get_next_link (&watch_list->watches, + link2); + + _dbus_verbose ("Removing watch on fd %d using newly-set remove function because initial add failed\n", + dbus_watch_get_socket (link2->data)); + + (* remove_function) (link2->data, data); + + link2 = next; + } + + return FALSE; + } + + link = next; + } + } + + /* Remove all current watches from previous watch handlers */ + + if (watch_list->remove_watch_function != NULL) + { + _dbus_verbose ("Removing all pre-existing watches\n"); + + _dbus_list_foreach (&watch_list->watches, + (DBusForeachFunction) watch_list->remove_watch_function, + watch_list->watch_data); + } + + if (watch_list->watch_free_data_function != NULL) + (* watch_list->watch_free_data_function) (watch_list->watch_data); + + watch_list->add_watch_function = add_function; + watch_list->remove_watch_function = remove_function; + watch_list->watch_toggled_function = toggled_function; + watch_list->watch_data = data; + watch_list->watch_free_data_function = free_data_function; + + return TRUE; +} + +/** + * Adds a new watch to the watch list, invoking the + * application DBusAddWatchFunction if appropriate. + * + * @param watch_list the watch list. + * @param watch the watch to add. + * @returns #TRUE on success, #FALSE if no memory. + */ +dbus_bool_t +_dbus_watch_list_add_watch (DBusWatchList *watch_list, + DBusWatch *watch) +{ + if (!_dbus_list_append (&watch_list->watches, watch)) + return FALSE; + + _dbus_watch_ref (watch); + + if (watch_list->add_watch_function != NULL) + { + _dbus_verbose ("Adding watch on fd %d\n", + dbus_watch_get_socket (watch)); + + if (!(* watch_list->add_watch_function) (watch, + watch_list->watch_data)) + { + _dbus_list_remove_last (&watch_list->watches, watch); + _dbus_watch_unref (watch); + return FALSE; + } + } + + return TRUE; +} + +/** + * Removes a watch from the watch list, invoking the + * application's DBusRemoveWatchFunction if appropriate. + * + * @param watch_list the watch list. + * @param watch the watch to remove. + */ +void +_dbus_watch_list_remove_watch (DBusWatchList *watch_list, + DBusWatch *watch) +{ + if (!_dbus_list_remove (&watch_list->watches, watch)) + _dbus_assert_not_reached ("Nonexistent watch was removed"); + + if (watch_list->remove_watch_function != NULL) + { + _dbus_verbose ("Removing watch on fd %d\n", + dbus_watch_get_socket (watch)); + + (* watch_list->remove_watch_function) (watch, + watch_list->watch_data); + } + + _dbus_watch_unref (watch); +} + +/** + * Sets a watch to the given enabled state, invoking the + * application's DBusWatchToggledFunction if appropriate. + * + * @param watch_list the watch list. + * @param watch the watch to toggle. + * @param enabled #TRUE to enable + */ +void +_dbus_watch_list_toggle_watch (DBusWatchList *watch_list, + DBusWatch *watch, + dbus_bool_t enabled) +{ + enabled = !!enabled; + + if (enabled == watch->enabled) + return; + + watch->enabled = enabled; + + if (watch_list->watch_toggled_function != NULL) + { + _dbus_verbose ("Toggling watch %p on fd %d to %d\n", + watch, dbus_watch_get_socket (watch), watch->enabled); + + (* watch_list->watch_toggled_function) (watch, + watch_list->watch_data); + } +} + +/** + * Sets the handler for the watch. + * + * @todo this function only exists because of the weird + * way connection watches are done, see the note + * in docs for _dbus_connection_handle_watch(). + * + * @param watch the watch + * @param handler the new handler + * @param data the data + * @param free_data_function free data with this + */ +void +_dbus_watch_set_handler (DBusWatch *watch, + DBusWatchHandler handler, + void *data, + DBusFreeFunction free_data_function) +{ + if (watch->free_handler_data_function) + (* watch->free_handler_data_function) (watch->handler_data); + + watch->handler = handler; + watch->handler_data = data; + watch->free_handler_data_function = free_data_function; +} + +/** @} */ + +/** + * @defgroup DBusWatch DBusWatch + * @ingroup DBus + * @brief Object representing a file descriptor to be watched. + * + * Types and functions related to DBusWatch. A watch represents + * a file descriptor that the main loop needs to monitor, + * as in Qt's QSocketNotifier or GLib's g_io_add_watch(). + * + * Use dbus_connection_set_watch_functions() or dbus_server_set_watch_functions() + * to be notified when libdbus needs to add or remove watches. + * + * @{ + */ + +/** + * @typedef DBusWatch + * + * Opaque object representing a file descriptor + * to be watched for changes in readability, + * writability, or hangup. + */ + +/** + * Deprecated former name of dbus_watch_get_unix_fd(). + * + * @param watch the DBusWatch object. + * @returns the file descriptor to watch. + */ +int +dbus_watch_get_fd (DBusWatch *watch) +{ + return dbus_watch_get_unix_fd(watch); +} + +/** + * Returns a UNIX file descriptor to be watched, + * which may be a pipe, socket, or other type of + * descriptor. On UNIX this is preferred to + * dbus_watch_get_socket() since it works with + * more kinds of #DBusWatch. + * + * Always returns -1 on Windows. On Windows you use + * dbus_watch_get_socket() to get a Winsock socket to watch. + * + * @param watch the DBusWatch object. + * @returns the file descriptor to watch. + */ +int +dbus_watch_get_unix_fd (DBusWatch *watch) +{ + /* FIXME remove #ifdef and do this on a lower level + * (watch should have set_socket and set_unix_fd and track + * which it has, and the transport should provide the + * appropriate watch type) + */ +#ifdef DBUS_UNIX + return watch->fd; +#else + return -1; +#endif +} + +/** + * Returns a socket to be watched, on UNIX this will return -1 if our + * transport is not socket-based so dbus_watch_get_unix_fd() is + * preferred. + * + * On Windows, dbus_watch_get_unix_fd() returns -1 but this function + * returns a Winsock socket (assuming the transport is socket-based, + * as it always is for now). + * + * @param watch the DBusWatch object. + * @returns the socket to watch. + */ +int +dbus_watch_get_socket (DBusWatch *watch) +{ + return watch->fd; +} + +/** + * Gets flags from DBusWatchFlags indicating + * what conditions should be monitored on the + * file descriptor. + * + * The flags returned will only contain DBUS_WATCH_READABLE + * and DBUS_WATCH_WRITABLE, never DBUS_WATCH_HANGUP or + * DBUS_WATCH_ERROR; all watches implicitly include a watch + * for hangups, errors, and other exceptional conditions. + * + * @param watch the DBusWatch object. + * @returns the conditions to watch. + */ +unsigned int +dbus_watch_get_flags (DBusWatch *watch) +{ + _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags); + + return watch->flags; +} + +/** + * Gets data previously set with dbus_watch_set_data() + * or #NULL if none. + * + * @param watch the DBusWatch object. + * @returns previously-set data. + */ +void* +dbus_watch_get_data (DBusWatch *watch) +{ + return watch->data; +} + +/** + * Sets data which can be retrieved with dbus_watch_get_data(). + * Intended for use by the DBusAddWatchFunction and + * DBusRemoveWatchFunction to store their own data. For example with + * Qt you might store the QSocketNotifier for this watch and with GLib + * you might store a GSource. + * + * @param watch the DBusWatch object. + * @param data the data. + * @param free_data_function function to be called to free the data. + */ +void +dbus_watch_set_data (DBusWatch *watch, + void *data, + DBusFreeFunction free_data_function) +{ + _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n", + dbus_watch_get_socket (watch), + data, free_data_function, watch->data, watch->free_data_function); + + if (watch->free_data_function != NULL) + (* watch->free_data_function) (watch->data); + + watch->data = data; + watch->free_data_function = free_data_function; +} + +/** + * Returns whether a watch is enabled or not. If not + * enabled, it should not be polled by the main loop. + * + * @param watch the DBusWatch object + * @returns #TRUE if the watch is enabled + */ +dbus_bool_t +dbus_watch_get_enabled (DBusWatch *watch) +{ + _dbus_assert (watch != NULL); + return watch->enabled; +} + + +/** + * Called to notify the D-Bus library when a previously-added watch is + * ready for reading or writing, or has an exception such as a hangup. + * + * If this function returns #FALSE, then the file descriptor may still + * be ready for reading or writing, but more memory is needed in order + * to do the reading or writing. If you ignore the #FALSE return, your + * application may spin in a busy loop on the file descriptor until + * memory becomes available, but nothing more catastrophic should + * happen. + * + * dbus_watch_handle() cannot be called during the + * DBusAddWatchFunction, as the connection will not be ready to handle + * that watch yet. + * + * It is not allowed to reference a DBusWatch after it has been passed + * to remove_function. + * + * @param watch the DBusWatch object. + * @param flags the poll condition using #DBusWatchFlags values + * @returns #FALSE if there wasn't enough memory + */ +dbus_bool_t +dbus_watch_handle (DBusWatch *watch, + unsigned int flags) +{ +#ifndef DBUS_DISABLE_CHECKS + if (watch->fd < 0 || watch->flags == 0) + { + _dbus_warn_check_failed ("%s: Watch is invalid, it should have been removed\n", + _DBUS_FUNCTION_NAME); + return TRUE; + } +#endif + + _dbus_return_val_if_fail (watch->fd >= 0 /* fails if watch was removed */, TRUE); + + _dbus_watch_sanitize_condition (watch, &flags); + + if (flags == 0) + { + _dbus_verbose ("After sanitization, watch flags on fd %d were 0\n", + watch->fd); + return TRUE; + } + else + return (* watch->handler) (watch, flags, + watch->handler_data); +} + + +/** @} */ diff --git a/dbus/dbus-watch.h b/dbus/dbus-watch.h new file mode 100644 index 00000000..fa953ec1 --- /dev/null +++ b/dbus/dbus-watch.h @@ -0,0 +1,83 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-watch.h DBusWatch internal interfaces + * + * Copyright (C) 2002 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_WATCH_H +#define DBUS_WATCH_H + +#include +#include + +DBUS_BEGIN_DECLS + +/** + * @addtogroup DBusWatchInternals + * @{ + */ + +/* Public methods on DBusWatch are in dbus-connection.h */ + +typedef struct DBusWatchList DBusWatchList; + +/** function to run when the watch is handled */ +typedef dbus_bool_t (* DBusWatchHandler) (DBusWatch *watch, + unsigned int flags, + void *data); + +DBusWatch* _dbus_watch_new (int fd, + unsigned int flags, + dbus_bool_t enabled, + DBusWatchHandler handler, + void *data, + DBusFreeFunction free_data_function); +DBusWatch* _dbus_watch_ref (DBusWatch *watch); +void _dbus_watch_unref (DBusWatch *watch); +void _dbus_watch_invalidate (DBusWatch *watch); +void _dbus_watch_sanitize_condition (DBusWatch *watch, + unsigned int *condition); +void _dbus_watch_set_handler (DBusWatch *watch, + DBusWatchHandler handler, + void *data, + DBusFreeFunction free_data_function); + + +DBusWatchList* _dbus_watch_list_new (void); +void _dbus_watch_list_free (DBusWatchList *watch_list); +dbus_bool_t _dbus_watch_list_set_functions (DBusWatchList *watch_list, + DBusAddWatchFunction add_function, + DBusRemoveWatchFunction remove_function, + DBusWatchToggledFunction toggled_function, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t _dbus_watch_list_add_watch (DBusWatchList *watch_list, + DBusWatch *watch); +void _dbus_watch_list_remove_watch (DBusWatchList *watch_list, + DBusWatch *watch); +void _dbus_watch_list_toggle_watch (DBusWatchList *watch_list, + DBusWatch *watch, + dbus_bool_t enabled); +dbus_bool_t _dbus_watch_get_enabled (DBusWatch *watch); + +/** @} */ + +DBUS_END_DECLS + +#endif /* DBUS_WATCH_H */ diff --git a/dbus/dbus.h b/dbus/dbus.h new file mode 100644 index 00000000..1f099508 --- /dev/null +++ b/dbus/dbus.h @@ -0,0 +1,103 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus.h Convenience header including all other headers + * + * Copyright (C) 2002, 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_H +#define DBUS_H + +#define DBUS_INSIDE_DBUS_H 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DBUS_INSIDE_DBUS_H + +/** + * @defgroup DBus D-Bus low-level public API + * @brief The low-level public API of the D-Bus library + * + * libdbus provides a low-level C API intended primarily for use by + * bindings to specific object systems and languages. D-Bus is most + * convenient when used with the GLib bindings, Python bindings, Qt + * bindings, Mono bindings, and so forth. This low-level API has a + * lot of complexity useful only for bindings. + * + * @{ + */ + +/** @} */ + +/** + * @mainpage + * + * This manual documents the low-level D-Bus C API. If you use + * this low-level API directly, you're signing up for some pain. + * + * Caveats aside, you might get started learning the low-level API by reading + * about @ref DBusConnection and @ref DBusMessage. + * + * There are several other places to look for D-Bus information, such + * as the tutorial and the specification; those can be found at the D-Bus + * website. If you're interested in a sysadmin or package + * maintainer's perspective on the dbus-daemon itself and its + * configuration, be sure to check out the man pages as well. + * + * The low-level API documented in this manual deliberately lacks + * most convenience functions - those are left up to higher-level libraries + * based on frameworks such as GLib, Qt, Python, Mono, Java, + * etc. These higher-level libraries (often called "D-Bus bindings") + * have features such as object systems and main loops that allow a + * much more convenient API. + * + * The low-level API also contains plenty of clutter to support + * integration with arbitrary object systems, languages, main loops, + * and so forth. These features add a lot of noise to the API that you + * probably don't care about unless you're coding a binding. + * + * This manual also contains docs for @ref DBusInternals "D-Bus internals", + * so you can use it to get oriented to the D-Bus source code if you're + * interested in patching the code. You should also read the + * file HACKING which comes with the source code if you plan to contribute to + * D-Bus. + * + * As you read the code, you can identify internal D-Bus functions + * because they start with an underscore ('_') character. Also, any + * identifier or macro that lacks a DBus, dbus_, or DBUS_ namepace + * prefix is internal, with a couple of exceptions such as #NULL, + * #TRUE, and #FALSE. + */ + +#endif /* DBUS_H */ diff --git a/depcomp b/depcomp new file mode 100755 index 00000000..df8eea7e --- /dev/null +++ b/depcomp @@ -0,0 +1,630 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free +# Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, 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 Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u="sed s,\\\\\\\\,/,g" + depmode=msvisualcpp +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> "$depfile" + echo >> "$depfile" + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add `dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 00000000..f76335f6 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,41 @@ +EXTRA_DIST= \ + busconfig.dtd \ + diagram.png \ + diagram.svg \ + introspect.dtd \ + dbus-faq.xml \ + dbus-specification.xml \ + dbus-test-plan.xml \ + dbus-tutorial.xml \ + dcop-howto.txt \ + file-boilerplate.c \ + introspect.xsl \ + system-activation.txt + +HTML_FILES= \ + dbus-faq.html \ + dbus-specification.html \ + dbus-test-plan.html \ + dbus-tutorial.html + +if DBUS_XML_DOCS_ENABLED +all-local: $(HTML_FILES) + +EXTRA_DIST += $(HTML_FILES) + +dbus-specification.html: dbus-specification.xml + $(XMLTO) html-nochunks $< + +dbus-test-plan.html: dbus-test-plan.xml + $(XMLTO) html-nochunks $< + +dbus-tutorial.html: dbus-tutorial.xml + $(XMLTO) html-nochunks $< + +dbus-faq.html: dbus-faq.xml + $(XMLTO) html-nochunks $< + +endif + +maintainer-clean-local: + rm -f $(HTML_FILES) diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 00000000..05386f6f --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,463 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@DBUS_XML_DOCS_ENABLED_TRUE@am__append_1 = $(HTML_FILES) +subdir = doc +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in TODO +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DBUS_BINDIR = @DBUS_BINDIR@ +DBUS_BUS_CFLAGS = @DBUS_BUS_CFLAGS@ +DBUS_BUS_LIBS = @DBUS_BUS_LIBS@ +DBUS_CLIENT_CFLAGS = @DBUS_CLIENT_CFLAGS@ +DBUS_CLIENT_LIBS = @DBUS_CLIENT_LIBS@ +DBUS_CONSOLE_AUTH_DIR = @DBUS_CONSOLE_AUTH_DIR@ +DBUS_CONSOLE_OWNER_FILE = @DBUS_CONSOLE_OWNER_FILE@ +DBUS_DAEMONDIR = @DBUS_DAEMONDIR@ +DBUS_DATADIR = @DBUS_DATADIR@ +DBUS_HAVE_INT64 = @DBUS_HAVE_INT64@ +DBUS_INT16_TYPE = @DBUS_INT16_TYPE@ +DBUS_INT32_TYPE = @DBUS_INT32_TYPE@ +DBUS_INT64_CONSTANT = @DBUS_INT64_CONSTANT@ +DBUS_INT64_TYPE = @DBUS_INT64_TYPE@ +DBUS_LAUNCHER_CFLAGS = @DBUS_LAUNCHER_CFLAGS@ +DBUS_LAUNCHER_LIBS = @DBUS_LAUNCHER_LIBS@ +DBUS_LIBEXECDIR = @DBUS_LIBEXECDIR@ +DBUS_MAJOR_VERSION = @DBUS_MAJOR_VERSION@ +DBUS_MICRO_VERSION = @DBUS_MICRO_VERSION@ +DBUS_MINOR_VERSION = @DBUS_MINOR_VERSION@ +DBUS_PATH_OR_ABSTRACT = @DBUS_PATH_OR_ABSTRACT@ +DBUS_SESSION_SOCKET_DIR = @DBUS_SESSION_SOCKET_DIR@ +DBUS_SYSTEM_BUS_DEFAULT_ADDRESS = @DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ +DBUS_SYSTEM_PID_FILE = @DBUS_SYSTEM_PID_FILE@ +DBUS_SYSTEM_SOCKET = @DBUS_SYSTEM_SOCKET@ +DBUS_TEST_CFLAGS = @DBUS_TEST_CFLAGS@ +DBUS_TEST_LIBS = @DBUS_TEST_LIBS@ +DBUS_UINT64_CONSTANT = @DBUS_UINT64_CONSTANT@ +DBUS_USER = @DBUS_USER@ +DBUS_VERSION = @DBUS_VERSION@ +DBUS_X_CFLAGS = @DBUS_X_CFLAGS@ +DBUS_X_LIBS = @DBUS_X_LIBS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPANDED_BINDIR = @EXPANDED_BINDIR@ +EXPANDED_DATADIR = @EXPANDED_DATADIR@ +EXPANDED_LIBDIR = @EXPANDED_LIBDIR@ +EXPANDED_LIBEXECDIR = @EXPANDED_LIBEXECDIR@ +EXPANDED_LOCALSTATEDIR = @EXPANDED_LOCALSTATEDIR@ +EXPANDED_SYSCONFDIR = @EXPANDED_SYSCONFDIR@ +FGREP = @FGREP@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML_CFLAGS = @LIBXML_CFLAGS@ +LIBXML_LIBS = @LIBXML_LIBS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_AGE = @LT_AGE@ +LT_CURRENT = @LT_CURRENT@ +LT_REVISION = @LT_REVISION@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIC_CFLAGS = @PIC_CFLAGS@ +PIC_LDFLAGS = @PIC_LDFLAGS@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +R_DYNAMIC_LDFLAG = @R_DYNAMIC_LDFLAG@ +SECTION_FLAGS = @SECTION_FLAGS@ +SECTION_LDFLAGS = @SECTION_LDFLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TEST_BUS_BINARY = @TEST_BUS_BINARY@ +TEST_EXIT_BINARY = @TEST_EXIT_BINARY@ +TEST_INVALID_SERVICE_DIR = @TEST_INVALID_SERVICE_DIR@ +TEST_INVALID_SERVICE_SYSTEM_DIR = @TEST_INVALID_SERVICE_SYSTEM_DIR@ +TEST_LAUNCH_HELPER_BINARY = @TEST_LAUNCH_HELPER_BINARY@ +TEST_PRIVSERVER_BINARY = @TEST_PRIVSERVER_BINARY@ +TEST_SEGFAULT_BINARY = @TEST_SEGFAULT_BINARY@ +TEST_SERVICE_BINARY = @TEST_SERVICE_BINARY@ +TEST_SHELL_SERVICE_BINARY = @TEST_SHELL_SERVICE_BINARY@ +TEST_SLEEP_FOREVER_BINARY = @TEST_SLEEP_FOREVER_BINARY@ +TEST_SOCKET_DIR = @TEST_SOCKET_DIR@ +TEST_VALID_SERVICE_DIR = @TEST_VALID_SERVICE_DIR@ +TEST_VALID_SERVICE_SYSTEM_DIR = @TEST_VALID_SERVICE_SYSTEM_DIR@ +VERSION = @VERSION@ +XMKMF = @XMKMF@ +XMLTO = @XMLTO@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = busconfig.dtd diagram.png diagram.svg introspect.dtd \ + dbus-faq.xml dbus-specification.xml dbus-test-plan.xml \ + dbus-tutorial.xml dcop-howto.txt file-boilerplate.c \ + introspect.xsl system-activation.txt $(am__append_1) +HTML_FILES = \ + dbus-faq.html \ + dbus-specification.html \ + dbus-test-plan.html \ + dbus-tutorial.html + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu doc/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +@DBUS_XML_DOCS_ENABLED_FALSE@all-local: +all-am: Makefile all-local +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic \ + maintainer-clean-local + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am all-local check check-am clean clean-generic \ + clean-libtool distclean distclean-generic distclean-libtool \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic \ + maintainer-clean-local mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am + + +@DBUS_XML_DOCS_ENABLED_TRUE@all-local: $(HTML_FILES) + +@DBUS_XML_DOCS_ENABLED_TRUE@dbus-specification.html: dbus-specification.xml +@DBUS_XML_DOCS_ENABLED_TRUE@ $(XMLTO) html-nochunks $< + +@DBUS_XML_DOCS_ENABLED_TRUE@dbus-test-plan.html: dbus-test-plan.xml +@DBUS_XML_DOCS_ENABLED_TRUE@ $(XMLTO) html-nochunks $< + +@DBUS_XML_DOCS_ENABLED_TRUE@dbus-tutorial.html: dbus-tutorial.xml +@DBUS_XML_DOCS_ENABLED_TRUE@ $(XMLTO) html-nochunks $< + +@DBUS_XML_DOCS_ENABLED_TRUE@dbus-faq.html: dbus-faq.xml +@DBUS_XML_DOCS_ENABLED_TRUE@ $(XMLTO) html-nochunks $< + +maintainer-clean-local: + rm -f $(HTML_FILES) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/doc/TODO b/doc/TODO new file mode 100644 index 00000000..eb4e797f --- /dev/null +++ b/doc/TODO @@ -0,0 +1,155 @@ +Important for 1.2 +=== + + - System bus activation + + - Windows port + +Important for 1.0 GLib Bindings +=== + + - Test point-to-point mode + + - Add support for getting sender + + - format_version in the object info doesn't look like it's handled correctly. The creator + of the object info should specify some fixed number per struct version; the library + should handle only specific numbers it knows about. There's no assumption that all + numbers >= the given one are compatible. The idea is that new versions of the lib + can offer totally different object info structs, but old versions + keep working. + +Important for 1.0 Python bindings +=== + + - Hammer down API + + - Fix removing of signals from the match tree + + - Fix refcounting and userdata lifecycles + + - Write a generic mainloop + +Might as Well for 1.0 +=== + + - protocol version in each message is pretty silly + +Can Be Post 1.0 +=== + + - revamp dbus-launch a bit, + see http://lists.freedesktop.org/archives/dbus/2006-October/005906.html + for some thoughts. + + - clean up the creds issue on *BSD's in dbus/dbus-sysdeps-unix.c. + They should work as is but we need to rearange it to make it + clearer which method is being used. configure.in should + be fixed up to make that decition. + + - _dbus_connection_unref_unlocked() is essentially always broken because + the connection finalizer calls non-unlocked functions. One fix is to make + the finalizer run with the lock held, but since it calls out to the app that may + be pretty broken. More likely all the uses of unref_unlocked are just wrong. + + - if the GUID is obtained only during authentication, not in the address, + we could still share the connection + + - Allow a dbus_g_proxy_to_string()/g_object_to_string() that + would convert the proxy to an "IOR" and dbus_g_proxy_from_string() + that would decode; using these, dbus-glib users could avoid + DBusConnection entirely. Of course the same applies to other kinds + of binding. This would use dbus_connection_open()'s connection-sharing + feature to avoid massive proliferation of connections. + + - DBusWatchList/TimeoutList duplicate a lot of code, as do + protected_change_watch/protected_change_timeout in dbus-connection.c + and dbus-server.c. This could all be mopped up, cut-and-paste + fixed, code size reduced. + + - change .service files to allow Names=list in addition to Name=string + + - The message bus internal code still says "service" for + "name", "base service" for "unique name", "activate" for + "start"; would be nice to clean up. + + - Property list feature on message bus (list of properties associated + with a connection). May also include message matching rules + that involve the properties of the source or destination + connection. + + - Disconnecting the remote end on invalid UTF-8 is probably not a good + idea. The definition of "valid" is slightly fuzzy. I think it might + be better to just silently "fix" the UTF-8, or perhaps return an error. + + - build and install the Doxygen manual in Makefile when --enable-docs + + - if you send the same message to multiple connections, the serial number + will only be right for one of them. Probably need to just write() the serial + number, rather than putting it in the DBusMessage, or something. + + - perhaps the bus driver should have properties that reflect attributes + of the session, such as hostname, architecture, operating system, + etc. Could be useful for code that wants to special-case behavior + for a particular host or class of hosts, for example. + + - currently the security policy stuff for messages to/from + the bus driver is kind of strange; basically it's hardcoded that + you can always talk to the driver, but the default config file + has rules for it anyway, or something. it's conceptually + screwy at the moment. + + - when making a method call, if the call serial were globally unique, + we could forward the call serial along with any method calls made + as a result of the first method call, and allow reentrancy that was + strictly part of the call stack of said method call. But I don't + really see how to do this without making the user pass around the + call serial to all method calls all the time, or disallowing + async calls. + + If done post 1.0 will probably be an optional/ugly-API type + of thing. + + - I don't want to introduce DBusObject, but refcounting and object + data could still be factored out into an internal "base class" + perhaps. + + - Keep convenience wrappers in sync with bus methods + + - document the auth protocol as a set of states and transitions, and + then reimplement it in those terms + + - recursive dispatch, see dbus_connection_dispatch() + + - do we need per-display activation; if so I'd like to do this by setting a + "display ID" property on screen 0, with a GUID, and keying activation by + said GUID. Otherwise you get all kinds of unrobust + string/hostname-based mess. per-screen is then done by appending screen number + to the display. If displays have a deterministic ID like this, you can + do per-display by simply including GUID in the service name. + + - optimization and profiling! + + - Match rules aren't in the spec (probably a lot of methods on the bus + are not) + + - the "break loader" and valid/invalid message tests are all disabled; + they need to be fixed and re-enabled with the new message args stuff. + I think I want to drop the .message files thing and just have code + that generates messages, more like the tests for + dbus-marshal-recursive.c (this is mostly done now, just needs some + cleanup) + + - just before 1.0, try a HAVE_INT64=0 build and be sure it runs + + - Windows port needs recursive mutexes + +Should Be Post 1.0 +=== + + - look into supporting the concept of a "connection" generically + (what does this TODO item mean?) + + - test/name-test should be named test/with-bus or something like that + + diff --git a/doc/busconfig.dtd b/doc/busconfig.dtd new file mode 100644 index 00000000..0cc519b4 --- /dev/null +++ b/doc/busconfig.dtd @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/dbus-faq.html b/doc/dbus-faq.html new file mode 100644 index 00000000..dff70fad --- /dev/null +++ b/doc/dbus-faq.html @@ -0,0 +1,437 @@ +D-Bus FAQ

D-Bus FAQ

Havoc Pennington

Red Hat, Inc.


+     
+   

David A Wheeler

Version 0.3


1. + What is D-Bus? +
2. + Is D-Bus stable/finished? +
3. + How is the reference implementation licensed? Can I use it in + proprietary applications? +
4. + What is the difference between a bus name, and object path, + and an interface? +
5. + What is a "service"? +
6. + Is D-Bus a "component system"? +
7. + How fast is the D-Bus reference implementation? +
8. + How large is the D-Bus reference implementation? +
9. + How does D-Bus differ from other interprocess communication + or networking protocols? +
10. + How does D-Bus differ from CORBA? +
11. + How does D-Bus differ from XML-RPC and SOAP? +
12. + How does D-Bus differ from DCE? +
13. + How does D-Bus differ from DCOM and COM? +
14. + How does D-Bus differ from ZeroC's Internet Communications Engine (Ice) +
15. + How does D-Bus differ from Inter-Client Exchange (ICE)? +
16. + How does D-Bus differ from DCOP? +
17. + How does D-Bus differ from [yet more IPC mechanisms]? +
18. + Which IPC mechanism should I use? +
19. + How can I submit a bug or patch? +

1.

+ What is D-Bus? +

+ This is probably best answered by reading the D-Bus tutorial or + the introduction to the specification. In + short, it is a system consisting of 1) a wire protocol for exposing a + typical object-oriented language/framework to other applications; and + 2) a bus daemon that allows applications to find and monitor one another. + Phrased differently, D-Bus is 1) an interprocess communication (IPC) system and 2) some higher-level + structure (lifecycle tracking, service activation, security policy) provided by two bus daemons, + one systemwide and one per-user-session. +

2.

+ Is D-Bus stable/finished? +

+ The low-level library "libdbus" and the protocol specification are considered + ABI stable. The README + file has a discussion of the API/ABI stability guarantees. + Higher-level bindings (such as those for Qt, GLib, Python, Java, C#) each + have their own release schedules and degree of maturity, not linked to + the low-level library and bus daemon release. Check the project page for + the binding you're considering to understand that project's policies. +

3.

+ How is the reference implementation licensed? Can I use it in + proprietary applications? +

+ The short answer is yes, you can use it in proprietary applications. + You should read the COPYING file, which + offers you the choice of two licenses. These are the GPL and the + AFL. The GPL requires that your application be licensed under the GPL + as well. The AFL is an "X-style" or "BSD-style" license compatible + with proprietary licensing, but it does have some requirements; in + particular it prohibits you from filing a lawsuit alleging that the + D-Bus software infringes your patents while you continue to + use D-Bus. If you're going to sue, you have to stop using + the software. Read the licenses to determine their meaning, this FAQ + entry is not intended to change the meaning or terms of the licenses. +

4.

+ What is the difference between a bus name, and object path, + and an interface? +

+ If you imagine a C++ program that implements a network service, then + the bus name is the hostname of the computer running this C++ program, + the object path is a C++ object instance pointer, and an interface is + a C++ class (a pure virtual or abstract class, to be exact). +

+ In Java terms, the object path is an object reference, + and an interface is a Java interface. +

+ People get confused because if they write an application + with a single object instance and a single interface, + then the bus name, object path, and interface look + redundant. For example, you might have a text editor + that uses the bus name org.freedesktop.TextEditor, + has a global singleton object called + /org/freedesktop/TextEditor, and + that singleton object could implement the interface + org.freedesktop.TextEditor. +

+ However, a text editor application could as easily own multiple bus + names (for example, org.kde.KWrite in addition to + generic TextEditor), have multiple objects (maybe + /org/kde/documents/4352 where the number changes + according to the document), and each object could implement multiple + interfaces, such as org.freedesktop.DBus.Introspectable, + org.freedesktop.BasicTextField, + org.kde.RichTextDocument. +

5.

+ What is a "service"? +

+ A service is a program that can be launched by the bus daemon + to provide some functionality to other programs. Services + are normally launched according to the bus name they will + have. +

+ People often misuse the word "service" for any + bus name, but this tends to be ambiguous and confusing so is discouraged. + In the D-Bus docs we try to use "service" only when talking about + programs the bus knows how to launch, i.e. a service always has a + .service file. +

6.

+ Is D-Bus a "component system"? +

+ It helps to keep these concepts separate in your mind: +

  1. + Object/component system +

  2. + GUI control/widget embedding interfaces +

  3. + Interprocess communication system or wire protocol +

+

+ D-Bus is not a component system. "Component system" was originally + defined by COM, and was essentially a workaround for the limitations + of the C++ object system (adding introspection, runtime location of + objects, ABI guarantees, and so forth). With the C# language and CLR, + Microsoft added these features to the primary object system, leaving + COM obsolete. Similarly, Java has much less need for something like + COM than C++ did. Even QObject (from Qt) and GObject (from GLib) offer + some of the same features found in COM. +

+ Component systems are not about GUI control embedding. Embedding + a spreadsheet in a word processor document is a matter of defining + some specific interfaces that objects + can implement. These interfaces provide methods related to + GUI controls. So an object implementing those interfaces + can be embedded. +

+ The word "component" just means "object with some fancy features" and + in modern languages all objects are effectively "components." +

+ So components are fancy objects, and some objects are GUI controls. +

+ A third, unrelated feature is interprocess communication or IPC. + D-Bus is an IPC system. Given an object (or "component" if you must), + you can expose the functionality of that object over an IPC system. + Examples of IPC systems are DCOM, CORBA, SOAP, XML-RPC, and D-Bus. + You can use any of these IPC systems with any object/component system, + though some of them are "tuned" for specific object systems. + You can think of an IPC system primarily as a wire protocol. +

+ If you combine an IPC system with a set of GUI control interfaces, + then you can have an out-of-process or dynamically-loaded GUI control. +

+ Another related concept is the plugin or + extension. Generic plugin systems such as the + Eclipse system are not so different + from component/object systems, though perhaps a "plugin" tends to be a + bundle of objects with a user-visible name and can be + downloaded/packaged as a unit. +

7.

+ How fast is the D-Bus reference implementation? +

+ Of course it depends a bit on what you're doing. + + This mail contains some benchmarking. At the time of that + benchmark, D-Bus one-to-one communication was about 2.5x slower than + simply pushing the data raw over a socket. After the recent rewrite of + the marshaling code, D-Bus is slower than that because a lot of + optimization work was lost. But it can probably be sped up again. +

+ D-Bus communication with the intermediate bus daemon should be + (and as last profiled, was) about twice as slow as one-to-one + mode, because a round trip involves four socket reads/writes rather + than two socket reads/writes. +

+ The overhead comes from a couple of places; part of it is simply + "abstraction penalty" (there are layers of code to support + multiple main loops, multiple transport types, security, etc.). + Probably the largest part comes from data validation + (because the reference implementation does not trust incoming data). + It would be simple to add a "no validation" mode, but probably + not a good idea all things considered. +

+ Raw bandwidth isn't the only concern; D-Bus is designed to + enable asynchronous communication and avoid round trips. + This is frequently a more important performance issue + than throughput. +

8.

+ How large is the D-Bus reference implementation? +

+ A production build (with assertions, unit tests, and verbose logging + disabled) is on the order of a 150K shared library. +

+ A much, much smaller implementation would be possible by omitting out + of memory handling, hardcoding a main loop (or always using blocking + I/O), skipping validation, and otherwise simplifying things. +

9.

+ How does D-Bus differ from other interprocess communication + or networking protocols? +

+ Keep in mind, it is not only an IPC system; it also includes + lifecycle tracking, service activation, security policy, and other + higher-level structure and assumptions. +

+ The best place to start is to read the D-Bus tutorial, so + you have a concrete idea what D-Bus actually is. If you + understand other protocols on a wire format level, you + may also want to read the D-Bus specification to see what + D-Bus looks like on a low level. +

+ As the tutorial and specification both explain, D-Bus is tuned + for some specific use cases. Thus, it probably isn't tuned + for what you want to do, unless you are doing the things + D-Bus was designed for. Don't make the mistake of thinking + that any system involving "IPC" is the same thing. +

+ The D-Bus authors would not recommend using D-Bus + for applications where it doesn't make sense. + The following questions compare D-Bus to some other + protocols primarily to help you understand D-Bus + and decide whether it's appropriate; D-Bus is neither intended + nor claimed to be the right choice for every application. +

+ It should be possible to bridge D-Bus to other IPC systems, + just as D-Bus can be bridged to object systems. +

+ Note: the D-Bus mailing list subscribers are very much not + interested in debating which IPC system is the One True + System. So if you want to discuss that, please use another forum. +

10.

+ How does D-Bus differ from CORBA? +

+ Start by reading Q: 9. +

+ CORBA is designed to support + object-oriented IPC between objects, automatically marshalling + parameters as necessary. CORBA is strongly supported by the Open Management Group (OMG), which + produces various standards and supporting documents for CORBA and has + the backing of many large organizations. There are many CORBA ORBs + available, both proprietary ORBs and free / open source software ORBs + (the latter include ORBit, MICO, and The ACE Orb (TAO)). Many + organizations continue to use CORBA ORBs for various kinds of IPC. +

+ Both GNOME and KDE have used CORBA and then moved away from it. KDE + had more success with a system called DCOP, and GNOME layered a system + called Bonobo on top of CORBA. Without custom extensions, CORBA does + not support many of the things one wants to do in a desktop + environment with the GNOME/KDE architecture. +

+ CORBA on the other hand has a number of features of interest for + enterprise and web application development, though XML systems such as + SOAP are the latest fad. +

+ Like D-Bus, CORBA uses a fast binary protocol (IIOP). Both systems + work in terms of objects and methods, and have concepts such as + "oneway" calls. Only D-Bus has direct support for "signals" as in + GLib/Qt (or Java listeners, or C# delegates). +

+ D-Bus hardcodes and specifies a lot of things that CORBA leaves open-ended, + because CORBA is more generic and D-Bus has two specific use-cases in mind. + This makes D-Bus a bit simpler. +

+ However, unlike CORBA D-Bus does not specify the + API for the language bindings. Instead, "native" bindings adapted + specifically to the conventions of a framework such as QObject, + GObject, C#, Java, Python, etc. are encouraged. The libdbus reference + implementation is designed to be a backend for bindings of this + nature, rather than to be used directly. The rationale is that an IPC + system API should not "leak" all over a program; it should come into + play only just before data goes over the wire. As an aside, OMG is + apparently working on a simpler C++ binding for CORBA. +

+ Many CORBA implementations such as ORBit are faster than the libdbus + reference implementation. One reason is that D-Bus considers data + from the other end of the connection to be untrusted and extensively + validates it. But generally speaking other priorities were placed + ahead of raw speed in the libdbus implementation. A fast D-Bus + implementation along the lines of ORBit should be possible, of course. +

+ On a more trivial note, D-Bus involves substantially fewer acronyms + than CORBA. +

11.

+ How does D-Bus differ from XML-RPC and SOAP? +

+ Start by reading Q: 9. +

+ In SOAP and XML-RPC, RPC calls are transformed + into an XML-based format, then sent over the wire (typically using the + HTTP protocol), where they are processed and returned. XML-RPC is the + simple protocol (its spec is only a page or two), and SOAP is the + full-featured protocol. +

+ XML-RPC and SOAP impose XML parsing overhead that is normally + irrelevant in the context of the Internet, but significant for + constant fine-grained IPC among applications in a desktop session. +

+ D-Bus offers persistent connections and with the bus daemon + supports lifecycle tracking of other applications connected + to the bus. With XML-RPC and SOAP, typically each method call + exists in isolation and has its own HTTP connection. +

12.

+ How does D-Bus differ from DCE? +

+ Start by reading Q: 9. +

+ Distributed Computing + Environment (DCE) is an industry-standard vendor-neutral + standard that includes an IPC mechanism. The Open Group + has released an implementation as open source software. DCE + is quite capable, and includes a vast amount of functionality such as + a distributed time service. As the name implies, DCE is intended for + use in a large, multi-computer distributed application. D-Bus would + not be well-suited for this. +

13.

+ How does D-Bus differ from DCOM and COM? +

+ Start by reading Q: 9. +

+ Comparing D-Bus to COM is apples and oranges; + see Q: 6. +

+ DCOM (distributed COM) is a Windows IPC system designed for use with + the COM object system. It's similar in some ways to DCE and CORBA. +

14.

+ How does D-Bus differ from ZeroC's Internet Communications Engine (Ice) +

+ Start by reading Q: 9. +

+ The Internet + Communications Engine (Ice) is a powerful IPC mechanism more + on the level of SOAP or CORBA than D-Bus. Ice has a "dual-license" + business around it; i.e. you can use it under the GPL, or pay for a + proprietary license. +

15.

+ How does D-Bus differ from Inter-Client Exchange (ICE)? +

+ ICE + was developed for the X Session Management protocol (XSMP), as part of + the X Window System (X11R6.1). The idea was to allow desktop sessions + to contain nongraphical clients in addition to X clients. +

+ ICE is a binary protocol designed for desktop use, and KDE's DCOP + builds on ICE. ICE is substantially simpler than D-Bus (in contrast + to most of the other IPC systems mentioned here, which are more + complex). ICE doesn't really define a mapping to objects and methods + (DCOP adds that layer). The reference implementation of ICE (libICE) + is often considered to be horrible (and horribly insecure). +

+ DCOP and XSMP are the only two widely-used applications of ICE, + and both could in principle be replaced by D-Bus. (Though whether + GNOME and KDE will bother is an open question.) +

16.

+ How does D-Bus differ from DCOP? +

+ Start by reading Q: 9. +

+ D-Bus is intentionally pretty similar to DCOP, + and can be thought of as a "DCOP the next generation" suitable for + sharing between the various open source desktop projects. +

+ D-Bus is a bit more complex than DCOP, though the Qt binding for D-Bus + should not be more complex for programmers. The additional complexity + of D-Bus arises from its separation of object references vs. bus names + vs. interfaces as distinct concepts, and its support for one-to-one + connections in addition to connections over the bus. The libdbus + reference implementation has a lot of API to support multiple bindings + and main loops, and performs data validation and out-of-memory handling + in order to support secure applications such as the systemwide bus. +

+ D-Bus is probably somewhat slower than DCOP due to data validation + and more "layers" in the reference implementation. A comparison + hasn't been posted to the list though. +

+ At this time, KDE has not committed to using D-Bus, but there have + been discussions of KDE bridging D-Bus and DCOP, or even changing + DCOP's implementation to use D-Bus internally (so that GNOME and KDE + would end up using exactly the same bus). See the KDE mailing list + archives for some of these discussions. +

17.

+ How does D-Bus differ from [yet more IPC mechanisms]? +

+ Start by reading Q: 9. +

+ There are countless uses of network sockets in the world. MBUS, Sun ONC/RPC, Jabber/XMPP, + SIP, are some we can think of quickly. +

18.

+ Which IPC mechanism should I use? +

+ Start by reading Q: 9. +

+ If you're writing an Internet or Intranet application, XML-RPC or SOAP + work for many people. These are standard, available for most + languages, simple to debug and easy to use. +

+ If you're writing a desktop application for UNIX, + then D-Bus is of course our recommendation for + talking to other parts of the desktop session. +

+ D-Bus is also designed for communications between system daemons and + communications between the desktop and system daemons. +

+ If you're doing something complicated such as clustering, + distributed swarms, peer-to-peer, or whatever then + the authors of this FAQ don't have expertise in these + areas and you should ask someone else or try a search engine. + D-Bus is most likely a poor choice but could be appropriate + for some things. +

+ Note: the D-Bus mailing list is probably not the place to + discuss which system is appropriate for your application, + though you are welcome to ask specific questions about + D-Bus after reading this FAQ, the tutorial, and + searching the list archives. The best way + to search the list archives is probably to use + an Internet engine such as Google. On Google, + include "site:freedesktop.org" in your search. +

19.

+ How can I submit a bug or patch? +

+ The D-Bus web site + has a link to the bug tracker, which is the best place to store + patches. You can also post them to the list, especially if you want + to discuss the patch or get feedback. +

diff --git a/doc/dbus-faq.xml b/doc/dbus-faq.xml new file mode 100644 index 00000000..69ac3f15 --- /dev/null +++ b/doc/dbus-faq.xml @@ -0,0 +1,674 @@ + + + +
+ + D-Bus FAQ + Version 0.3 + 17 November 2006 + + + Havoc + Pennington + + Red Hat, Inc. +
+ hp@pobox.com +
+
+
+ + David + A + Wheeler + +
+
+ + + + + + + What is D-Bus? + + + + + This is probably best answered by reading the D-Bus tutorial or + the introduction to the specification. In + short, it is a system consisting of 1) a wire protocol for exposing a + typical object-oriented language/framework to other applications; and + 2) a bus daemon that allows applications to find and monitor one another. + Phrased differently, D-Bus is 1) an interprocess communication (IPC) system and 2) some higher-level + structure (lifecycle tracking, service activation, security policy) provided by two bus daemons, + one systemwide and one per-user-session. + + + + + + + + Is D-Bus stable/finished? + + + + + The low-level library "libdbus" and the protocol specification are considered + ABI stable. The README + file has a discussion of the API/ABI stability guarantees. + Higher-level bindings (such as those for Qt, GLib, Python, Java, C#) each + have their own release schedules and degree of maturity, not linked to + the low-level library and bus daemon release. Check the project page for + the binding you're considering to understand that project's policies. + + + + + + + + How is the reference implementation licensed? Can I use it in + proprietary applications? + + + + + The short answer is yes, you can use it in proprietary applications. + You should read the COPYING file, which + offers you the choice of two licenses. These are the GPL and the + AFL. The GPL requires that your application be licensed under the GPL + as well. The AFL is an "X-style" or "BSD-style" license compatible + with proprietary licensing, but it does have some requirements; in + particular it prohibits you from filing a lawsuit alleging that the + D-Bus software infringes your patents while you continue to + use D-Bus. If you're going to sue, you have to stop using + the software. Read the licenses to determine their meaning, this FAQ + entry is not intended to change the meaning or terms of the licenses. + + + + + + + + What is the difference between a bus name, and object path, + and an interface? + + + + + If you imagine a C++ program that implements a network service, then + the bus name is the hostname of the computer running this C++ program, + the object path is a C++ object instance pointer, and an interface is + a C++ class (a pure virtual or abstract class, to be exact). + + + In Java terms, the object path is an object reference, + and an interface is a Java interface. + + + People get confused because if they write an application + with a single object instance and a single interface, + then the bus name, object path, and interface look + redundant. For example, you might have a text editor + that uses the bus name org.freedesktop.TextEditor, + has a global singleton object called + /org/freedesktop/TextEditor, and + that singleton object could implement the interface + org.freedesktop.TextEditor. + + + However, a text editor application could as easily own multiple bus + names (for example, org.kde.KWrite in addition to + generic TextEditor), have multiple objects (maybe + /org/kde/documents/4352 where the number changes + according to the document), and each object could implement multiple + interfaces, such as org.freedesktop.DBus.Introspectable, + org.freedesktop.BasicTextField, + org.kde.RichTextDocument. + + + + + + + + + What is a "service"? + + + + + A service is a program that can be launched by the bus daemon + to provide some functionality to other programs. Services + are normally launched according to the bus name they will + have. + + + People often misuse the word "service" for any + bus name, but this tends to be ambiguous and confusing so is discouraged. + In the D-Bus docs we try to use "service" only when talking about + programs the bus knows how to launch, i.e. a service always has a + .service file. + + + + + + + + Is D-Bus a "component system"? + + + + + It helps to keep these concepts separate in your mind: + + + + Object/component system + + + + + GUI control/widget embedding interfaces + + + + + Interprocess communication system or wire protocol + + + + + + D-Bus is not a component system. "Component system" was originally + defined by COM, and was essentially a workaround for the limitations + of the C++ object system (adding introspection, runtime location of + objects, ABI guarantees, and so forth). With the C# language and CLR, + Microsoft added these features to the primary object system, leaving + COM obsolete. Similarly, Java has much less need for something like + COM than C++ did. Even QObject (from Qt) and GObject (from GLib) offer + some of the same features found in COM. + + + Component systems are not about GUI control embedding. Embedding + a spreadsheet in a word processor document is a matter of defining + some specific interfaces that objects + can implement. These interfaces provide methods related to + GUI controls. So an object implementing those interfaces + can be embedded. + + + The word "component" just means "object with some fancy features" and + in modern languages all objects are effectively "components." + + + So components are fancy objects, and some objects are GUI controls. + + + A third, unrelated feature is interprocess communication or IPC. + D-Bus is an IPC system. Given an object (or "component" if you must), + you can expose the functionality of that object over an IPC system. + Examples of IPC systems are DCOM, CORBA, SOAP, XML-RPC, and D-Bus. + You can use any of these IPC systems with any object/component system, + though some of them are "tuned" for specific object systems. + You can think of an IPC system primarily as a wire protocol. + + + If you combine an IPC system with a set of GUI control interfaces, + then you can have an out-of-process or dynamically-loaded GUI control. + + + Another related concept is the plugin or + extension. Generic plugin systems such as the + Eclipse system are not so different + from component/object systems, though perhaps a "plugin" tends to be a + bundle of objects with a user-visible name and can be + downloaded/packaged as a unit. + + + + + + + + How fast is the D-Bus reference implementation? + + + + + Of course it depends a bit on what you're doing. + + This mail contains some benchmarking. At the time of that + benchmark, D-Bus one-to-one communication was about 2.5x slower than + simply pushing the data raw over a socket. After the recent rewrite of + the marshaling code, D-Bus is slower than that because a lot of + optimization work was lost. But it can probably be sped up again. + + + D-Bus communication with the intermediate bus daemon should be + (and as last profiled, was) about twice as slow as one-to-one + mode, because a round trip involves four socket reads/writes rather + than two socket reads/writes. + + + The overhead comes from a couple of places; part of it is simply + "abstraction penalty" (there are layers of code to support + multiple main loops, multiple transport types, security, etc.). + Probably the largest part comes from data validation + (because the reference implementation does not trust incoming data). + It would be simple to add a "no validation" mode, but probably + not a good idea all things considered. + + + Raw bandwidth isn't the only concern; D-Bus is designed to + enable asynchronous communication and avoid round trips. + This is frequently a more important performance issue + than throughput. + + + + + + + + + How large is the D-Bus reference implementation? + + + + + A production build (with assertions, unit tests, and verbose logging + disabled) is on the order of a 150K shared library. + + + A much, much smaller implementation would be possible by omitting out + of memory handling, hardcoding a main loop (or always using blocking + I/O), skipping validation, and otherwise simplifying things. + + + + + + + + How does D-Bus differ from other interprocess communication + or networking protocols? + + + + + Keep in mind, it is not only an IPC system; it also includes + lifecycle tracking, service activation, security policy, and other + higher-level structure and assumptions. + + + The best place to start is to read the D-Bus tutorial, so + you have a concrete idea what D-Bus actually is. If you + understand other protocols on a wire format level, you + may also want to read the D-Bus specification to see what + D-Bus looks like on a low level. + + + As the tutorial and specification both explain, D-Bus is tuned + for some specific use cases. Thus, it probably isn't tuned + for what you want to do, unless you are doing the things + D-Bus was designed for. Don't make the mistake of thinking + that any system involving "IPC" is the same thing. + + + The D-Bus authors would not recommend using D-Bus + for applications where it doesn't make sense. + The following questions compare D-Bus to some other + protocols primarily to help you understand D-Bus + and decide whether it's appropriate; D-Bus is neither intended + nor claimed to be the right choice for every application. + + + It should be possible to bridge D-Bus to other IPC systems, + just as D-Bus can be bridged to object systems. + + + Note: the D-Bus mailing list subscribers are very much not + interested in debating which IPC system is the One True + System. So if you want to discuss that, please use another forum. + + + + + + + + + How does D-Bus differ from CORBA? + + + + + Start by reading . + + + CORBA is designed to support + object-oriented IPC between objects, automatically marshalling + parameters as necessary. CORBA is strongly supported by the Open Management Group (OMG), which + produces various standards and supporting documents for CORBA and has + the backing of many large organizations. There are many CORBA ORBs + available, both proprietary ORBs and free / open source software ORBs + (the latter include ORBit, MICO, and The ACE Orb (TAO)). Many + organizations continue to use CORBA ORBs for various kinds of IPC. + + + Both GNOME and KDE have used CORBA and then moved away from it. KDE + had more success with a system called DCOP, and GNOME layered a system + called Bonobo on top of CORBA. Without custom extensions, CORBA does + not support many of the things one wants to do in a desktop + environment with the GNOME/KDE architecture. + + + CORBA on the other hand has a number of features of interest for + enterprise and web application development, though XML systems such as + SOAP are the latest fad. + + + Like D-Bus, CORBA uses a fast binary protocol (IIOP). Both systems + work in terms of objects and methods, and have concepts such as + "oneway" calls. Only D-Bus has direct support for "signals" as in + GLib/Qt (or Java listeners, or C# delegates). + + + D-Bus hardcodes and specifies a lot of things that CORBA leaves open-ended, + because CORBA is more generic and D-Bus has two specific use-cases in mind. + This makes D-Bus a bit simpler. + + + However, unlike CORBA D-Bus does not specify the + API for the language bindings. Instead, "native" bindings adapted + specifically to the conventions of a framework such as QObject, + GObject, C#, Java, Python, etc. are encouraged. The libdbus reference + implementation is designed to be a backend for bindings of this + nature, rather than to be used directly. The rationale is that an IPC + system API should not "leak" all over a program; it should come into + play only just before data goes over the wire. As an aside, OMG is + apparently working on a simpler C++ binding for CORBA. + + + Many CORBA implementations such as ORBit are faster than the libdbus + reference implementation. One reason is that D-Bus considers data + from the other end of the connection to be untrusted and extensively + validates it. But generally speaking other priorities were placed + ahead of raw speed in the libdbus implementation. A fast D-Bus + implementation along the lines of ORBit should be possible, of course. + + + On a more trivial note, D-Bus involves substantially fewer acronyms + than CORBA. + + + + + + + + + How does D-Bus differ from XML-RPC and SOAP? + + + + + Start by reading . + + + In SOAP and XML-RPC, RPC calls are transformed + into an XML-based format, then sent over the wire (typically using the + HTTP protocol), where they are processed and returned. XML-RPC is the + simple protocol (its spec is only a page or two), and SOAP is the + full-featured protocol. + + + XML-RPC and SOAP impose XML parsing overhead that is normally + irrelevant in the context of the Internet, but significant for + constant fine-grained IPC among applications in a desktop session. + + + D-Bus offers persistent connections and with the bus daemon + supports lifecycle tracking of other applications connected + to the bus. With XML-RPC and SOAP, typically each method call + exists in isolation and has its own HTTP connection. + + + + + + + + How does D-Bus differ from DCE? + + + + + Start by reading . + + + Distributed Computing + Environment (DCE) is an industry-standard vendor-neutral + standard that includes an IPC mechanism. The Open Group + has released an implementation as open source software. DCE + is quite capable, and includes a vast amount of functionality such as + a distributed time service. As the name implies, DCE is intended for + use in a large, multi-computer distributed application. D-Bus would + not be well-suited for this. + + + + + + + + + How does D-Bus differ from DCOM and COM? + + + + + Start by reading . + + + Comparing D-Bus to COM is apples and oranges; + see . + + + DCOM (distributed COM) is a Windows IPC system designed for use with + the COM object system. It's similar in some ways to DCE and CORBA. + + + + + + + + How does D-Bus differ from ZeroC's Internet Communications Engine (Ice) + + + + + Start by reading . + + + The Internet + Communications Engine (Ice) is a powerful IPC mechanism more + on the level of SOAP or CORBA than D-Bus. Ice has a "dual-license" + business around it; i.e. you can use it under the GPL, or pay for a + proprietary license. + + + + + + + + How does D-Bus differ from Inter-Client Exchange (ICE)? + + + + + ICE + was developed for the X Session Management protocol (XSMP), as part of + the X Window System (X11R6.1). The idea was to allow desktop sessions + to contain nongraphical clients in addition to X clients. + + + ICE is a binary protocol designed for desktop use, and KDE's DCOP + builds on ICE. ICE is substantially simpler than D-Bus (in contrast + to most of the other IPC systems mentioned here, which are more + complex). ICE doesn't really define a mapping to objects and methods + (DCOP adds that layer). The reference implementation of ICE (libICE) + is often considered to be horrible (and horribly insecure). + + + DCOP and XSMP are the only two widely-used applications of ICE, + and both could in principle be replaced by D-Bus. (Though whether + GNOME and KDE will bother is an open question.) + + + + + + + + + + How does D-Bus differ from DCOP? + + + + + Start by reading . + + + D-Bus is intentionally pretty similar to DCOP, + and can be thought of as a "DCOP the next generation" suitable for + sharing between the various open source desktop projects. + + + D-Bus is a bit more complex than DCOP, though the Qt binding for D-Bus + should not be more complex for programmers. The additional complexity + of D-Bus arises from its separation of object references vs. bus names + vs. interfaces as distinct concepts, and its support for one-to-one + connections in addition to connections over the bus. The libdbus + reference implementation has a lot of API to support multiple bindings + and main loops, and performs data validation and out-of-memory handling + in order to support secure applications such as the systemwide bus. + + + D-Bus is probably somewhat slower than DCOP due to data validation + and more "layers" in the reference implementation. A comparison + hasn't been posted to the list though. + + + At this time, KDE has not committed to using D-Bus, but there have + been discussions of KDE bridging D-Bus and DCOP, or even changing + DCOP's implementation to use D-Bus internally (so that GNOME and KDE + would end up using exactly the same bus). See the KDE mailing list + archives for some of these discussions. + + + + + + + + + How does D-Bus differ from [yet more IPC mechanisms]? + + + + + Start by reading . + + + There are countless uses of network sockets in the world. MBUS, Sun ONC/RPC, Jabber/XMPP, + SIP, are some we can think of quickly. + + + + + + + + + Which IPC mechanism should I use? + + + + + Start by reading . + + + If you're writing an Internet or Intranet application, XML-RPC or SOAP + work for many people. These are standard, available for most + languages, simple to debug and easy to use. + + + If you're writing a desktop application for UNIX, + then D-Bus is of course our recommendation for + talking to other parts of the desktop session. + + + D-Bus is also designed for communications between system daemons and + communications between the desktop and system daemons. + + + If you're doing something complicated such as clustering, + distributed swarms, peer-to-peer, or whatever then + the authors of this FAQ don't have expertise in these + areas and you should ask someone else or try a search engine. + D-Bus is most likely a poor choice but could be appropriate + for some things. + + + Note: the D-Bus mailing list is probably not the place to + discuss which system is appropriate for your application, + though you are welcome to ask specific questions about + D-Bus after reading this FAQ, the tutorial, and + searching the list archives. The best way + to search the list archives is probably to use + an Internet engine such as Google. On Google, + include "site:freedesktop.org" in your search. + + + + + + + + + How can I submit a bug or patch? + + + + + The D-Bus web site + has a link to the bug tracker, which is the best place to store + patches. You can also post them to the list, especially if you want + to discuss the patch or get feedback. + + + + + + +
diff --git a/doc/dbus-specification.html b/doc/dbus-specification.html new file mode 100644 index 00000000..18006de5 --- /dev/null +++ b/doc/dbus-specification.html @@ -0,0 +1,2081 @@ +D-Bus Specification

D-Bus Specification

Havoc Pennington

Red Hat, Inc.


+     
+   

Anders Carlsson

CodeFactory AB


+            
+          

Alexander Larsson

Red Hat, Inc.


+            
+          

Version 0.12


Introduction

+ D-Bus is a system for low-latency, low-overhead, easy to use + interprocess communication (IPC). In more detail: +

  • + D-Bus is low-latency because it is designed + to avoid round trips and allow asynchronous operation, much like + the X protocol. +

  • + D-Bus is low-overhead because it uses a + binary protocol, and does not have to convert to and from a text + format such as XML. Because D-Bus is intended for potentially + high-resolution same-machine IPC, not primarily for Internet IPC, + this is an interesting optimization. +

  • + D-Bus is easy to use because it works in terms + of messages rather than byte streams, and + automatically handles a lot of the hard IPC issues. Also, the D-Bus + library is designed to be wrapped in a way that lets developers use + their framework's existing object/type system, rather than learning + a new one specifically for IPC. +

+

+ The base D-Bus protocol is a one-to-one (peer-to-peer or client-server) + protocol, specified in the section called “Message Protocol”. That is, it is + a system for one application to talk to a single other + application. However, the primary intended application of the protocol is the + D-Bus message bus, specified in the section called “Message Bus Specification”. The message bus is a special application that + accepts connections from multiple other applications, and forwards + messages among them. +

+ Uses of D-Bus include notification of system changes (notification of when + a camera is plugged in to a computer, or a new version of some software + has been installed), or desktop interoperability, for example a file + monitoring service or a configuration service. +

+ D-Bus is designed for two specific use cases: +

  • + A "system bus" for notifications from the system to user sessions, + and to allow the system to request input from user sessions. +

  • + A "session bus" used to implement desktop environments such as + GNOME and KDE. +

+ D-Bus is not intended to be a generic IPC system for any possible + application, and intentionally omits many features found in other + IPC systems for this reason. +

+ At the same time, the bus daemons offer a number of features not found in + other IPC systems, such as single-owner "bus names" (similar to X + selections), on-demand startup of services, and security policies. + In many ways, these features are the primary motivation for developing + D-Bus; other systems would have sufficed if IPC were the only goal. +

+ D-Bus may turn out to be useful in unanticipated applications, but future + versions of this spec and the reference implementation probably will not + incorporate features that interfere with the core use cases. +

+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119. However, the + document could use a serious audit to be sure it makes sense to do + so. Also, they are not capitalized. +

Protocol and Specification Stability

+ The D-Bus protocol is frozen (only compatible extensions are allowed) as + of November 8, 2006. However, this specification could still use a fair + bit of work to make interoperable reimplementation possible without + reference to the D-Bus reference implementation. Thus, this + specification is not marked 1.0. To mark it 1.0, we'd like to see + someone invest significant effort in clarifying the specification + language, and growing the specification to cover more aspects of the + reference implementation's behavior. +

+ Until this work is complete, any attempt to reimplement D-Bus will + probably require looking at the reference implementation and/or asking + questions on the D-Bus mailing list about intended behavior. + Questions on the list are very welcome. +

+ Nonetheless, this document should be a useful starting point and is + to our knowledge accurate, though incomplete. +

Message Protocol

+ A message consists of a + header and a body. If you + think of a message as a package, the header is the address, and the body + contains the package contents. The message delivery system uses the header + information to figure out where to send the message and how to interpret + it; the recipient interprets the body of the message. +

+ The body of the message is made up of zero or more + arguments, which are typed values, such as an + integer or a byte array. +

+ Both header and body use the same type system and format for + serializing data. Each type of value has a wire format. + Converting a value from some other representation into the wire + format is called marshaling and converting + it back from the wire format is unmarshaling. +

Type Signatures

+ The D-Bus protocol does not include type tags in the marshaled data; a + block of marshaled values must have a known type + signature. The type signature is made up of type + codes. A type code is an ASCII character representing the + type of a value. Because ASCII characters are used, the type signature + will always form a valid ASCII string. A simple string compare + determines whether two type signatures are equivalent. +

+ As a simple example, the type code for 32-bit integer (INT32) is + the ASCII character 'i'. So the signature for a block of values + containing a single INT32 would be: +

+          "i"
+        

+ A block of values containing two INT32 would have this signature: +

+          "ii"
+        

+

+ All basic types work like + INT32 in this example. To marshal and unmarshal + basic types, you simply read one value from the data + block corresponding to each type code in the signature. + In addition to basic types, there are four container + types: STRUCT, ARRAY, VARIANT, + and DICT_ENTRY. +

+ STRUCT has a type code, ASCII character 'r', but this type + code does not appear in signatures. Instead, ASCII characters + '(' and ')' are used to mark the beginning and end of the struct. + So for example, a struct containing two integers would have this + signature: +

+          "(ii)"
+        

+ Structs can be nested, so for example a struct containing + an integer and another struct: +

+          "(i(ii))"
+        

+ The value block storing that struct would contain three integers; the + type signature allows you to distinguish "(i(ii))" from "((ii)i)" or + "(iii)" or "iii". +

+ The STRUCT type code 'r' is not currently used in the D-Bus protocol, + but is useful in code that implements the protocol. This type code + is specified to allow such code to interoperate in non-protocol contexts. +

+ Empty structures are not allowed; there must be at least one + type code between the parentheses. +

+ ARRAY has ASCII character 'a' as type code. The array type code must be + followed by a single complete type. The single + complete type following the array is the type of each array element. So + the simple example is: +

+          "ai"
+        

+ which is an array of 32-bit integers. But an array can be of any type, + such as this array-of-struct-with-two-int32-fields: +

+          "a(ii)"
+        

+ Or this array of array of integer: +

+          "aai"
+        

+

+ The phrase single complete type deserves some + definition. A single complete type is a basic type code, a variant type code, + an array with its element type, or a struct with its fields. + So the following signatures are not single complete types: +

+          "aa"
+        

+

+          "(ii"
+        

+

+          "ii)"
+        

+ And the following signatures contain multiple complete types: +

+          "ii"
+        

+

+          "aiai"
+        

+

+          "(ii)(ii)"
+        

+ Note however that a single complete type may contain + multiple other single complete types. +

+ VARIANT has ASCII character 'v' as its type code. A marshaled value of + type VARIANT will have the signature of a single complete type as part + of the value. This signature will be followed by a + marshaled value of that type. +

+ A DICT_ENTRY works exactly like a struct, but rather + than parentheses it uses curly braces, and it has more restrictions. + The restrictions are: it occurs only as an array element type; it has + exactly two single complete types inside the curly braces; the first + single complete type (the "key") must be a basic type rather than a + container type. Implementations must not accept dict entries outside of + arrays, must not accept dict entries with zero, one, or more than two + fields, and must not accept dict entries with non-basic-typed keys. A + dict entry is always a key-value pair. +

+ The first field in the DICT_ENTRY is always the key. + A message is considered corrupt if the same key occurs twice in the same + array of DICT_ENTRY. However, for performance reasons + implementations are not required to reject dicts with duplicate keys. +

+ In most languages, an array of dict entry would be represented as a + map, hash table, or dict object. +

+ The following table summarizes the D-Bus types. +

Conventional NameCodeDescription
INVALID0 (ASCII NUL)Not a valid type code, used to terminate signatures
BYTE121 (ASCII 'y')8-bit unsigned integer
BOOLEAN98 (ASCII 'b')Boolean value, 0 is FALSE and 1 is TRUE. Everything else is invalid.
INT16110 (ASCII 'n')16-bit signed integer
UINT16113 (ASCII 'q')16-bit unsigned integer
INT32105 (ASCII 'i')32-bit signed integer
UINT32117 (ASCII 'u')32-bit unsigned integer
INT64120 (ASCII 'x')64-bit signed integer
UINT64116 (ASCII 't')64-bit unsigned integer
DOUBLE100 (ASCII 'd')IEEE 754 double
STRING115 (ASCII 's')UTF-8 string (must be valid UTF-8). Must be nul terminated and contain no other nul bytes.
OBJECT_PATH111 (ASCII 'o')Name of an object instance
SIGNATURE103 (ASCII 'g')A type signature
ARRAY97 (ASCII 'a')Array
STRUCT114 (ASCII 'r'), 40 (ASCII '('), 41 (ASCII ')')Struct
VARIANT118 (ASCII 'v') Variant type (the type of the value is part of the value itself)
DICT_ENTRY101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}') Entry in a dict or map (array of key-value pairs)

+

Marshaling (Wire Format)

+ Given a type signature, a block of bytes can be converted into typed + values. This section describes the format of the block of bytes. Byte + order and alignment issues are handled uniformly for all D-Bus types. +

+ A block of bytes has an associated byte order. The byte order + has to be discovered in some way; for D-Bus messages, the + byte order is part of the message header as described in + the section called “Message Format”. For now, assume + that the byte order is known to be either little endian or big + endian. +

+ Each value in a block of bytes is aligned "naturally," for example + 4-byte values are aligned to a 4-byte boundary, and 8-byte values to an + 8-byte boundary. To properly align a value, alignment + padding may be necessary. The alignment padding must always + be the minimum required padding to properly align the following value; + and it must always be made up of nul bytes. The alignment padding must + not be left uninitialized (it can't contain garbage), and more padding + than required must not be used. +

+ Given all this, the types are marshaled on the wire as follows: +

Conventional NameEncodingAlignment
INVALIDNot applicable; cannot be marshaled.N/A
BYTEA single 8-bit byte.1
BOOLEANAs for UINT32, but only 0 and 1 are valid values.4
INT1616-bit signed integer in the message's byte order.2
UINT1616-bit unsigned integer in the message's byte order.2
INT3232-bit signed integer in the message's byte order.4
UINT3232-bit unsigned integer in the message's byte order.4
INT6464-bit signed integer in the message's byte order.8
UINT6464-bit unsigned integer in the message's byte order.8
DOUBLE64-bit IEEE 754 double in the message's byte order.8
STRINGA UINT32 indicating the string's + length in bytes excluding its terminating nul, followed by + non-nul string data of the given length, followed by a terminating nul + byte. + + 4 (for the length) +
OBJECT_PATHExactly the same as STRING except the + content must be a valid object path (see below). + + 4 (for the length) +
SIGNATUREThe same as STRING except the length is a single + byte (thus signatures have a maximum length of 255) + and the content must be a valid signature (see below). + + 1 +
ARRAY + A UINT32 giving the length of the array data in bytes, followed by + alignment padding to the alignment boundary of the array element type, + followed by each array element. The array length is from the + end of the alignment padding to the end of the last element, + i.e. it does not include the padding after the length, + or any padding after the last element. + Arrays have a maximum length defined to be 2 to the 26th power or + 67108864. Implementations must not send or accept arrays exceeding this + length. + + 4 (for the length) +
STRUCT + A struct must start on an 8-byte boundary regardless of the + type of the struct fields. The struct value consists of each + field marshaled in sequence starting from that 8-byte + alignment boundary. + + 8 +
VARIANT + A variant type has a marshaled SIGNATURE + followed by a marshaled value with the type + given in the signature. + Unlike a message signature, the variant signature + can contain only a single complete type. + So "i", "ai" or "(ii)" is OK, but "ii" is not. + + 1 (alignment of the signature) +
DICT_ENTRY + Identical to STRUCT. + + 8 +

+

Valid Object Paths

+ An object path is a name used to refer to an object instance. + Conceptually, each participant in a D-Bus message exchange may have + any number of object instances (think of C++ or Java objects) and each + such instance will have a path. Like a filesystem, the object + instances in an application form a hierarchical tree. +

+ The following rules define a valid object path. Implementations must + not send or accept messages with invalid object paths. +

  • + The path may be of any length. +

  • + The path must begin with an ASCII '/' (integer 47) character, + and must consist of elements separated by slash characters. +

  • + Each element must only contain the ASCII characters + "[A-Z][a-z][0-9]_" +

  • + No element may be the empty string. +

  • + Multiple '/' characters cannot occur in sequence. +

  • + A trailing '/' character is not allowed unless the + path is the root path (a single '/' character). +

+

Valid Signatures

+ An implementation must not send or accept invalid signatures. + Valid signatures will conform to the following rules: +

  • + The signature ends with a nul byte. +

  • + The signature is a list of single complete types. + Arrays must have element types, and structs must + have both open and close parentheses. +

  • + Only type codes and open and close parentheses are + allowed in the signature. The STRUCT type code + is not allowed in signatures, because parentheses + are used instead. +

  • + The maximum depth of container type nesting is 32 array type + codes and 32 open parentheses. This implies that the maximum + total depth of recursion is 64, for an "array of array of array + of ... struct of struct of struct of ..." where there are 32 + array and 32 struct. +

  • + The maximum length of a signature is 255. +

  • + Signatures must be nul-terminated. +

+

Message Format

+ A message consists of a header and a body. The header is a block of + values with a fixed signature and meaning. The body is a separate block + of values, with a signature specified in the header. +

+ The length of the header must be a multiple of 8, allowing the body to + begin on an 8-byte boundary when storing the entire message in a single + buffer. If the header does not naturally end on an 8-byte boundary + up to 7 bytes of nul-initialized alignment padding must be added. +

+ The message body need not end on an 8-byte boundary. +

+ The maximum length of a message, including header, header alignment padding, + and body is 2 to the 27th power or 134217728. Implementations must not + send or accept messages exceeding this size. +

+ The signature of the header is: +

+          "yyyyuua(yv)"
+        

+ Written out more readably, this is: +

+          BYTE, BYTE, BYTE, BYTE, UINT32, UINT32, ARRAY of STRUCT of (BYTE,VARIANT)
+        

+

+ These values have the following meanings: +

ValueDescription
1st BYTEEndianness flag; ASCII 'l' for little-endian + or ASCII 'B' for big-endian. Both header and body are + in this endianness.
2nd BYTEMessage type. Unknown types must be ignored. + Currently-defined types are described below. +
3rd BYTEBitwise OR of flags. Unknown flags + must be ignored. Currently-defined flags are described below. +
4th BYTEMajor protocol version of the sending application. If + the major protocol version of the receiving application does not + match, the applications will not be able to communicate and the + D-Bus connection must be disconnected. The major protocol + version for this version of the specification is 1. +
1st UINT32Length in bytes of the message body, starting + from the end of the header. The header ends after + its alignment padding to an 8-boundary. +
2nd UINT32The serial of this message, used as a cookie + by the sender to identify the reply corresponding + to this request. This must not be zero. +
ARRAY of STRUCT of (BYTE,VARIANT)An array of zero or more header + fields where the byte is the field code, and the + variant is the field value. The message type determines + which fields are required. +

+

+ Message types that can appear in the second byte + of the header are: +

Conventional nameDecimal valueDescription
INVALID0This is an invalid type.
METHOD_CALL1Method call.
METHOD_RETURN2Method reply with returned data.
ERROR3Error reply. If the first argument exists and is a + string, it is an error message.
SIGNAL4Signal emission.

+

+ Flags that can appear in the third byte of the header: +

Conventional nameHex valueDescription
NO_REPLY_EXPECTED0x1This message does not expect method return replies or + error replies; the reply can be omitted as an + optimization. However, it is compliant with this specification + to return the reply despite this flag and the only harm + from doing so is extra network traffic. +
NO_AUTO_START0x2The bus must not launch an owner + for the destination name in response to this message. +

+

Header Fields

+ The array at the end of the header contains header + fields, where each field is a 1-byte field code followed + by a field value. A header must contain the required header fields for + its message type, and zero or more of any optional header + fields. Future versions of this protocol specification may add new + fields. Implementations must ignore fields they do not + understand. Implementations must not invent their own header fields; + only changes to this specification may introduce new header fields. +

+ Again, if an implementation sees a header field code that it does not + expect, it must ignore that field, as it will be part of a new + (but compatible) version of this specification. This also applies + to known header fields appearing in unexpected messages, for + example: if a signal has a reply serial it must be ignored + even though it has no meaning as of this version of the spec. +

+ However, implementations must not send or accept known header fields + with the wrong type stored in the field value. So for example a + message with an INTERFACE field of type + UINT32 would be considered corrupt. +

+ Here are the currently-defined header fields: +

Conventional NameDecimal CodeTypeRequired InDescription
INVALID0N/Anot allowedNot a valid field name (error if it appears in a message)
PATH1OBJECT_PATHMETHOD_CALL, SIGNALThe object to send a call to, + or the object a signal is emitted from. + The special path + /org/freedesktop/DBus/Local is reserved; + implementations should not send messages with this path, + and the reference implementation of the bus daemon will + disconnect any application that attempts to do so. +
INTERFACE2STRINGSIGNAL + The interface to invoke a method call on, or + that a signal is emitted from. Optional for + method calls, required for signals. + The special interface + org.freedesktop.DBus.Local is reserved; + implementations should not send messages with this + interface, and the reference implementation of the bus + daemon will disconnect any application that attempts to + do so. +
MEMBER3STRINGMETHOD_CALL, SIGNALThe member, either the method name or signal name.
ERROR_NAME4STRINGERRORThe name of the error that occurred, for errors
REPLY_SERIAL5UINT32ERROR, METHOD_RETURNThe serial number of the message this message is a reply + to. (The serial number is the second UINT32 in the header.)
DESTINATION6STRINGoptionalThe name of the connection this message is intended for. + Only used in combination with the message bus, see + the section called “Message Bus Specification”.
SENDER7STRINGoptionalUnique name of the sending connection. + The message bus fills in this field so it is reliable; the field is + only meaningful in combination with the message bus.
SIGNATURE8SIGNATUREoptionalThe signature of the message body. + If omitted, it is assumed to be the + empty signature "" (i.e. the body must be 0-length).

+

Valid Names

+ The various names in D-Bus messages have some restrictions. +

+ There is a maximum name length + of 255 which applies to bus names, interfaces, and members. +

Interface names

+ Interfaces have names with type STRING, meaning that + they must be valid UTF-8. However, there are also some + additional restrictions that apply to interface names + specifically: +

  • Interface names are composed of 1 or more elements separated by + a period ('.') character. All elements must contain at least + one character. +

  • Each element must only contain the ASCII characters + "[A-Z][a-z][0-9]_" and must not begin with a digit. +

  • Interface names must contain at least one '.' (period) + character (and thus at least two elements). +

  • Interface names must not begin with a '.' (period) character.

  • Interface names must not exceed the maximum name length.

+

Bus names

+ Connections have one or more bus names associated with them. + A connection has exactly one bus name that is a unique connection + name. The unique connection name remains with the connection for + its entire lifetime. + A bus name is of type STRING, + meaning that it must be valid UTF-8. However, there are also + some additional restrictions that apply to bus names + specifically: +

  • Bus names that start with a colon (':') + character are unique connection names. +

  • Bus names are composed of 1 or more elements separated by + a period ('.') character. All elements must contain at least + one character. +

  • Each element must only contain the ASCII characters + "[A-Z][a-z][0-9]_-". Only elements that are part of a unique + connection name may begin with a digit, elements in + other bus names must not begin with a digit. +

  • Bus names must contain at least one '.' (period) + character (and thus at least two elements). +

  • Bus names must not begin with a '.' (period) character.

  • Bus names must not exceed the maximum name length.

+

+ Note that the hyphen ('-') character is allowed in bus names but + not in interface names. +

Member names

+ Member (i.e. method or signal) names: +

  • Must only contain the ASCII characters + "[A-Z][a-z][0-9]_" and may not begin with a + digit.

  • Must not contain the '.' (period) character.

  • Must not exceed the maximum name length.

  • Must be at least 1 byte in length.

+

Error names

+ Error names have the same restrictions as interface names. +

Message Types

+ Each of the message types (METHOD_CALL, METHOD_RETURN, ERROR, and + SIGNAL) has its own expected usage conventions and header fields. + This section describes these conventions. +

Method Calls

+ Some messages invoke an operation on a remote object. These are + called method call messages and have the type tag METHOD_CALL. Such + messages map naturally to methods on objects in a typical program. +

+ A method call message is required to have a MEMBER header field + indicating the name of the method. Optionally, the message has an + INTERFACE field giving the interface the method is a part of. In the + absence of an INTERFACE field, if two interfaces on the same object have + a method with the same name, it is undefined which of the two methods + will be invoked. Implementations may also choose to return an error in + this ambiguous case. However, if a method name is unique + implementations must not require an interface field. +

+ Method call messages also include a PATH field + indicating the object to invoke the method on. If the call is passing + through a message bus, the message will also have a + DESTINATION field giving the name of the connection + to receive the message. +

+ When an application handles a method call message, it is required to + return a reply. The reply is identified by a REPLY_SERIAL header field + indicating the serial number of the METHOD_CALL being replied to. The + reply can have one of two types; either METHOD_RETURN or ERROR. +

+ If the reply has type METHOD_RETURN, the arguments to the reply message + are the return value(s) or "out parameters" of the method call. + If the reply has type ERROR, then an "exception" has been thrown, + and the call fails; no return value will be provided. It makes + no sense to send multiple replies to the same method call. +

+ Even if a method call has no return values, a METHOD_RETURN + reply is required, so the caller will know the method + was successfully processed. +

+ The METHOD_RETURN or ERROR reply message must have the REPLY_SERIAL + header field. +

+ If a METHOD_CALL message has the flag NO_REPLY_EXPECTED, + then as an optimization the application receiving the method + call may choose to omit the reply message (regardless of + whether the reply would have been METHOD_RETURN or ERROR). + However, it is also acceptable to ignore the NO_REPLY_EXPECTED + flag and reply anyway. +

+ Unless a message has the flag NO_AUTO_START, if the + destination name does not exist then a program to own the destination + name will be started before the message is delivered. The message + will be held until the new program is successfully started or has + failed to start; in case of failure, an error will be returned. This + flag is only relevant in the context of a message bus, it is ignored + during one-to-one communication with no intermediate bus. +

Mapping method calls to native APIs

+ APIs for D-Bus may map method calls to a method call in a specific + programming language, such as C++, or may map a method call written + in an IDL to a D-Bus message. +

+ In APIs of this nature, arguments to a method are often termed "in" + (which implies sent in the METHOD_CALL), or "out" (which implies + returned in the METHOD_RETURN). Some APIs such as CORBA also have + "inout" arguments, which are both sent and received, i.e. the caller + passes in a value which is modified. Mapped to D-Bus, an "inout" + argument is equivalent to an "in" argument, followed by an "out" + argument. You can't pass things "by reference" over the wire, so + "inout" is purely an illusion of the in-process API. +

+ Given a method with zero or one return values, followed by zero or more + arguments, where each argument may be "in", "out", or "inout", the + caller constructs a message by appending each "in" or "inout" argument, + in order. "out" arguments are not represented in the caller's message. +

+ The recipient constructs a reply by appending first the return value + if any, then each "out" or "inout" argument, in order. + "in" arguments are not represented in the reply message. +

+ Error replies are normally mapped to exceptions in languages that have + exceptions. +

+ In converting from native APIs to D-Bus, it is perhaps nice to + map D-Bus naming conventions ("FooBar") to native conventions + such as "fooBar" or "foo_bar" automatically. This is OK + as long as you can say that the native API is one that + was specifically written for D-Bus. It makes the most sense + when writing object implementations that will be exported + over the bus. Object proxies used to invoke remote D-Bus + objects probably need the ability to call any D-Bus method, + and thus a magic name mapping like this could be a problem. +

+ This specification doesn't require anything of native API bindings; + the preceding is only a suggested convention for consistency + among bindings. +

Signal Emission

+ Unlike method calls, signal emissions have no replies. + A signal emission is simply a single message of type SIGNAL. + It must have three header fields: PATH giving the object + the signal was emitted from, plus INTERFACE and MEMBER giving + the fully-qualified name of the signal. The INTERFACE header is required + for signals, though it is optional for method calls. +

Errors

+ Messages of type ERROR are most commonly replies + to a METHOD_CALL, but may be returned in reply + to any kind of message. The message bus for example + will return an ERROR in reply to a signal emission if + the bus does not have enough memory to send the signal. +

+ An ERROR may have any arguments, but if the first + argument is a STRING, it must be an error message. + The error message may be logged or shown to the user + in some way. +

Notation in this document

+ This document uses a simple pseudo-IDL to describe particular method + calls and signals. Here is an example of a method call: +

+            org.freedesktop.DBus.StartServiceByName (in STRING name, in UINT32 flags,
+                                                     out UINT32 resultcode)
+          

+ This means INTERFACE = org.freedesktop.DBus, MEMBER = StartServiceByName, + METHOD_CALL arguments are STRING and UINT32, METHOD_RETURN argument + is UINT32. Remember that the MEMBER field can't contain any '.' (period) + characters so it's known that the last part of the name in + the "IDL" is the member name. +

+ In C++ that might end up looking like this: +

+            unsigned int org::freedesktop::DBus::StartServiceByName (const char  *name,
+                                                                     unsigned int flags);
+          

+ or equally valid, the return value could be done as an argument: +

+            void org::freedesktop::DBus::StartServiceByName (const char   *name, 
+                                                             unsigned int  flags,
+                                                             unsigned int *resultcode);
+          

+ It's really up to the API designer how they want to make + this look. You could design an API where the namespace wasn't used + in C++, using STL or Qt, using varargs, or whatever you wanted. +

+ Signals are written as follows: +

+            org.freedesktop.DBus.NameLost (STRING name)
+          

+ Signals don't specify "in" vs. "out" because only + a single direction is possible. +

+ It isn't especially encouraged to use this lame pseudo-IDL in actual + API implementations; you might use the native notation for the + language you're using, or you might use COM or CORBA IDL, for example. +

Invalid Protocol and Spec Extensions

+ For security reasons, the D-Bus protocol should be strictly parsed and + validated, with the exception of defined extension points. Any invalid + protocol or spec violations should result in immediately dropping the + connection without notice to the other end. Exceptions should be + carefully considered, e.g. an exception may be warranted for a + well-understood idiosyncrasy of a widely-deployed implementation. In + cases where the other end of a connection is 100% trusted and known to + be friendly, skipping validation for performance reasons could also make + sense in certain cases. +

+ Generally speaking violations of the "must" requirements in this spec + should be considered possible attempts to exploit security, and violations + of the "should" suggestions should be considered legitimate (though perhaps + they should generate an error in some cases). +

+ The following extension points are built in to D-Bus on purpose and must + not be treated as invalid protocol. The extension points are intended + for use by future versions of this spec, they are not intended for third + parties. At the moment, the only way a third party could extend D-Bus + without breaking interoperability would be to introduce a way to negotiate new + feature support as part of the auth protocol, using EXTENSION_-prefixed + commands. There is not yet a standard way to negotiate features. +

  • + In the authentication protocol (see the section called “Authentication Protocol”) unknown + commands result in an ERROR rather than a disconnect. This enables + future extensions to the protocol. Commands starting with EXTENSION_ are + reserved for third parties. +

  • + The authentication protocol supports pluggable auth mechanisms. +

  • + The address format (see the section called “Server Addresses”) supports new + kinds of transport. +

  • + Messages with an unknown type (something other than + METHOD_CALL, METHOD_RETURN, + ERROR, SIGNAL) are ignored. + Unknown-type messages must still be well-formed in the same way + as the known messages, however. They still have the normal + header and body. +

  • + Header fields with an unknown or unexpected field code must be ignored, + though again they must still be well-formed. +

  • + New standard interfaces (with new methods and signals) can of course be added. +

+

Authentication Protocol

+ Before the flow of messages begins, two applications must + authenticate. A simple plain-text protocol is used for + authentication; this protocol is a SASL profile, and maps fairly + directly from the SASL specification. The message encoding is + NOT used here, only plain text messages. +

+ In examples, "C:" and "S:" indicate lines sent by the client and + server respectively. +

Protocol Overview

+ The protocol is a line-based protocol, where each line ends with + \r\n. Each line begins with an all-caps ASCII command name containing + only the character range [A-Z_], a space, then any arguments for the + command, then the \r\n ending the line. The protocol is + case-sensitive. All bytes must be in the ASCII character set. + + Commands from the client to the server are as follows: + +

  • AUTH [mechanism] [initial-response]

  • CANCEL

  • BEGIN

  • DATA <data in hex encoding>

  • ERROR [human-readable error explanation]

+ + From server to client are as follows: + +

  • REJECTED <space-separated list of mechanism names>

  • OK <GUID in hex>

  • DATA <data in hex encoding>

  • ERROR

+

+ Unofficial extensions to the command set must begin with the letters + "EXTENSION_", to avoid conflicts with future official commands. + For example, "EXTENSION_COM_MYDOMAIN_DO_STUFF". +

Special credentials-passing nul byte

+ Immediately after connecting to the server, the client must send a + single nul byte. This byte may be accompanied by credentials + information on some operating systems that use sendmsg() with + SCM_CREDS or SCM_CREDENTIALS to pass credentials over UNIX domain + sockets. However, the nul byte must be sent even on other kinds of + socket, and even on operating systems that do not require a byte to be + sent in order to transmit credentials. The text protocol described in + this document begins after the single nul byte. If the first byte + received from the client is not a nul byte, the server may disconnect + that client. +

+ A nul byte in any context other than the initial byte is an error; + the protocol is ASCII-only. +

+ The credentials sent along with the nul byte may be used with the + SASL mechanism EXTERNAL. +

AUTH command

+ If an AUTH command has no arguments, it is a request to list + available mechanisms. The server must respond with a REJECTED + command listing the mechanisms it understands, or with an error. +

+ If an AUTH command specifies a mechanism, and the server supports + said mechanism, the server should begin exchanging SASL + challenge-response data with the client using DATA commands. +

+ If the server does not support the mechanism given in the AUTH + command, it must send either a REJECTED command listing the mechanisms + it does support, or an error. +

+ If the [initial-response] argument is provided, it is intended for use + with mechanisms that have no initial challenge (or an empty initial + challenge), as if it were the argument to an initial DATA command. If + the selected mechanism has an initial challenge and [initial-response] + was provided, the server should reject authentication by sending + REJECTED. +

+ If authentication succeeds after exchanging DATA commands, + an OK command must be sent to the client. +

+ The first octet received by the client after the \r\n of the OK + command must be the first octet of the authenticated/encrypted + stream of D-Bus messages. +

+ The first octet received by the server after the \r\n of the BEGIN + command from the client must be the first octet of the + authenticated/encrypted stream of D-Bus messages. +

CANCEL Command

+ At any time up to sending the BEGIN command, the client may send a + CANCEL command. On receiving the CANCEL command, the server must + send a REJECTED command and abort the current authentication + exchange. +

DATA Command

+ The DATA command may come from either client or server, and simply + contains a hex-encoded block of data to be interpreted + according to the SASL mechanism in use. +

+ Some SASL mechanisms support sending an "empty string"; + FIXME we need some way to do this. +

BEGIN Command

+ The BEGIN command acknowledges that the client has received an + OK command from the server, and that the stream of messages + is about to begin. +

+ The first octet received by the server after the \r\n of the BEGIN + command from the client must be the first octet of the + authenticated/encrypted stream of D-Bus messages. +

REJECTED Command

+ The REJECTED command indicates that the current authentication + exchange has failed, and further exchange of DATA is inappropriate. + The client would normally try another mechanism, or try providing + different responses to challenges. +

+ Optionally, the REJECTED command has a space-separated list of + available auth mechanisms as arguments. If a server ever provides + a list of supported mechanisms, it must provide the same list + each time it sends a REJECTED message. Clients are free to + ignore all lists received after the first. +

OK Command

+ The OK command indicates that the client has been authenticated, + and that further communication will be a stream of D-Bus messages + (optionally encrypted, as negotiated) rather than this protocol. +

+ The first octet received by the client after the \r\n of the OK + command must be the first octet of the authenticated/encrypted + stream of D-Bus messages. +

+ The client must respond to the OK command by sending a BEGIN + command, followed by its stream of messages, or by disconnecting. + The server must not accept additional commands using this protocol + after the OK command has been sent. +

+ The OK command has one argument, which is the GUID of the server. + See the section called “Server Addresses” for more on server GUIDs. +

ERROR Command

+ The ERROR command indicates that either server or client did not + know a command, does not accept the given command in the current + context, or did not understand the arguments to the command. This + allows the protocol to be extended; a client or server can send a + command present or permitted only in new protocol versions, and if + an ERROR is received instead of an appropriate response, fall back + to using some other technique. +

+ If an ERROR is sent, the server or client that sent the + error must continue as if the command causing the ERROR had never been + received. However, the the server or client receiving the error + should try something other than whatever caused the error; + if only canceling/rejecting the authentication. +

+ If the D-Bus protocol changes incompatibly at some future time, + applications implementing the new protocol would probably be able to + check for support of the new protocol by sending a new command and + receiving an ERROR from applications that don't understand it. Thus the + ERROR feature of the auth protocol is an escape hatch that lets us + negotiate extensions or changes to the D-Bus protocol in the future. +

Authentication examples

+

Figure 1. Example of successful magic cookie authentication

+            (MAGIC_COOKIE is a made up mechanism)
+
+            C: AUTH MAGIC_COOKIE 3138363935333137393635383634
+            S: OK 1234deadbeef
+            C: BEGIN
+          


+

Figure 2. Example of finding out mechanisms then picking one

+            C: AUTH
+            S: REJECTED KERBEROS_V4 SKEY
+            C: AUTH SKEY 7ab83f32ee
+            S: DATA 8799cabb2ea93e
+            C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f
+            S: OK 1234deadbeef
+            C: BEGIN
+          


+

Figure 3. Example of client sends unknown command then falls back to regular auth

+            C: FOOBAR
+            S: ERROR
+            C: AUTH MAGIC_COOKIE 3736343435313230333039
+            S: OK 1234deadbeef
+            C: BEGIN
+          


+

Figure 4. Example of server doesn't support initial auth mechanism

+            C: AUTH MAGIC_COOKIE 3736343435313230333039
+            S: REJECTED KERBEROS_V4 SKEY
+            C: AUTH SKEY 7ab83f32ee
+            S: DATA 8799cabb2ea93e
+            C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f
+            S: OK 1234deadbeef
+            C: BEGIN
+          


+

Figure 5. Example of wrong password or the like followed by successful retry

+            C: AUTH MAGIC_COOKIE 3736343435313230333039
+            S: REJECTED KERBEROS_V4 SKEY
+            C: AUTH SKEY 7ab83f32ee
+            S: DATA 8799cabb2ea93e
+            C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f
+            S: REJECTED
+            C: AUTH SKEY 7ab83f32ee
+            S: DATA 8799cabb2ea93e
+            C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f
+            S: OK 1234deadbeef
+            C: BEGIN
+          


+

Figure 6. Example of skey cancelled and restarted

+            C: AUTH MAGIC_COOKIE 3736343435313230333039
+            S: REJECTED KERBEROS_V4 SKEY
+            C: AUTH SKEY 7ab83f32ee
+            S: DATA 8799cabb2ea93e
+            C: CANCEL
+            S: REJECTED
+            C: AUTH SKEY 7ab83f32ee
+            S: DATA 8799cabb2ea93e
+            C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f
+            S: OK 1234deadbeef
+            C: BEGIN
+          


+

Authentication state diagrams

+ This section documents the auth protocol in terms of + a state machine for the client and the server. This is + probably the most robust way to implement the protocol. +

Client states

+ To more precisely describe the interaction between the + protocol state machine and the authentication mechanisms the + following notation is used: MECH(CHALL) means that the + server challenge CHALL was fed to the mechanism MECH, which + returns one of + +

  • + CONTINUE(RESP) means continue the auth conversation + and send RESP as the response to the server; +

  • + OK(RESP) means that after sending RESP to the server + the client side of the auth conversation is finished + and the server should return "OK"; +

  • + ERROR means that CHALL was invalid and could not be + processed. +

+ + Both RESP and CHALL may be empty. +

+ The Client starts by getting an initial response from the + default mechanism and sends AUTH MECH RESP, or AUTH MECH if + the mechanism did not provide an initial response. If the + mechanism returns CONTINUE, the client starts in state + WaitingForData, if the mechanism + returns OK the client starts in state + WaitingForOK. +

+ The client should keep track of available mechanisms and + which it mechanisms it has already attempted. This list is + used to decide which AUTH command to send. When the list is + exhausted, the client should give up and close the + connection. +

WaitingForData +

  • + Receive DATA CHALL +

    + MECH(CHALL) returns CONTINUE(RESP) → send + DATA RESP, goto + WaitingForData +
    + MECH(CHALL) returns OK(RESP) → send DATA + RESP, goto WaitingForOK +
    + MECH(CHALL) returns ERROR → send ERROR + [msg], goto WaitingForData +

    +

  • + Receive REJECTED [mechs] → + send AUTH [next mech], goto + WaitingForData or WaitingForOK +

  • + Receive ERROR → send + CANCEL, goto + WaitingForReject +

  • + Receive OK → send + BEGIN, terminate auth + conversation, authenticated +

  • + Receive anything else → send + ERROR, goto + WaitingForData +

+

WaitingForOK +

  • + Receive OK → send BEGIN, terminate auth + conversation, authenticated +

  • + Receive REJECT [mechs] → send AUTH [next mech], + goto WaitingForData or + WaitingForOK +

  • + Receive DATA → send CANCEL, goto + WaitingForReject +

  • + Receive ERROR → send CANCEL, goto + WaitingForReject +

  • + Receive anything else → send ERROR, goto + WaitingForOK +

+

WaitingForReject +

  • + Receive REJECT [mechs] → send AUTH [next mech], + goto WaitingForData or + WaitingForOK +

  • + Receive anything else → terminate auth + conversation, disconnect +

+

Server states

+ For the server MECH(RESP) means that the client response + RESP was fed to the the mechanism MECH, which returns one of + +

  • + CONTINUE(CHALL) means continue the auth conversation and + send CHALL as the challenge to the client; +

  • + OK means that the client has been successfully + authenticated; +

  • + REJECT means that the client failed to authenticate or + there was an error in RESP. +

+ + The server starts out in state + WaitingForAuth. If the client is + rejected too many times the server must disconnect the + client. +

WaitingForAuth +

  • + Receive AUTH → send REJECTED [mechs], goto + WaitingForAuth +

  • + Receive AUTH MECH RESP + +

    + MECH not valid mechanism → send REJECTED + [mechs], goto + WaitingForAuth +
    + MECH(RESP) returns CONTINUE(CHALL) → send + DATA CHALL, goto + WaitingForData +
    + MECH(RESP) returns OK → send OK, goto + WaitingForBegin +
    + MECH(RESP) returns REJECT → send REJECTED + [mechs], goto + WaitingForAuth +

    +

  • + Receive BEGIN → terminate + auth conversation, disconnect +

  • + Receive ERROR → send REJECTED [mechs], goto + WaitingForAuth +

  • + Receive anything else → send + ERROR, goto + WaitingForAuth +

+

WaitingForData +

  • + Receive DATA RESP +

    + MECH(RESP) returns CONTINUE(CHALL) → send + DATA CHALL, goto + WaitingForData +
    + MECH(RESP) returns OK → send OK, goto + WaitingForBegin +
    + MECH(RESP) returns REJECT → send REJECTED + [mechs], goto + WaitingForAuth +

    +

  • + Receive BEGIN → terminate auth conversation, + disconnect +

  • + Receive CANCEL → send REJECTED [mechs], goto + WaitingForAuth +

  • + Receive ERROR → send REJECTED [mechs], goto + WaitingForAuth +

  • + Receive anything else → send ERROR, goto + WaitingForData +

+

WaitingForBegin +

  • + Receive BEGIN → terminate auth conversation, + client authenticated +

  • + Receive CANCEL → send REJECTED [mechs], goto + WaitingForAuth +

  • + Receive ERROR → send REJECTED [mechs], goto + WaitingForAuth +

  • + Receive anything else → send ERROR, goto + WaitingForBegin +

+

Authentication mechanisms

+ This section describes some new authentication mechanisms. + D-Bus also allows any standard SASL mechanism of course. +

DBUS_COOKIE_SHA1

+ The DBUS_COOKIE_SHA1 mechanism is designed to establish that a client + has the ability to read a private file owned by the user being + authenticated. If the client can prove that it has access to a secret + cookie stored in this file, then the client is authenticated. + Thus the security of DBUS_COOKIE_SHA1 depends on a secure home + directory. +

+ Throughout this description, "hex encoding" must output the digits + from a to f in lower-case; the digits A to F must not be used + in the DBUS_COOKIE_SHA1 mechanism. +

+ Authentication proceeds as follows: +

  • + The client sends the username it would like to authenticate + as, hex-encoded. +

  • + The server sends the name of its "cookie context" (see below); a + space character; the integer ID of the secret cookie the client + must demonstrate knowledge of; a space character; then a + randomly-generated challenge string, all of this hex-encoded into + one, single string. +

  • + The client locates the cookie and generates its own + randomly-generated challenge string. The client then concatenates + the server's decoded challenge, a ":" character, its own challenge, + another ":" character, and the cookie. It computes the SHA-1 hash + of this composite string as a hex digest. It concatenates the + client's challenge string, a space character, and the SHA-1 hex + digest, hex-encodes the result and sends it back to the server. +

  • + The server generates the same concatenated string used by the + client and computes its SHA-1 hash. It compares the hash with + the hash received from the client; if the two hashes match, the + client is authenticated. +

+

+ Each server has a "cookie context," which is a name that identifies a + set of cookies that apply to that server. A sample context might be + "org_freedesktop_session_bus". Context names must be valid ASCII, + nonzero length, and may not contain the characters slash ("/"), + backslash ("\"), space (" "), newline ("\n"), carriage return ("\r"), + tab ("\t"), or period ("."). There is a default context, + "org_freedesktop_general" that's used by servers that do not specify + otherwise. +

+ Cookies are stored in a user's home directory, in the directory + ~/.dbus-keyrings/. This directory must + not be readable or writable by other users. If it is, + clients and servers must ignore it. The directory + contains cookie files named after the cookie context. +

+ A cookie file contains one cookie per line. Each line + has three space-separated fields: +

  • + The cookie ID number, which must be a non-negative integer and + may not be used twice in the same file. +

  • + The cookie's creation time, in UNIX seconds-since-the-epoch + format. +

  • + The cookie itself, a hex-encoded random block of bytes. The cookie + may be of any length, though obviously security increases + as the length increases. +

+

+ Only server processes modify the cookie file. + They must do so with this procedure: +

  • + Create a lockfile name by appending ".lock" to the name of the + cookie file. The server should attempt to create this file + using O_CREAT | O_EXCL. If file creation + fails, the lock fails. Servers should retry for a reasonable + period of time, then they may choose to delete an existing lock + to keep users from having to manually delete a stale + lock. [1] +

  • + Once the lockfile has been created, the server loads the cookie + file. It should then delete any cookies that are old (the + timeout can be fairly short), or more than a reasonable + time in the future (so that cookies never accidentally + become permanent, if the clock was set far into the future + at some point). If no recent keys remain, the + server may generate a new key. +

  • + The pruned and possibly added-to cookie file + must be resaved atomically (using a temporary + file which is rename()'d). +

  • + The lock must be dropped by deleting the lockfile. +

+

+ Clients need not lock the file in order to load it, + because servers are required to save the file atomically. +

Server Addresses

+ Server addresses consist of a transport name followed by a colon, and + then an optional, comma-separated list of keys and values in the form key=value. + Each value is escaped. +

+ For example: +

unix:path=/tmp/dbus-test

+ Which is the address to a unix socket with the path /tmp/dbus-test. +

+ Value escaping is similar to URI escaping but simpler. +

  • + The set of optionally-escaped bytes is: + [0-9A-Za-z_-/.\]. To escape, each + byte (note, not character) which is not in the + set of optionally-escaped bytes must be replaced with an ASCII + percent (%) and the value of the byte in hex. + The hex value must always be two digits, even if the first digit is + zero. The optionally-escaped bytes may be escaped if desired. +

  • + To unescape, append each byte in the value; if a byte is an ASCII + percent (%) character then append the following + hex value instead. It is an error if a % byte + does not have two hex digits following. It is an error if a + non-optionally-escaped byte is seen unescaped. +

+ The set of optionally-escaped bytes is intended to preserve address + readability and convenience. +

+ A server may specify a key-value pair with the key guid + and the value a hex-encoded 16-byte sequence. the section called “UUIDs” + describes the format of the guid field. If present, + this UUID may be used to distinguish one server address from another. A + server should use a different UUID for each address it listens on. For + example, if a message bus daemon offers both UNIX domain socket and TCP + connections, but treats clients the same regardless of how they connect, + those two connections are equivalent post-connection but should have + distinct UUIDs to distinguish the kinds of connection. +

+ The intent of the address UUID feature is to allow a client to avoid + opening multiple identical connections to the same server, by allowing the + client to check whether an address corresponds to an already-existing + connection. Comparing two addresses is insufficient, because addresses + can be recycled by distinct servers, and equivalent addresses may look + different if simply compared as strings (for example, the host in a TCP + address can be given as an IP address or as a hostname). +

+ Note that the address key is guid even though the + rest of the API and documentation says "UUID," for historical reasons. +

+ [FIXME clarify if attempting to connect to each is a requirement + or just a suggestion] + When connecting to a server, multiple server addresses can be + separated by a semi-colon. The library will then try to connect + to the first address and if that fails, it'll try to connect to + the next one specified, and so forth. For example +

unix:path=/tmp/dbus-test;unix:path=/tmp/dbus-test2

+

Transports

+ [FIXME we need to specify in detail each transport and its possible arguments] + + Current transports include: unix domain sockets (including + abstract namespace on linux), TCP/IP, and a debug/testing transport using + in-process pipes. Future possible transports include one that + tunnels over X11 protocol. +

Unix Domain Sockets

+ Unix domain sockets can be either paths in the file system or on Linux + kernels, they can be abstract which are similar to paths but + do not show up in the file system. +

+ When a socket is opened by the D-Bus library it truncates the path + name right before the first trailing Nul byte. This is true for both + normal paths and abstract paths. Note that this is a departure from + previous versions of D-Bus that would create sockets with a fixed + length path name. Names which were shorter than the fixed length + would be padded by Nul bytes. +

Naming Conventions

+ D-Bus namespaces are all lowercase and correspond to reversed domain + names, as with Java. e.g. "org.freedesktop" +

+ Interface, signal, method, and property names are "WindowsStyleCaps", note + that the first letter is capitalized, unlike Java. +

+ Object paths are normally all lowercase with underscores used rather than + hyphens. +

UUIDs

+ A working D-Bus implementation uses universally-unique IDs in two places. + First, each server address has a UUID identifying the address, + as described in the section called “Server Addresses”. Second, each operating + system kernel instance running a D-Bus client or server has a UUID + identifying that kernel, retrieved by invoking the method + org.freedesktop.DBus.Peer.GetMachineId() (see the section called “org.freedesktop.DBus.Peer). +

+ The term "UUID" in this document is intended literally, i.e. an + identifier that is universally unique. It is not intended to refer to + RFC4122, and in fact the D-Bus UUID is not compatible with that RFC. +

+ The UUID must contain 128 bits of data and be hex-encoded. The + hex-encoded string may not contain hyphens or other non-hex-digit + characters, and it must be exactly 32 characters long. To generate a + UUID, the current reference implementation concatenates 96 bits of random + data followed by the 32-bit time in seconds since the UNIX epoch (in big + endian byte order). +

+ It would also be acceptable and probably better to simply generate 128 + bits of random data, as long as the random number generator is of high + quality. The timestamp could conceivably help if the random bits are not + very random. With a quality random number generator, collisions are + extremely unlikely even with only 96 bits, so it's somewhat academic. +

+ Implementations should, however, stick to random data for the first 96 bits + of the UUID. +

Standard Interfaces

+ See the section called “Notation in this document” for details on + the notation used in this section. There are some standard interfaces + that may be useful across various D-Bus applications. +

org.freedesktop.DBus.Peer

+ The org.freedesktop.DBus.Peer interface + has two methods: +

+          org.freedesktop.DBus.Peer.Ping ()
+          org.freedesktop.DBus.Peer.GetMachineId (out STRING machine_uuid)
+        

+

+ On receipt of the METHOD_CALL message + org.freedesktop.DBus.Peer.Ping, an application should do + nothing other than reply with a METHOD_RETURN as + usual. It does not matter which object path a ping is sent to. The + reference implementation handles this method automatically. +

+ On receipt of the METHOD_CALL message + org.freedesktop.DBus.Peer.GetMachineId, an application should + reply with a METHOD_RETURN containing a hex-encoded + UUID representing the identity of the machine the process is running on. + This UUID must be the same for all processes on a single system at least + until that system next reboots. It should be the same across reboots + if possible, but this is not always possible to implement and is not + guaranteed. + It does not matter which object path a GetMachineId is sent to. The + reference implementation handles this method automatically. +

+ The UUID is intended to be per-instance-of-the-operating-system, so may represent + a virtual machine running on a hypervisor, rather than a physical machine. + Basically if two processes see the same UUID, they should also see the same + shared memory, UNIX domain sockets, process IDs, and other features that require + a running OS kernel in common between the processes. +

+ The UUID is often used where other programs might use a hostname. Hostnames + can change without rebooting, however, or just be "localhost" - so the UUID + is more robust. +

+ the section called “UUIDs” explains the format of the UUID. +

org.freedesktop.DBus.Introspectable

+ This interface has one method: +

+          org.freedesktop.DBus.Introspectable.Introspect (out STRING xml_data)
+        

+

+ Objects instances may implement + Introspect which returns an XML description of + the object, including its interfaces (with signals and methods), objects + below it in the object path tree, and its properties. +

+ the section called “Introspection Data Format” describes the format of this XML string. +

org.freedesktop.DBus.Properties

+ Many native APIs will have a concept of object properties + or attributes. These can be exposed via the + org.freedesktop.DBus.Properties interface. +

+

+              org.freedesktop.DBus.Properties.Get (in STRING interface_name,
+                                                   in STRING property_name,
+                                                   out VARIANT value);
+              org.freedesktop.DBus.Properties.Set (in STRING interface_name,
+                                                   in STRING property_name,
+                                                   in VARIANT value);
+              org.freedesktop.DBus.Properties.GetAll (in STRING interface_name,
+                                                      out DICT<STRING,VARIANT> props);
+        

+

+ The available properties and whether they are writable can be determined + by calling org.freedesktop.DBus.Introspectable.Introspect, + see the section called “org.freedesktop.DBus.Introspectable. +

+ An empty string may be provided for the interface name; in this case, + if there are multiple properties on an object with the same name, + the results are undefined (picking one by according to an arbitrary + deterministic rule, or returning an error, are the reasonable + possibilities). +

Introspection Data Format

+ As described in the section called “org.freedesktop.DBus.Introspectable, + objects may be introspected at runtime, returning an XML string + that describes the object. The same XML format may be used in + other contexts as well, for example as an "IDL" for generating + static language bindings. +

+ Here is an example of introspection data: +

+        <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+         "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+        <node name="/org/freedesktop/sample_object">
+          <interface name="org.freedesktop.SampleInterface">
+            <method name="Frobate">
+              <arg name="foo" type="i" direction="in"/>
+              <arg name="bar" type="s" direction="out"/>
+              <arg name="baz" type="a{us}" direction="out"/>
+              <annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
+            </method>
+            <method name="Bazify">
+              <arg name="bar" type="(iiu)" direction="in"/>
+              <arg name="bar" type="v" direction="out"/>
+            </method>
+            <method name="Mogrify">
+              <arg name="bar" type="(iiav)" direction="in"/>
+            </method>
+            <signal name="Changed">
+              <arg name="new_value" type="b"/>
+            </signal>
+            <property name="Bar" type="y" access="readwrite"/>
+          </interface>
+          <node name="child_of_sample_object"/>
+          <node name="another_child_of_sample_object"/>
+       </node>
+      

+

+ A more formal DTD and spec needs writing, but here are some quick notes. +

  • + Only the root <node> element can omit the node name, as it's + known to be the object that was introspected. If the root + <node> does have a name attribute, it must be an absolute + object path. If child <node> have object paths, they must be + relative. +

  • + If a child <node> has any sub-elements, then they + must represent a complete introspection of the child. + If a child <node> is empty, then it may or may + not have sub-elements; the child must be introspected + in order to find out. The intent is that if an object + knows that its children are "fast" to introspect + it can go ahead and return their information, but + otherwise it can omit it. +

  • + The direction element on <arg> may be omitted, + in which case it defaults to "in" for method calls + and "out" for signals. Signals only allow "out" + so while direction may be specified, it's pointless. +

  • + The possible directions are "in" and "out", + unlike CORBA there is no "inout" +

  • + The possible property access flags are + "readwrite", "read", and "write" +

  • + Multiple interfaces can of course be listed for + one <node>. +

  • + The "name" attribute on arguments is optional. +

+

+ Method, interface, property, and signal elements may have + "annotations", which are generic key/value pairs of metadata. + They are similar conceptually to Java's annotations and C# attributes. + Well-known annotations: +

NameValues (separated by ,)Description
org.freedesktop.DBus.Deprecatedtrue,falseWhether or not the entity is deprecated; defaults to false
org.freedesktop.DBus.GLib.CSymbol(string)The C symbol; may be used for methods and interfaces
org.freedesktop.DBus.Method.NoReplytrue,falseIf set, don't expect a reply to the method call; defaults to false.

Message Bus Specification

Message Bus Overview

+ The message bus accepts connections from one or more applications. + Once connected, applications can exchange messages with other + applications that are also connected to the bus. +

+ In order to route messages among connections, the message bus keeps a + mapping from names to connections. Each connection has one + unique-for-the-lifetime-of-the-bus name automatically assigned. + Applications may request additional names for a connection. Additional + names are usually "well-known names" such as + "org.freedesktop.TextEditor". When a name is bound to a connection, + that connection is said to own the name. +

+ The bus itself owns a special name, org.freedesktop.DBus. + This name routes messages to the bus, allowing applications to make + administrative requests. For example, applications can ask the bus + to assign a name to a connection. +

+ Each name may have queued owners. When an + application requests a name for a connection and the name is already in + use, the bus will optionally add the connection to a queue waiting for + the name. If the current owner of the name disconnects or releases + the name, the next connection in the queue will become the new owner. +

+ This feature causes the right thing to happen if you start two text + editors for example; the first one may request "org.freedesktop.TextEditor", + and the second will be queued as a possible owner of that name. When + the first exits, the second will take over. +

+ Messages may have a DESTINATION field (see the section called “Header Fields”). If the + DESTINATION field is present, it specifies a message + recipient by name. Method calls and replies normally specify this field. +

+ Signals normally do not specify a destination; they are sent to all + applications with message matching rules that + match the message. +

+ When the message bus receives a method call, if the + DESTINATION field is absent, the call is taken to be + a standard one-to-one message and interpreted by the message bus + itself. For example, sending an + org.freedesktop.DBus.Peer.Ping message with no + DESTINATION will cause the message bus itself to + reply to the ping immediately; the message bus will not make this + message visible to other applications. +

+ Continuing the org.freedesktop.DBus.Peer.Ping example, if + the ping message were sent with a DESTINATION name of + com.yoyodyne.Screensaver, then the ping would be + forwarded, and the Yoyodyne Corporation screensaver application would be + expected to reply to the ping. +

Message Bus Names

+ Each connection has at least one name, assigned at connection time and + returned in response to the + org.freedesktop.DBus.Hello method call. This + automatically-assigned name is called the connection's unique + name. Unique names are never reused for two different + connections to the same bus. +

+ Ownership of a unique name is a prerequisite for interaction with + the message bus. It logically follows that the unique name is always + the first name that an application comes to own, and the last + one that it loses ownership of. +

+ Unique connection names must begin with the character ':' (ASCII colon + character); bus names that are not unique names must not begin + with this character. (The bus must reject any attempt by an application + to manually request a name beginning with ':'.) This restriction + categorically prevents "spoofing"; messages sent to a unique name + will always go to the expected connection. +

+ When a connection is closed, all the names that it owns are deleted (or + transferred to the next connection in the queue if any). +

+ A connection can request additional names to be associated with it using + the org.freedesktop.DBus.RequestName message. the section called “Bus names” describes the format of a valid + name. These names can be released again using the + org.freedesktop.DBus.ReleaseName message. +

org.freedesktop.DBus.RequestName

+ As a method: +

+            UINT32 RequestName (in STRING name, in UINT32 flags)
+          

+ Message arguments: +

ArgumentTypeDescription
0STRINGName to request
1UINT32Flags

+ Reply arguments: +

ArgumentTypeDescription
0UINT32Return value

+

+ This method call should be sent to + org.freedesktop.DBus and asks the message bus to + assign the given name to the method caller. Each name maintains a + queue of possible owners, where the head of the queue is the primary + or current owner of the name. Each potential owner in the queue + maintains the DBUS_NAME_FLAG_ALLOW_REPLACEMENT and + DBUS_NAME_FLAG_DO_NOT_QUEUE settings from its latest RequestName + call. When RequestName is invoked the following occurs: +

  • + If the method caller is currently the primary owner of the name, + the DBUS_NAME_FLAG_ALLOW_REPLACEMENT and DBUS_NAME_FLAG_DO_NOT_QUEUE + values are updated with the values from the new RequestName call, + and nothing further happens. +

  • + If the current primary owner (head of the queue) has + DBUS_NAME_FLAG_ALLOW_REPLACEMENT set, and the RequestName + invocation has the DBUS_NAME_FLAG_REPLACE_EXISTING flag, then + the caller of RequestName replaces the current primary owner at + the head of the queue and the current primary owner moves to the + second position in the queue. If the caller of RequestName was + in the queue previously its flags are updated with the values from + the new RequestName in addition to moving it to the head of the queue. +

  • + If replacement is not possible, and the method caller is + currently in the queue but not the primary owner, its flags are + updated with the values from the new RequestName call. +

  • + If replacement is not possible, and the method caller is + currently not in the queue, the method caller is appended to the + queue. +

  • + If any connection in the queue has DBUS_NAME_FLAG_DO_NOT_QUEUE + set and is not the primary owner, it is removed from the + queue. This can apply to the previous primary owner (if it + was replaced) or the method caller (if it updated the + DBUS_NAME_FLAG_DO_NOT_QUEUE flag while still stuck in the + queue, or if it was just added to the queue with that flag set). +

+

+ Note that DBUS_NAME_FLAG_REPLACE_EXISTING results in "jumping the + queue," even if another application already in the queue had specified + DBUS_NAME_FLAG_REPLACE_EXISTING. This comes up if a primary owner + that does not allow replacement goes away, and the next primary owner + does allow replacement. In this case, queued items that specified + DBUS_NAME_FLAG_REPLACE_EXISTING do not + automatically replace the new primary owner. In other words, + DBUS_NAME_FLAG_REPLACE_EXISTING is not saved, it is only used at the + time RequestName is called. This is deliberate to avoid an infinite loop + anytime two applications are both DBUS_NAME_FLAG_ALLOW_REPLACEMENT + and DBUS_NAME_FLAG_REPLACE_EXISTING. +

+ The flags argument contains any of the following values logically ORed + together: + +

Conventional NameValueDescription
DBUS_NAME_FLAG_ALLOW_REPLACEMENT0x1 + + If an application A specifies this flag and succeeds in + becoming the owner of the name, and another application B + later calls RequestName with the + DBUS_NAME_FLAG_REPLACE_EXISTING flag, then application A + will lose ownership and receive a + org.freedesktop.DBus.NameLost signal, and + application B will become the new owner. If DBUS_NAME_FLAG_ALLOW_REPLACEMENT + is not specified by application A, or DBUS_NAME_FLAG_REPLACE_EXISTING + is not specified by application B, then application B will not replace + application A as the owner. + +
DBUS_NAME_FLAG_REPLACE_EXISTING0x2 + + Try to replace the current owner if there is one. If this + flag is not set the application will only become the owner of + the name if there is no current owner. If this flag is set, + the application will replace the current owner if + the current owner specified DBUS_NAME_FLAG_ALLOW_REPLACEMENT. + +
DBUS_NAME_FLAG_DO_NOT_QUEUE0x4 + + Without this flag, if an application requests a name that is + already owned, the application will be placed in a queue to + own the name when the current owner gives it up. If this + flag is given, the application will not be placed in the + queue, the request for the name will simply fail. This flag + also affects behavior when an application is replaced as + name owner; by default the application moves back into the + waiting queue, unless this flag was provided when the application + became the name owner. + +

+ + The return code can be one of the following values: + +

Conventional NameValueDescription
DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER1The caller is now the primary owner of + the name, replacing any previous owner. Either the name had no + owner before, or the caller specified + DBUS_NAME_FLAG_REPLACE_EXISTING and the current owner specified + DBUS_NAME_FLAG_ALLOW_REPLACEMENT.
DBUS_REQUEST_NAME_REPLY_IN_QUEUE2The name already had an owner, + DBUS_NAME_FLAG_DO_NOT_QUEUE was not specified, and either + the current owner did not specify + DBUS_NAME_FLAG_ALLOW_REPLACEMENT or the requesting + application did not specify DBUS_NAME_FLAG_REPLACE_EXISTING. +
DBUS_REQUEST_NAME_REPLY_EXISTS3The name already has an owner, + DBUS_NAME_FLAG_DO_NOT_QUEUE was specified, and either + DBUS_NAME_FLAG_ALLOW_REPLACEMENT was not specified by the + current owner, or DBUS_NAME_FLAG_REPLACE_EXISTING was not + specified by the requesting application.
DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER4The application trying to request ownership of a name is already the owner of it.

+

org.freedesktop.DBus.ReleaseName

+ As a method: +

+            UINT32 ReleaseName (in STRING name)
+          

+ Message arguments: +

ArgumentTypeDescription
0STRINGName to release

+ Reply arguments: +

ArgumentTypeDescription
0UINT32Return value

+

+ This method call should be sent to + org.freedesktop.DBus and asks the message bus to + release the method caller's claim to the given name. If the caller is + the primary owner, a new primary owner will be selected from the + queue if any other owners are waiting. If the caller is waiting in + the queue for the name, the caller will removed from the queue and + will not be made an owner of the name if it later becomes available. + If there are no other owners in the queue for the name, it will be + removed from the bus entirely. + + The return code can be one of the following values: + +

Conventional NameValueDescription
DBUS_RELEASE_NAME_REPLY_RELEASED1The caller has released his claim on + the given name. Either the caller was the primary owner of + the name, and the name is now unused or taken by somebody + waiting in the queue for the name, or the caller was waiting + in the queue for the name and has now been removed from the + queue.
DBUS_RELEASE_NAME_REPLY_NON_EXISTENT2The given name does not exist on this bus.
DBUS_RELEASE_NAME_REPLY_NOT_OWNER3The caller was not the primary owner of this name, + and was also not waiting in the queue to own this name.

+

Message Bus Message Routing

+ FIXME +

Match Rules

+ An important part of the message bus routing protocol is match + rules. Match rules describe what messages can be sent to a client + based on the contents of the message. When a message is routed + through the bus it is compared to clients' match rules. If any + of the rules match, the message is dispatched to the client. + If none of the rules match the message never leaves the bus. This + is an effective way to control traffic over the bus and to make sure + only relevant message need to be processed by the client. +

+ Match rules are added using the AddMatch bus method + (see xref linkend="bus-messages-add-match"/>). Rules are + specified as a string of comma separated key/value pairs. + Excluding a key from the rule indicates a wildcard match. + For instance excluding the the member from a match rule but + adding a sender would let all messages from that sender through. + An example of a complete rule would be + "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',path='/bar/foo',destination=':452345.34',arg2='bar'" +

+ The following table describes the keys that can be used to create + a match rule: + The following table summarizes the D-Bus types. +

KeyPossible ValuesDescription
type'signal', 'method_call', 'method_return', 'error'Match on the message type. An example of a type match is type='signal'
senderA bus or unique name (see Bus Name + and Unique Connection Name respectively) + Match messages sent by a particular sender. An example of a sender match + is sender='org.freedesktop.Hal'
interfaceAn interface name (see the section called “Interface names”)Match messages sent over or to a particular interface. An example of an + interface match is interface='org.freedesktop.Hal.Manager'. + If a message omits the interface header, it must not match any rule + that specifies this key.
memberAny valid method or signal nameMatches messages which have the give method or signal name. An example of + a member match is member='NameOwnerChanged'
pathAn object path (see the section called “Valid Object Paths”)Matches messages which are sent from or to the given object. An example of a + path match is path='/org/freedesktop/Hal/Manager'
destinationA unique name (see Unique Connection Name)Matches messages which are being sent to the given unique name. An + example of a destination match is destination=':1.0'
arg[0, 1, 2, 3, ...]Any stringArg matches are special and are used for further restricting the + match based on the arguments in the body of a message. As of this time + only string arguments can be matched. An example of an argument match + would be arg3='Foo'. Only argument indexes from 0 to 63 should be + accepted.
arg[0, 1, 2, 3, ...]pathAny stringArgument path matches provide a specialised form of wildcard + matching for path-like namespaces. As with normal argument matches, + if the argument is exactly equal to the string given in the match + rule then the rule is satisfied. Additionally, there is also a + match when either the string given in the match rule or the + appropriate message argument ends with '/' and is a prefix of the + other. An example argument path match is arg0path='/aa/bb/'. This + would match messages with first arguments of '/', '/aa/', + '/aa/bb/', '/aa/bb/cc/' and '/aa/bb/cc'. It would not match + messages with first arguments of '/aa/b', '/aa' or even '/aa/bb'.

+

Message Bus Starting Services

+ The message bus can start applications on behalf of other applications. + In CORBA terms, this would be called activation. + An application that can be started in this way is called a + service. +

+ With D-Bus, starting a service is normally done by name. That is, + applications ask the message bus to start some program that will own a + well-known name, such as org.freedesktop.TextEditor. + This implies a contract documented along with the name + org.freedesktop.TextEditor for which objects + the owner of that name will provide, and what interfaces those + objects will have. +

+ To find an executable corresponding to a particular name, the bus daemon + looks for service description files. Service + description files define a mapping from names to executables. Different + kinds of message bus will look for these files in different places, see + the section called “Well-known Message Bus Instances”. +

+ [FIXME the file format should be much better specified than "similar to + .desktop entries" esp. since desktop entries are already + badly-specified. ;-)] Service description files have the ".service" file + extension. The message bus will only load service description files + ending with .service; all other files will be ignored. The file format + is similar to that of desktop + entries. All service description files must be in UTF-8 + encoding. To ensure that there will be no name collisions, service files + must be namespaced using the same mechanism as messages and service + names. + +

Figure 7. Example service description file

+            # Sample service description file
+            [D-BUS Service]
+            Names=org.freedesktop.ConfigurationDatabase;org.gnome.GConf;
+            Exec=/usr/libexec/gconfd-2
+          


+

+ When an application asks to start a service by name, the bus daemon tries to + find a service that will own that name. It then tries to spawn the + executable associated with it. If this fails, it will report an + error. [FIXME what happens if two .service files offer the same service; + what kind of error is reported, should we have a way for the client to + choose one?] +

+ The executable launched will have the environment variable + DBUS_STARTER_ADDRESS set to the address of the + message bus so it can connect and request the appropriate names. +

+ The executable being launched may want to know whether the message bus + starting it is one of the well-known message buses (see the section called “Well-known Message Bus Instances”). To facilitate this, the bus must also set + the DBUS_STARTER_BUS_TYPE environment variable if it is one + of the well-known buses. The currently-defined values for this variable + are system for the systemwide message bus, + and session for the per-login-session message + bus. The new executable must still connect to the address given + in DBUS_STARTER_ADDRESS, but may assume that the + resulting connection is to the well-known bus. +

+ [FIXME there should be a timeout somewhere, either specified + in the .service file, by the client, or just a global value + and if the client being activated fails to connect within that + timeout, an error should be sent back.] +

Message Bus Service Scope

+ The "scope" of a service is its "per-", such as per-session, + per-machine, per-home-directory, or per-display. The reference + implementation doesn't yet support starting services in a different + scope from the message bus itself. So e.g. if you start a service + on the session bus its scope is per-session. +

+ We could add an optional scope to a bus name. For example, for + per-(display,session pair), we could have a unique ID for each display + generated automatically at login and set on screen 0 by executing a + special "set display ID" binary. The ID would be stored in a + _DBUS_DISPLAY_ID property and would be a string of + random bytes. This ID would then be used to scope names. + Starting/locating a service could be done by ID-name pair rather than + only by name. +

+ Contrast this with a per-display scope. To achieve that, we would + want a single bus spanning all sessions using a given display. + So we might set a _DBUS_DISPLAY_BUS_ADDRESS + property on screen 0 of the display, pointing to this bus. +

Well-known Message Bus Instances

+ Two standard message bus instances are defined here, along with how + to locate them and where their service files live. +

Login session message bus

+ Each time a user logs in, a login session message + bus may be started. All applications in the user's login + session may interact with one another using this message bus. +

+ The address of the login session message bus is given + in the DBUS_SESSION_BUS_ADDRESS environment + variable. If that variable is not set, applications may + also try to read the address from the X Window System root + window property _DBUS_SESSION_BUS_ADDRESS. + The root window property must have type STRING. + The environment variable should have precedence over the + root window property. +

+ [FIXME specify location of .service files, probably using + DESKTOP_DIRS etc. from basedir specification, though login session + bus is not really desktop-specific] +

System message bus

+ A computer may have a system message bus, + accessible to all applications on the system. This message bus may be + used to broadcast system events, such as adding new hardware devices, + changes in the printer queue, and so forth. +

+ The address of the system message bus is given + in the DBUS_SYSTEM_BUS_ADDRESS environment + variable. If that variable is not set, applications should try + to connect to the well-known address + unix:path=/var/run/dbus/system_bus_socket. + [2] +

+ [FIXME specify location of system bus .service files] +

Message Bus Messages

+ The special message bus name org.freedesktop.DBus + responds to a number of additional messages. +

org.freedesktop.DBus.Hello

+ As a method: +

+            STRING Hello ()
+          

+ Reply arguments: +

ArgumentTypeDescription
0STRINGUnique name assigned to the connection

+

+ Before an application is able to send messages to other applications + it must send the org.freedesktop.DBus.Hello message + to the message bus to obtain a unique name. If an application without + a unique name tries to send a message to another application, or a + message to the message bus itself that isn't the + org.freedesktop.DBus.Hello message, it will be + disconnected from the bus. +

+ There is no corresponding "disconnect" request; if a client wishes to + disconnect from the bus, it simply closes the socket (or other + communication channel). +

org.freedesktop.DBus.ListNames

+ As a method: +

+            ARRAY of STRING ListNames ()
+          

+ Reply arguments: +

ArgumentTypeDescription
0ARRAY of STRINGArray of strings where each string is a bus name

+

+ Returns a list of all currently-owned names on the bus. +

org.freedesktop.DBus.ListActivatableNames

+ As a method: +

+            ARRAY of STRING ListActivatableNames ()
+          

+ Reply arguments: +

ArgumentTypeDescription
0ARRAY of STRINGArray of strings where each string is a bus name

+

+ Returns a list of all names that can be activated on the bus. +

org.freedesktop.DBus.NameHasOwner

+ As a method: +

+            BOOLEAN NameHasOwner (in STRING name)
+          

+ Message arguments: +

ArgumentTypeDescription
0STRINGName to check

+ Reply arguments: +

ArgumentTypeDescription
0BOOLEANReturn value, true if the name exists

+

+ Checks if the specified name exists (currently has an owner). +

org.freedesktop.DBus.NameOwnerChanged

+ This is a signal: +

+            NameOwnerChanged (STRING name, STRING old_owner, STRING new_owner)
+          

+ Message arguments: +

ArgumentTypeDescription
0STRINGName with a new owner
1STRINGOld owner or empty string if none
2STRINGNew owner or empty string if none

+

+ This signal indicates that the owner of a name has changed. + It's also the signal to use to detect the appearance of + new names on the bus. +

org.freedesktop.DBus.NameLost

+ This is a signal: +

+            NameLost (STRING name)
+          

+ Message arguments: +

ArgumentTypeDescription
0STRINGName which was lost

+

+ This signal is sent to a specific application when it loses + ownership of a name. +

org.freedesktop.DBus.NameAcquired

+ This is a signal: +

+            NameAcquired (STRING name)
+          

+ Message arguments: +

ArgumentTypeDescription
0STRINGName which was acquired

+

+ This signal is sent to a specific application when it gains + ownership of a name. +

org.freedesktop.DBus.StartServiceByName

+ As a method: +

+            UINT32 StartServiceByName (in STRING name, in UINT32 flags)
+          

+ Message arguments: +

ArgumentTypeDescription
0STRINGName of the service to start
1UINT32Flags (currently not used)

+ Reply arguments: +

ArgumentTypeDescription
0UINT32Return value

+ Tries to launch the executable associated with a name. For more information, see the section called “Message Bus Starting Services”. + +

+ The return value can be one of the following values: +

IdentifierValueDescription
DBUS_START_REPLY_SUCCESS1The service was successfully started.
DBUS_START_REPLY_ALREADY_RUNNING2A connection already owns the given name.

+

org.freedesktop.DBus.UpdateActivationEnvironment

+ As a method: +

+            UpdateActivationEnvironment (in ARRAY of DICT<STRING,STRING> environment)
+          

+ Message arguments: +

ArgumentTypeDescription
0ARRAY of DICT<STRING,STRING>Environment to add or update

+ Normally, session bus activated services inherit the environment of the bus daemon. This method adds to or modifies that environment when activating services. +

+ Some bus instances, such as the standard system bus, may disable access to this method for some or all callers. +

org.freedesktop.DBus.GetNameOwner

+ As a method: +

+            STRING GetNameOwner (in STRING name)
+          

+ Message arguments: +

ArgumentTypeDescription
0STRINGName to get the owner of

+ Reply arguments: +

ArgumentTypeDescription
0STRINGReturn value, a unique connection name

+ Returns the unique connection name of the primary owner of the name + given. If the requested name doesn't have an owner, returns a + org.freedesktop.DBus.Error.NameHasNoOwner error. +

org.freedesktop.DBus.GetConnectionUnixUser

+ As a method: +

+            UINT32 GetConnectionUnixUser (in STRING connection_name)
+          

+ Message arguments: +

ArgumentTypeDescription
0STRINGName of the connection to query

+ Reply arguments: +

ArgumentTypeDescription
0UINT32unix user id

+ Returns the unix uid of the process connected to the server. If unable to + determine it, a org.freedesktop.DBus.Error.Failed + error is returned. +

org.freedesktop.DBus.AddMatch

+ As a method: +

+            AddMatch (in STRING rule)
+          

+ Message arguments: +

ArgumentTypeDescription
0STRINGMatch rule to add to the connection

+ Adds a match rule to match messages going through the message bus (see the section called “Match Rules”). + If the bus does not have enough resources the org.freedesktop.DBus.Error.OOM + error is returned. +

org.freedesktop.DBus.RemoveMatch

+ As a method: +

+            RemoveMatch (in STRING rule)
+          

+ Message arguments: +

ArgumentTypeDescription
0STRINGMatch rule to remove from the connection

+ Removes the first rule that matches (see the section called “Match Rules”). + If the rule is not found the org.freedesktop.DBus.Error.MatchRuleNotFound + error is returned. +

org.freedesktop.DBus.GetId

+ As a method: +

+            GetId (out STRING id)
+          

+ Reply arguments: +

ArgumentTypeDescription
0STRINGUnique ID identifying the bus daemon

+ Gets the unique ID of the bus. The unique ID here is shared among all addresses the + bus daemon is listening on (TCP, UNIX domain socket, etc.) and its format is described in + the section called “UUIDs”. Each address the bus is listening on also has its own unique + ID, as described in the section called “Server Addresses”. The per-bus and per-address IDs are not related. + There is also a per-machine ID, described in the section called “org.freedesktop.DBus.Peer and returned + by org.freedesktop.DBus.Peer.GetMachineId(). + For a desktop session bus, the bus ID can be used as a way to uniquely identify a user's session. +

Glossary

+ This glossary defines some of the terms used in this specification. +

Bus Name

+ The message bus maintains an association between names and + connections. (Normally, there's one connection per application.) A + bus name is simply an identifier used to locate connections. For + example, the hypothetical com.yoyodyne.Screensaver + name might be used to send a message to a screensaver from Yoyodyne + Corporation. An application is said to own a + name if the message bus has associated the application's connection + with the name. Names may also have queued + owners (see Queued Name Owner). + The bus assigns a unique name to each connection, + see Unique Connection Name. Other names + can be thought of as "well-known names" and are + used to find applications that offer specific functionality. +

Message

+ A message is the atomic unit of communication via the D-Bus + protocol. It consists of a header and a + body; the body is made up of + arguments. +

Message Bus

+ The message bus is a special application that forwards + or routes messages between a group of applications + connected to the message bus. It also manages + names used for routing + messages. +

Name

+ See Bus Name. "Name" may + also be used to refer to some of the other names + in D-Bus, such as interface names. +

Namespace

+ Used to prevent collisions when defining new interfaces or bus + names. The convention used is the same one Java uses for defining + classes: a reversed domain name. +

Object

+ Each application contains objects, which have + interfaces and + methods. Objects are referred to by a name, + called a path. +

One-to-One

+ An application talking directly to another application, without going + through a message bus. One-to-one connections may be "peer to peer" or + "client to server." The D-Bus protocol has no concept of client + vs. server after a connection has authenticated; the flow of messages + is symmetrical (full duplex). +

Path

+ Object references (object names) in D-Bus are organized into a + filesystem-style hierarchy, so each object is named by a path. As in + LDAP, there's no difference between "files" and "directories"; a path + can refer to an object, while still having child objects below it. +

Queued Name Owner

+ Each bus name has a primary owner; messages sent to the name go to the + primary owner. However, certain names also maintain a queue of + secondary owners "waiting in the wings." If the primary owner releases + the name, then the first secondary owner in the queue automatically + becomes the new owner of the name. +

Service

+ A service is an executable that can be launched by the bus daemon. + Services normally guarantee some particular features, for example they + may guarantee that they will request a specific name such as + "org.freedesktop.Screensaver", have a singleton object + "/org/freedesktop/Application", and that object will implement the + interface "org.freedesktop.ScreensaverControl". +

Service Description Files

+ ".service files" tell the bus about service applications that can be + launched (see Service). Most importantly they + provide a mapping from bus names to services that will request those + names when they start up. +

Unique Connection Name

+ The special name automatically assigned to each connection by the + message bus. This name will never change owner, and will be unique + (never reused during the lifetime of the message bus). + It will begin with a ':' character. +



[1] Lockfiles are used instead of real file + locking fcntl() because real locking + implementations are still flaky on network + filesystems.

[2] + The D-Bus reference implementation actually honors the + $(localstatedir) configure option + for this address, on both client and server side. +

diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml new file mode 100644 index 00000000..b5866e53 --- /dev/null +++ b/doc/dbus-specification.xml @@ -0,0 +1,4086 @@ + + + +
+ + D-Bus Specification + Version 0.12 + 7 November 2006 + + + Havoc + Pennington + + Red Hat, Inc. +
+ hp@pobox.com +
+
+
+ + Anders + Carlsson + + CodeFactory AB +
+ andersca@codefactory.se +
+
+
+ + Alexander + Larsson + + Red Hat, Inc. +
+ alexl@redhat.com +
+
+
+
+
+ + + Introduction + + D-Bus is a system for low-latency, low-overhead, easy to use + interprocess communication (IPC). In more detail: + + + + D-Bus is low-latency because it is designed + to avoid round trips and allow asynchronous operation, much like + the X protocol. + + + + + D-Bus is low-overhead because it uses a + binary protocol, and does not have to convert to and from a text + format such as XML. Because D-Bus is intended for potentially + high-resolution same-machine IPC, not primarily for Internet IPC, + this is an interesting optimization. + + + + + D-Bus is easy to use because it works in terms + of messages rather than byte streams, and + automatically handles a lot of the hard IPC issues. Also, the D-Bus + library is designed to be wrapped in a way that lets developers use + their framework's existing object/type system, rather than learning + a new one specifically for IPC. + + + + + + + The base D-Bus protocol is a one-to-one (peer-to-peer or client-server) + protocol, specified in . That is, it is + a system for one application to talk to a single other + application. However, the primary intended application of the protocol is the + D-Bus message bus, specified in . The message bus is a special application that + accepts connections from multiple other applications, and forwards + messages among them. + + + + Uses of D-Bus include notification of system changes (notification of when + a camera is plugged in to a computer, or a new version of some software + has been installed), or desktop interoperability, for example a file + monitoring service or a configuration service. + + + + D-Bus is designed for two specific use cases: + + + + A "system bus" for notifications from the system to user sessions, + and to allow the system to request input from user sessions. + + + + + A "session bus" used to implement desktop environments such as + GNOME and KDE. + + + + D-Bus is not intended to be a generic IPC system for any possible + application, and intentionally omits many features found in other + IPC systems for this reason. + + + + At the same time, the bus daemons offer a number of features not found in + other IPC systems, such as single-owner "bus names" (similar to X + selections), on-demand startup of services, and security policies. + In many ways, these features are the primary motivation for developing + D-Bus; other systems would have sufficed if IPC were the only goal. + + + + D-Bus may turn out to be useful in unanticipated applications, but future + versions of this spec and the reference implementation probably will not + incorporate features that interfere with the core use cases. + + + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119. However, the + document could use a serious audit to be sure it makes sense to do + so. Also, they are not capitalized. + + + + Protocol and Specification Stability + + The D-Bus protocol is frozen (only compatible extensions are allowed) as + of November 8, 2006. However, this specification could still use a fair + bit of work to make interoperable reimplementation possible without + reference to the D-Bus reference implementation. Thus, this + specification is not marked 1.0. To mark it 1.0, we'd like to see + someone invest significant effort in clarifying the specification + language, and growing the specification to cover more aspects of the + reference implementation's behavior. + + + Until this work is complete, any attempt to reimplement D-Bus will + probably require looking at the reference implementation and/or asking + questions on the D-Bus mailing list about intended behavior. + Questions on the list are very welcome. + + + Nonetheless, this document should be a useful starting point and is + to our knowledge accurate, though incomplete. + + + + + + + Message Protocol + + + A message consists of a + header and a body. If you + think of a message as a package, the header is the address, and the body + contains the package contents. The message delivery system uses the header + information to figure out where to send the message and how to interpret + it; the recipient interprets the body of the message. + + + + The body of the message is made up of zero or more + arguments, which are typed values, such as an + integer or a byte array. + + + + Both header and body use the same type system and format for + serializing data. Each type of value has a wire format. + Converting a value from some other representation into the wire + format is called marshaling and converting + it back from the wire format is unmarshaling. + + + + Type Signatures + + + The D-Bus protocol does not include type tags in the marshaled data; a + block of marshaled values must have a known type + signature. The type signature is made up of type + codes. A type code is an ASCII character representing the + type of a value. Because ASCII characters are used, the type signature + will always form a valid ASCII string. A simple string compare + determines whether two type signatures are equivalent. + + + + As a simple example, the type code for 32-bit integer (INT32) is + the ASCII character 'i'. So the signature for a block of values + containing a single INT32 would be: + + "i" + + A block of values containing two INT32 would have this signature: + + "ii" + + + + + All basic types work like + INT32 in this example. To marshal and unmarshal + basic types, you simply read one value from the data + block corresponding to each type code in the signature. + In addition to basic types, there are four container + types: STRUCT, ARRAY, VARIANT, + and DICT_ENTRY. + + + + STRUCT has a type code, ASCII character 'r', but this type + code does not appear in signatures. Instead, ASCII characters + '(' and ')' are used to mark the beginning and end of the struct. + So for example, a struct containing two integers would have this + signature: + + "(ii)" + + Structs can be nested, so for example a struct containing + an integer and another struct: + + "(i(ii))" + + The value block storing that struct would contain three integers; the + type signature allows you to distinguish "(i(ii))" from "((ii)i)" or + "(iii)" or "iii". + + + + The STRUCT type code 'r' is not currently used in the D-Bus protocol, + but is useful in code that implements the protocol. This type code + is specified to allow such code to interoperate in non-protocol contexts. + + + + Empty structures are not allowed; there must be at least one + type code between the parentheses. + + + + ARRAY has ASCII character 'a' as type code. The array type code must be + followed by a single complete type. The single + complete type following the array is the type of each array element. So + the simple example is: + + "ai" + + which is an array of 32-bit integers. But an array can be of any type, + such as this array-of-struct-with-two-int32-fields: + + "a(ii)" + + Or this array of array of integer: + + "aai" + + + + + The phrase single complete type deserves some + definition. A single complete type is a basic type code, a variant type code, + an array with its element type, or a struct with its fields. + So the following signatures are not single complete types: + + "aa" + + + "(ii" + + + "ii)" + + And the following signatures contain multiple complete types: + + "ii" + + + "aiai" + + + "(ii)(ii)" + + Note however that a single complete type may contain + multiple other single complete types. + + + + VARIANT has ASCII character 'v' as its type code. A marshaled value of + type VARIANT will have the signature of a single complete type as part + of the value. This signature will be followed by a + marshaled value of that type. + + + + A DICT_ENTRY works exactly like a struct, but rather + than parentheses it uses curly braces, and it has more restrictions. + The restrictions are: it occurs only as an array element type; it has + exactly two single complete types inside the curly braces; the first + single complete type (the "key") must be a basic type rather than a + container type. Implementations must not accept dict entries outside of + arrays, must not accept dict entries with zero, one, or more than two + fields, and must not accept dict entries with non-basic-typed keys. A + dict entry is always a key-value pair. + + + + The first field in the DICT_ENTRY is always the key. + A message is considered corrupt if the same key occurs twice in the same + array of DICT_ENTRY. However, for performance reasons + implementations are not required to reject dicts with duplicate keys. + + + + In most languages, an array of dict entry would be represented as a + map, hash table, or dict object. + + + + The following table summarizes the D-Bus types. + + + + + Conventional Name + Code + Description + + + + + INVALID + 0 (ASCII NUL) + Not a valid type code, used to terminate signatures + + BYTE + 121 (ASCII 'y') + 8-bit unsigned integer + + BOOLEAN + 98 (ASCII 'b') + Boolean value, 0 is FALSE and 1 is TRUE. Everything else is invalid. + + INT16 + 110 (ASCII 'n') + 16-bit signed integer + + UINT16 + 113 (ASCII 'q') + 16-bit unsigned integer + + INT32 + 105 (ASCII 'i') + 32-bit signed integer + + UINT32 + 117 (ASCII 'u') + 32-bit unsigned integer + + INT64 + 120 (ASCII 'x') + 64-bit signed integer + + UINT64 + 116 (ASCII 't') + 64-bit unsigned integer + + DOUBLE + 100 (ASCII 'd') + IEEE 754 double + + STRING + 115 (ASCII 's') + UTF-8 string (must be valid UTF-8). Must be nul terminated and contain no other nul bytes. + + OBJECT_PATH + 111 (ASCII 'o') + Name of an object instance + + SIGNATURE + 103 (ASCII 'g') + A type signature + + ARRAY + 97 (ASCII 'a') + Array + + STRUCT + 114 (ASCII 'r'), 40 (ASCII '('), 41 (ASCII ')') + Struct + + VARIANT + 118 (ASCII 'v') + Variant type (the type of the value is part of the value itself) + + DICT_ENTRY + 101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}') + Entry in a dict or map (array of key-value pairs) + + + + + + + + + + Marshaling (Wire Format) + + + Given a type signature, a block of bytes can be converted into typed + values. This section describes the format of the block of bytes. Byte + order and alignment issues are handled uniformly for all D-Bus types. + + + + A block of bytes has an associated byte order. The byte order + has to be discovered in some way; for D-Bus messages, the + byte order is part of the message header as described in + . For now, assume + that the byte order is known to be either little endian or big + endian. + + + + Each value in a block of bytes is aligned "naturally," for example + 4-byte values are aligned to a 4-byte boundary, and 8-byte values to an + 8-byte boundary. To properly align a value, alignment + padding may be necessary. The alignment padding must always + be the minimum required padding to properly align the following value; + and it must always be made up of nul bytes. The alignment padding must + not be left uninitialized (it can't contain garbage), and more padding + than required must not be used. + + + + Given all this, the types are marshaled on the wire as follows: + + + + + Conventional Name + Encoding + Alignment + + + + + INVALID + Not applicable; cannot be marshaled. + N/A + + BYTE + A single 8-bit byte. + 1 + + BOOLEAN + As for UINT32, but only 0 and 1 are valid values. + 4 + + INT16 + 16-bit signed integer in the message's byte order. + 2 + + UINT16 + 16-bit unsigned integer in the message's byte order. + 2 + + INT32 + 32-bit signed integer in the message's byte order. + 4 + + UINT32 + 32-bit unsigned integer in the message's byte order. + 4 + + INT64 + 64-bit signed integer in the message's byte order. + 8 + + UINT64 + 64-bit unsigned integer in the message's byte order. + 8 + + DOUBLE + 64-bit IEEE 754 double in the message's byte order. + 8 + + STRING + A UINT32 indicating the string's + length in bytes excluding its terminating nul, followed by + non-nul string data of the given length, followed by a terminating nul + byte. + + + 4 (for the length) + + + OBJECT_PATH + Exactly the same as STRING except the + content must be a valid object path (see below). + + + 4 (for the length) + + + SIGNATURE + The same as STRING except the length is a single + byte (thus signatures have a maximum length of 255) + and the content must be a valid signature (see below). + + + 1 + + + ARRAY + + A UINT32 giving the length of the array data in bytes, followed by + alignment padding to the alignment boundary of the array element type, + followed by each array element. The array length is from the + end of the alignment padding to the end of the last element, + i.e. it does not include the padding after the length, + or any padding after the last element. + Arrays have a maximum length defined to be 2 to the 26th power or + 67108864. Implementations must not send or accept arrays exceeding this + length. + + + 4 (for the length) + + + STRUCT + + A struct must start on an 8-byte boundary regardless of the + type of the struct fields. The struct value consists of each + field marshaled in sequence starting from that 8-byte + alignment boundary. + + + 8 + + + VARIANT + + A variant type has a marshaled SIGNATURE + followed by a marshaled value with the type + given in the signature. + Unlike a message signature, the variant signature + can contain only a single complete type. + So "i", "ai" or "(ii)" is OK, but "ii" is not. + + + 1 (alignment of the signature) + + + DICT_ENTRY + + Identical to STRUCT. + + + 8 + + + + + + + + + Valid Object Paths + + + An object path is a name used to refer to an object instance. + Conceptually, each participant in a D-Bus message exchange may have + any number of object instances (think of C++ or Java objects) and each + such instance will have a path. Like a filesystem, the object + instances in an application form a hierarchical tree. + + + + The following rules define a valid object path. Implementations must + not send or accept messages with invalid object paths. + + + + The path may be of any length. + + + + + The path must begin with an ASCII '/' (integer 47) character, + and must consist of elements separated by slash characters. + + + + + Each element must only contain the ASCII characters + "[A-Z][a-z][0-9]_" + + + + + No element may be the empty string. + + + + + Multiple '/' characters cannot occur in sequence. + + + + + A trailing '/' character is not allowed unless the + path is the root path (a single '/' character). + + + + + + + + + + Valid Signatures + + An implementation must not send or accept invalid signatures. + Valid signatures will conform to the following rules: + + + + The signature ends with a nul byte. + + + + + The signature is a list of single complete types. + Arrays must have element types, and structs must + have both open and close parentheses. + + + + + Only type codes and open and close parentheses are + allowed in the signature. The STRUCT type code + is not allowed in signatures, because parentheses + are used instead. + + + + + The maximum depth of container type nesting is 32 array type + codes and 32 open parentheses. This implies that the maximum + total depth of recursion is 64, for an "array of array of array + of ... struct of struct of struct of ..." where there are 32 + array and 32 struct. + + + + + The maximum length of a signature is 255. + + + + + Signatures must be nul-terminated. + + + + + + + + + + Message Format + + + A message consists of a header and a body. The header is a block of + values with a fixed signature and meaning. The body is a separate block + of values, with a signature specified in the header. + + + + The length of the header must be a multiple of 8, allowing the body to + begin on an 8-byte boundary when storing the entire message in a single + buffer. If the header does not naturally end on an 8-byte boundary + up to 7 bytes of nul-initialized alignment padding must be added. + + + + The message body need not end on an 8-byte boundary. + + + + The maximum length of a message, including header, header alignment padding, + and body is 2 to the 27th power or 134217728. Implementations must not + send or accept messages exceeding this size. + + + + The signature of the header is: + + "yyyyuua(yv)" + + Written out more readably, this is: + + BYTE, BYTE, BYTE, BYTE, UINT32, UINT32, ARRAY of STRUCT of (BYTE,VARIANT) + + + + + These values have the following meanings: + + + + + Value + Description + + + + + 1st BYTE + Endianness flag; ASCII 'l' for little-endian + or ASCII 'B' for big-endian. Both header and body are + in this endianness. + + + 2nd BYTE + Message type. Unknown types must be ignored. + Currently-defined types are described below. + + + + 3rd BYTE + Bitwise OR of flags. Unknown flags + must be ignored. Currently-defined flags are described below. + + + + 4th BYTE + Major protocol version of the sending application. If + the major protocol version of the receiving application does not + match, the applications will not be able to communicate and the + D-Bus connection must be disconnected. The major protocol + version for this version of the specification is 1. + + + + 1st UINT32 + Length in bytes of the message body, starting + from the end of the header. The header ends after + its alignment padding to an 8-boundary. + + + + 2nd UINT32 + The serial of this message, used as a cookie + by the sender to identify the reply corresponding + to this request. This must not be zero. + + + + ARRAY of STRUCT of (BYTE,VARIANT) + An array of zero or more header + fields where the byte is the field code, and the + variant is the field value. The message type determines + which fields are required. + + + + + + + + Message types that can appear in the second byte + of the header are: + + + + + Conventional name + Decimal value + Description + + + + + INVALID + 0 + This is an invalid type. + + + METHOD_CALL + 1 + Method call. + + + METHOD_RETURN + 2 + Method reply with returned data. + + + ERROR + 3 + Error reply. If the first argument exists and is a + string, it is an error message. + + + SIGNAL + 4 + Signal emission. + + + + + + + Flags that can appear in the third byte of the header: + + + + + Conventional name + Hex value + Description + + + + + NO_REPLY_EXPECTED + 0x1 + This message does not expect method return replies or + error replies; the reply can be omitted as an + optimization. However, it is compliant with this specification + to return the reply despite this flag and the only harm + from doing so is extra network traffic. + + + + NO_AUTO_START + 0x2 + The bus must not launch an owner + for the destination name in response to this message. + + + + + + + + + Header Fields + + + The array at the end of the header contains header + fields, where each field is a 1-byte field code followed + by a field value. A header must contain the required header fields for + its message type, and zero or more of any optional header + fields. Future versions of this protocol specification may add new + fields. Implementations must ignore fields they do not + understand. Implementations must not invent their own header fields; + only changes to this specification may introduce new header fields. + + + + Again, if an implementation sees a header field code that it does not + expect, it must ignore that field, as it will be part of a new + (but compatible) version of this specification. This also applies + to known header fields appearing in unexpected messages, for + example: if a signal has a reply serial it must be ignored + even though it has no meaning as of this version of the spec. + + + + However, implementations must not send or accept known header fields + with the wrong type stored in the field value. So for example a + message with an INTERFACE field of type + UINT32 would be considered corrupt. + + + + Here are the currently-defined header fields: + + + + + Conventional Name + Decimal Code + Type + Required In + Description + + + + + INVALID + 0 + N/A + not allowed + Not a valid field name (error if it appears in a message) + + + PATH + 1 + OBJECT_PATH + METHOD_CALL, SIGNAL + The object to send a call to, + or the object a signal is emitted from. + The special path + /org/freedesktop/DBus/Local is reserved; + implementations should not send messages with this path, + and the reference implementation of the bus daemon will + disconnect any application that attempts to do so. + + + + INTERFACE + 2 + STRING + SIGNAL + + The interface to invoke a method call on, or + that a signal is emitted from. Optional for + method calls, required for signals. + The special interface + org.freedesktop.DBus.Local is reserved; + implementations should not send messages with this + interface, and the reference implementation of the bus + daemon will disconnect any application that attempts to + do so. + + + + MEMBER + 3 + STRING + METHOD_CALL, SIGNAL + The member, either the method name or signal name. + + + ERROR_NAME + 4 + STRING + ERROR + The name of the error that occurred, for errors + + + REPLY_SERIAL + 5 + UINT32 + ERROR, METHOD_RETURN + The serial number of the message this message is a reply + to. (The serial number is the second UINT32 in the header.) + + + DESTINATION + 6 + STRING + optional + The name of the connection this message is intended for. + Only used in combination with the message bus, see + . + + + SENDER + 7 + STRING + optional + Unique name of the sending connection. + The message bus fills in this field so it is reliable; the field is + only meaningful in combination with the message bus. + + + SIGNATURE + 8 + SIGNATURE + optional + The signature of the message body. + If omitted, it is assumed to be the + empty signature "" (i.e. the body must be 0-length). + + + + + + + + + + Valid Names + + The various names in D-Bus messages have some restrictions. + + + There is a maximum name length + of 255 which applies to bus names, interfaces, and members. + + + Interface names + + Interfaces have names with type STRING, meaning that + they must be valid UTF-8. However, there are also some + additional restrictions that apply to interface names + specifically: + + Interface names are composed of 1 or more elements separated by + a period ('.') character. All elements must contain at least + one character. + + + Each element must only contain the ASCII characters + "[A-Z][a-z][0-9]_" and must not begin with a digit. + + + + Interface names must contain at least one '.' (period) + character (and thus at least two elements). + + + Interface names must not begin with a '.' (period) character. + Interface names must not exceed the maximum name length. + + + + + Bus names + + Connections have one or more bus names associated with them. + A connection has exactly one bus name that is a unique connection + name. The unique connection name remains with the connection for + its entire lifetime. + A bus name is of type STRING, + meaning that it must be valid UTF-8. However, there are also + some additional restrictions that apply to bus names + specifically: + + Bus names that start with a colon (':') + character are unique connection names. + + + Bus names are composed of 1 or more elements separated by + a period ('.') character. All elements must contain at least + one character. + + + Each element must only contain the ASCII characters + "[A-Z][a-z][0-9]_-". Only elements that are part of a unique + connection name may begin with a digit, elements in + other bus names must not begin with a digit. + + + + Bus names must contain at least one '.' (period) + character (and thus at least two elements). + + + Bus names must not begin with a '.' (period) character. + Bus names must not exceed the maximum name length. + + + + Note that the hyphen ('-') character is allowed in bus names but + not in interface names. + + + + Member names + + Member (i.e. method or signal) names: + + Must only contain the ASCII characters + "[A-Z][a-z][0-9]_" and may not begin with a + digit. + Must not contain the '.' (period) character. + Must not exceed the maximum name length. + Must be at least 1 byte in length. + + + + + Error names + + Error names have the same restrictions as interface names. + + + + + + Message Types + + Each of the message types (METHOD_CALL, METHOD_RETURN, ERROR, and + SIGNAL) has its own expected usage conventions and header fields. + This section describes these conventions. + + + Method Calls + + Some messages invoke an operation on a remote object. These are + called method call messages and have the type tag METHOD_CALL. Such + messages map naturally to methods on objects in a typical program. + + + A method call message is required to have a MEMBER header field + indicating the name of the method. Optionally, the message has an + INTERFACE field giving the interface the method is a part of. In the + absence of an INTERFACE field, if two interfaces on the same object have + a method with the same name, it is undefined which of the two methods + will be invoked. Implementations may also choose to return an error in + this ambiguous case. However, if a method name is unique + implementations must not require an interface field. + + + Method call messages also include a PATH field + indicating the object to invoke the method on. If the call is passing + through a message bus, the message will also have a + DESTINATION field giving the name of the connection + to receive the message. + + + When an application handles a method call message, it is required to + return a reply. The reply is identified by a REPLY_SERIAL header field + indicating the serial number of the METHOD_CALL being replied to. The + reply can have one of two types; either METHOD_RETURN or ERROR. + + + If the reply has type METHOD_RETURN, the arguments to the reply message + are the return value(s) or "out parameters" of the method call. + If the reply has type ERROR, then an "exception" has been thrown, + and the call fails; no return value will be provided. It makes + no sense to send multiple replies to the same method call. + + + Even if a method call has no return values, a METHOD_RETURN + reply is required, so the caller will know the method + was successfully processed. + + + The METHOD_RETURN or ERROR reply message must have the REPLY_SERIAL + header field. + + + If a METHOD_CALL message has the flag NO_REPLY_EXPECTED, + then as an optimization the application receiving the method + call may choose to omit the reply message (regardless of + whether the reply would have been METHOD_RETURN or ERROR). + However, it is also acceptable to ignore the NO_REPLY_EXPECTED + flag and reply anyway. + + + Unless a message has the flag NO_AUTO_START, if the + destination name does not exist then a program to own the destination + name will be started before the message is delivered. The message + will be held until the new program is successfully started or has + failed to start; in case of failure, an error will be returned. This + flag is only relevant in the context of a message bus, it is ignored + during one-to-one communication with no intermediate bus. + + + Mapping method calls to native APIs + + APIs for D-Bus may map method calls to a method call in a specific + programming language, such as C++, or may map a method call written + in an IDL to a D-Bus message. + + + In APIs of this nature, arguments to a method are often termed "in" + (which implies sent in the METHOD_CALL), or "out" (which implies + returned in the METHOD_RETURN). Some APIs such as CORBA also have + "inout" arguments, which are both sent and received, i.e. the caller + passes in a value which is modified. Mapped to D-Bus, an "inout" + argument is equivalent to an "in" argument, followed by an "out" + argument. You can't pass things "by reference" over the wire, so + "inout" is purely an illusion of the in-process API. + + + Given a method with zero or one return values, followed by zero or more + arguments, where each argument may be "in", "out", or "inout", the + caller constructs a message by appending each "in" or "inout" argument, + in order. "out" arguments are not represented in the caller's message. + + + The recipient constructs a reply by appending first the return value + if any, then each "out" or "inout" argument, in order. + "in" arguments are not represented in the reply message. + + + Error replies are normally mapped to exceptions in languages that have + exceptions. + + + In converting from native APIs to D-Bus, it is perhaps nice to + map D-Bus naming conventions ("FooBar") to native conventions + such as "fooBar" or "foo_bar" automatically. This is OK + as long as you can say that the native API is one that + was specifically written for D-Bus. It makes the most sense + when writing object implementations that will be exported + over the bus. Object proxies used to invoke remote D-Bus + objects probably need the ability to call any D-Bus method, + and thus a magic name mapping like this could be a problem. + + + This specification doesn't require anything of native API bindings; + the preceding is only a suggested convention for consistency + among bindings. + + + + + + Signal Emission + + Unlike method calls, signal emissions have no replies. + A signal emission is simply a single message of type SIGNAL. + It must have three header fields: PATH giving the object + the signal was emitted from, plus INTERFACE and MEMBER giving + the fully-qualified name of the signal. The INTERFACE header is required + for signals, though it is optional for method calls. + + + + + Errors + + Messages of type ERROR are most commonly replies + to a METHOD_CALL, but may be returned in reply + to any kind of message. The message bus for example + will return an ERROR in reply to a signal emission if + the bus does not have enough memory to send the signal. + + + An ERROR may have any arguments, but if the first + argument is a STRING, it must be an error message. + The error message may be logged or shown to the user + in some way. + + + + + Notation in this document + + This document uses a simple pseudo-IDL to describe particular method + calls and signals. Here is an example of a method call: + + org.freedesktop.DBus.StartServiceByName (in STRING name, in UINT32 flags, + out UINT32 resultcode) + + This means INTERFACE = org.freedesktop.DBus, MEMBER = StartServiceByName, + METHOD_CALL arguments are STRING and UINT32, METHOD_RETURN argument + is UINT32. Remember that the MEMBER field can't contain any '.' (period) + characters so it's known that the last part of the name in + the "IDL" is the member name. + + + In C++ that might end up looking like this: + + unsigned int org::freedesktop::DBus::StartServiceByName (const char *name, + unsigned int flags); + + or equally valid, the return value could be done as an argument: + + void org::freedesktop::DBus::StartServiceByName (const char *name, + unsigned int flags, + unsigned int *resultcode); + + It's really up to the API designer how they want to make + this look. You could design an API where the namespace wasn't used + in C++, using STL or Qt, using varargs, or whatever you wanted. + + + Signals are written as follows: + + org.freedesktop.DBus.NameLost (STRING name) + + Signals don't specify "in" vs. "out" because only + a single direction is possible. + + + It isn't especially encouraged to use this lame pseudo-IDL in actual + API implementations; you might use the native notation for the + language you're using, or you might use COM or CORBA IDL, for example. + + + + + + Invalid Protocol and Spec Extensions + + + For security reasons, the D-Bus protocol should be strictly parsed and + validated, with the exception of defined extension points. Any invalid + protocol or spec violations should result in immediately dropping the + connection without notice to the other end. Exceptions should be + carefully considered, e.g. an exception may be warranted for a + well-understood idiosyncrasy of a widely-deployed implementation. In + cases where the other end of a connection is 100% trusted and known to + be friendly, skipping validation for performance reasons could also make + sense in certain cases. + + + + Generally speaking violations of the "must" requirements in this spec + should be considered possible attempts to exploit security, and violations + of the "should" suggestions should be considered legitimate (though perhaps + they should generate an error in some cases). + + + + The following extension points are built in to D-Bus on purpose and must + not be treated as invalid protocol. The extension points are intended + for use by future versions of this spec, they are not intended for third + parties. At the moment, the only way a third party could extend D-Bus + without breaking interoperability would be to introduce a way to negotiate new + feature support as part of the auth protocol, using EXTENSION_-prefixed + commands. There is not yet a standard way to negotiate features. + + + + In the authentication protocol (see ) unknown + commands result in an ERROR rather than a disconnect. This enables + future extensions to the protocol. Commands starting with EXTENSION_ are + reserved for third parties. + + + + + The authentication protocol supports pluggable auth mechanisms. + + + + + The address format (see ) supports new + kinds of transport. + + + + + Messages with an unknown type (something other than + METHOD_CALL, METHOD_RETURN, + ERROR, SIGNAL) are ignored. + Unknown-type messages must still be well-formed in the same way + as the known messages, however. They still have the normal + header and body. + + + + + Header fields with an unknown or unexpected field code must be ignored, + though again they must still be well-formed. + + + + + New standard interfaces (with new methods and signals) can of course be added. + + + + + + + + + + + Authentication Protocol + + Before the flow of messages begins, two applications must + authenticate. A simple plain-text protocol is used for + authentication; this protocol is a SASL profile, and maps fairly + directly from the SASL specification. The message encoding is + NOT used here, only plain text messages. + + + In examples, "C:" and "S:" indicate lines sent by the client and + server respectively. + + + Protocol Overview + + The protocol is a line-based protocol, where each line ends with + \r\n. Each line begins with an all-caps ASCII command name containing + only the character range [A-Z_], a space, then any arguments for the + command, then the \r\n ending the line. The protocol is + case-sensitive. All bytes must be in the ASCII character set. + + Commands from the client to the server are as follows: + + + AUTH [mechanism] [initial-response] + CANCEL + BEGIN + DATA <data in hex encoding> + ERROR [human-readable error explanation] + + + From server to client are as follows: + + + REJECTED <space-separated list of mechanism names> + OK <GUID in hex> + DATA <data in hex encoding> + ERROR + + + + Unofficial extensions to the command set must begin with the letters + "EXTENSION_", to avoid conflicts with future official commands. + For example, "EXTENSION_COM_MYDOMAIN_DO_STUFF". + + + + Special credentials-passing nul byte + + Immediately after connecting to the server, the client must send a + single nul byte. This byte may be accompanied by credentials + information on some operating systems that use sendmsg() with + SCM_CREDS or SCM_CREDENTIALS to pass credentials over UNIX domain + sockets. However, the nul byte must be sent even on other kinds of + socket, and even on operating systems that do not require a byte to be + sent in order to transmit credentials. The text protocol described in + this document begins after the single nul byte. If the first byte + received from the client is not a nul byte, the server may disconnect + that client. + + + A nul byte in any context other than the initial byte is an error; + the protocol is ASCII-only. + + + The credentials sent along with the nul byte may be used with the + SASL mechanism EXTERNAL. + + + + AUTH command + + If an AUTH command has no arguments, it is a request to list + available mechanisms. The server must respond with a REJECTED + command listing the mechanisms it understands, or with an error. + + + If an AUTH command specifies a mechanism, and the server supports + said mechanism, the server should begin exchanging SASL + challenge-response data with the client using DATA commands. + + + If the server does not support the mechanism given in the AUTH + command, it must send either a REJECTED command listing the mechanisms + it does support, or an error. + + + If the [initial-response] argument is provided, it is intended for use + with mechanisms that have no initial challenge (or an empty initial + challenge), as if it were the argument to an initial DATA command. If + the selected mechanism has an initial challenge and [initial-response] + was provided, the server should reject authentication by sending + REJECTED. + + + If authentication succeeds after exchanging DATA commands, + an OK command must be sent to the client. + + + The first octet received by the client after the \r\n of the OK + command must be the first octet of the authenticated/encrypted + stream of D-Bus messages. + + + The first octet received by the server after the \r\n of the BEGIN + command from the client must be the first octet of the + authenticated/encrypted stream of D-Bus messages. + + + + CANCEL Command + + At any time up to sending the BEGIN command, the client may send a + CANCEL command. On receiving the CANCEL command, the server must + send a REJECTED command and abort the current authentication + exchange. + + + + DATA Command + + The DATA command may come from either client or server, and simply + contains a hex-encoded block of data to be interpreted + according to the SASL mechanism in use. + + + Some SASL mechanisms support sending an "empty string"; + FIXME we need some way to do this. + + + + BEGIN Command + + The BEGIN command acknowledges that the client has received an + OK command from the server, and that the stream of messages + is about to begin. + + + The first octet received by the server after the \r\n of the BEGIN + command from the client must be the first octet of the + authenticated/encrypted stream of D-Bus messages. + + + + REJECTED Command + + The REJECTED command indicates that the current authentication + exchange has failed, and further exchange of DATA is inappropriate. + The client would normally try another mechanism, or try providing + different responses to challenges. + + Optionally, the REJECTED command has a space-separated list of + available auth mechanisms as arguments. If a server ever provides + a list of supported mechanisms, it must provide the same list + each time it sends a REJECTED message. Clients are free to + ignore all lists received after the first. + + + + OK Command + + The OK command indicates that the client has been authenticated, + and that further communication will be a stream of D-Bus messages + (optionally encrypted, as negotiated) rather than this protocol. + + + The first octet received by the client after the \r\n of the OK + command must be the first octet of the authenticated/encrypted + stream of D-Bus messages. + + + The client must respond to the OK command by sending a BEGIN + command, followed by its stream of messages, or by disconnecting. + The server must not accept additional commands using this protocol + after the OK command has been sent. + + + The OK command has one argument, which is the GUID of the server. + See for more on server GUIDs. + + + + ERROR Command + + The ERROR command indicates that either server or client did not + know a command, does not accept the given command in the current + context, or did not understand the arguments to the command. This + allows the protocol to be extended; a client or server can send a + command present or permitted only in new protocol versions, and if + an ERROR is received instead of an appropriate response, fall back + to using some other technique. + + + If an ERROR is sent, the server or client that sent the + error must continue as if the command causing the ERROR had never been + received. However, the the server or client receiving the error + should try something other than whatever caused the error; + if only canceling/rejecting the authentication. + + + If the D-Bus protocol changes incompatibly at some future time, + applications implementing the new protocol would probably be able to + check for support of the new protocol by sending a new command and + receiving an ERROR from applications that don't understand it. Thus the + ERROR feature of the auth protocol is an escape hatch that lets us + negotiate extensions or changes to the D-Bus protocol in the future. + + + + Authentication examples + + +
+ Example of successful magic cookie authentication + + (MAGIC_COOKIE is a made up mechanism) + + C: AUTH MAGIC_COOKIE 3138363935333137393635383634 + S: OK 1234deadbeef + C: BEGIN + +
+
+ Example of finding out mechanisms then picking one + + C: AUTH + S: REJECTED KERBEROS_V4 SKEY + C: AUTH SKEY 7ab83f32ee + S: DATA 8799cabb2ea93e + C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f + S: OK 1234deadbeef + C: BEGIN + +
+
+ Example of client sends unknown command then falls back to regular auth + + C: FOOBAR + S: ERROR + C: AUTH MAGIC_COOKIE 3736343435313230333039 + S: OK 1234deadbeef + C: BEGIN + +
+
+ Example of server doesn't support initial auth mechanism + + C: AUTH MAGIC_COOKIE 3736343435313230333039 + S: REJECTED KERBEROS_V4 SKEY + C: AUTH SKEY 7ab83f32ee + S: DATA 8799cabb2ea93e + C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f + S: OK 1234deadbeef + C: BEGIN + +
+
+ Example of wrong password or the like followed by successful retry + + C: AUTH MAGIC_COOKIE 3736343435313230333039 + S: REJECTED KERBEROS_V4 SKEY + C: AUTH SKEY 7ab83f32ee + S: DATA 8799cabb2ea93e + C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f + S: REJECTED + C: AUTH SKEY 7ab83f32ee + S: DATA 8799cabb2ea93e + C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f + S: OK 1234deadbeef + C: BEGIN + +
+
+ Example of skey cancelled and restarted + + C: AUTH MAGIC_COOKIE 3736343435313230333039 + S: REJECTED KERBEROS_V4 SKEY + C: AUTH SKEY 7ab83f32ee + S: DATA 8799cabb2ea93e + C: CANCEL + S: REJECTED + C: AUTH SKEY 7ab83f32ee + S: DATA 8799cabb2ea93e + C: DATA 8ac876e8f68ee9809bfa876e6f9876g8fa8e76e98f + S: OK 1234deadbeef + C: BEGIN + +
+
+
+ + Authentication state diagrams + + + This section documents the auth protocol in terms of + a state machine for the client and the server. This is + probably the most robust way to implement the protocol. + + + + Client states + + + To more precisely describe the interaction between the + protocol state machine and the authentication mechanisms the + following notation is used: MECH(CHALL) means that the + server challenge CHALL was fed to the mechanism MECH, which + returns one of + + + + + CONTINUE(RESP) means continue the auth conversation + and send RESP as the response to the server; + + + + + + OK(RESP) means that after sending RESP to the server + the client side of the auth conversation is finished + and the server should return "OK"; + + + + + + ERROR means that CHALL was invalid and could not be + processed. + + + + + Both RESP and CHALL may be empty. + + + + The Client starts by getting an initial response from the + default mechanism and sends AUTH MECH RESP, or AUTH MECH if + the mechanism did not provide an initial response. If the + mechanism returns CONTINUE, the client starts in state + WaitingForData, if the mechanism + returns OK the client starts in state + WaitingForOK. + + + + The client should keep track of available mechanisms and + which it mechanisms it has already attempted. This list is + used to decide which AUTH command to send. When the list is + exhausted, the client should give up and close the + connection. + + + + <emphasis>WaitingForData</emphasis> + + + + + Receive DATA CHALL + + + MECH(CHALL) returns CONTINUE(RESP) → send + DATA RESP, goto + WaitingForData + + + + MECH(CHALL) returns OK(RESP) → send DATA + RESP, goto WaitingForOK + + + + MECH(CHALL) returns ERROR → send ERROR + [msg], goto WaitingForData + + + + + + + + Receive REJECTED [mechs] → + send AUTH [next mech], goto + WaitingForData or WaitingForOK + + + + + Receive ERROR → send + CANCEL, goto + WaitingForReject + + + + + Receive OK → send + BEGIN, terminate auth + conversation, authenticated + + + + + Receive anything else → send + ERROR, goto + WaitingForData + + + + + + + + <emphasis>WaitingForOK</emphasis> + + + + + Receive OK → send BEGIN, terminate auth + conversation, authenticated + + + + + Receive REJECT [mechs] → send AUTH [next mech], + goto WaitingForData or + WaitingForOK + + + + + + Receive DATA → send CANCEL, goto + WaitingForReject + + + + + + Receive ERROR → send CANCEL, goto + WaitingForReject + + + + + + Receive anything else → send ERROR, goto + WaitingForOK + + + + + + + + <emphasis>WaitingForReject</emphasis> + + + + + Receive REJECT [mechs] → send AUTH [next mech], + goto WaitingForData or + WaitingForOK + + + + + + Receive anything else → terminate auth + conversation, disconnect + + + + + + + + + + Server states + + + For the server MECH(RESP) means that the client response + RESP was fed to the the mechanism MECH, which returns one of + + + + + CONTINUE(CHALL) means continue the auth conversation and + send CHALL as the challenge to the client; + + + + + + OK means that the client has been successfully + authenticated; + + + + + + REJECT means that the client failed to authenticate or + there was an error in RESP. + + + + + The server starts out in state + WaitingForAuth. If the client is + rejected too many times the server must disconnect the + client. + + + + <emphasis>WaitingForAuth</emphasis> + + + + + + Receive AUTH → send REJECTED [mechs], goto + WaitingForAuth + + + + + + Receive AUTH MECH RESP + + + + MECH not valid mechanism → send REJECTED + [mechs], goto + WaitingForAuth + + + + MECH(RESP) returns CONTINUE(CHALL) → send + DATA CHALL, goto + WaitingForData + + + + MECH(RESP) returns OK → send OK, goto + WaitingForBegin + + + + MECH(RESP) returns REJECT → send REJECTED + [mechs], goto + WaitingForAuth + + + + + + + + Receive BEGIN → terminate + auth conversation, disconnect + + + + + + Receive ERROR → send REJECTED [mechs], goto + WaitingForAuth + + + + + + Receive anything else → send + ERROR, goto + WaitingForAuth + + + + + + + + + <emphasis>WaitingForData</emphasis> + + + + + Receive DATA RESP + + + MECH(RESP) returns CONTINUE(CHALL) → send + DATA CHALL, goto + WaitingForData + + + + MECH(RESP) returns OK → send OK, goto + WaitingForBegin + + + + MECH(RESP) returns REJECT → send REJECTED + [mechs], goto + WaitingForAuth + + + + + + + + Receive BEGIN → terminate auth conversation, + disconnect + + + + + + Receive CANCEL → send REJECTED [mechs], goto + WaitingForAuth + + + + + + Receive ERROR → send REJECTED [mechs], goto + WaitingForAuth + + + + + + Receive anything else → send ERROR, goto + WaitingForData + + + + + + + + <emphasis>WaitingForBegin</emphasis> + + + + + Receive BEGIN → terminate auth conversation, + client authenticated + + + + + + Receive CANCEL → send REJECTED [mechs], goto + WaitingForAuth + + + + + + Receive ERROR → send REJECTED [mechs], goto + WaitingForAuth + + + + + + Receive anything else → send ERROR, goto + WaitingForBegin + + + + + + + + + + + Authentication mechanisms + + This section describes some new authentication mechanisms. + D-Bus also allows any standard SASL mechanism of course. + + + DBUS_COOKIE_SHA1 + + The DBUS_COOKIE_SHA1 mechanism is designed to establish that a client + has the ability to read a private file owned by the user being + authenticated. If the client can prove that it has access to a secret + cookie stored in this file, then the client is authenticated. + Thus the security of DBUS_COOKIE_SHA1 depends on a secure home + directory. + + + Throughout this description, "hex encoding" must output the digits + from a to f in lower-case; the digits A to F must not be used + in the DBUS_COOKIE_SHA1 mechanism. + + + Authentication proceeds as follows: + + + + The client sends the username it would like to authenticate + as, hex-encoded. + + + + + The server sends the name of its "cookie context" (see below); a + space character; the integer ID of the secret cookie the client + must demonstrate knowledge of; a space character; then a + randomly-generated challenge string, all of this hex-encoded into + one, single string. + + + + + The client locates the cookie and generates its own + randomly-generated challenge string. The client then concatenates + the server's decoded challenge, a ":" character, its own challenge, + another ":" character, and the cookie. It computes the SHA-1 hash + of this composite string as a hex digest. It concatenates the + client's challenge string, a space character, and the SHA-1 hex + digest, hex-encodes the result and sends it back to the server. + + + + + The server generates the same concatenated string used by the + client and computes its SHA-1 hash. It compares the hash with + the hash received from the client; if the two hashes match, the + client is authenticated. + + + + + + Each server has a "cookie context," which is a name that identifies a + set of cookies that apply to that server. A sample context might be + "org_freedesktop_session_bus". Context names must be valid ASCII, + nonzero length, and may not contain the characters slash ("/"), + backslash ("\"), space (" "), newline ("\n"), carriage return ("\r"), + tab ("\t"), or period ("."). There is a default context, + "org_freedesktop_general" that's used by servers that do not specify + otherwise. + + + Cookies are stored in a user's home directory, in the directory + ~/.dbus-keyrings/. This directory must + not be readable or writable by other users. If it is, + clients and servers must ignore it. The directory + contains cookie files named after the cookie context. + + + A cookie file contains one cookie per line. Each line + has three space-separated fields: + + + + The cookie ID number, which must be a non-negative integer and + may not be used twice in the same file. + + + + + The cookie's creation time, in UNIX seconds-since-the-epoch + format. + + + + + The cookie itself, a hex-encoded random block of bytes. The cookie + may be of any length, though obviously security increases + as the length increases. + + + + + + Only server processes modify the cookie file. + They must do so with this procedure: + + + + Create a lockfile name by appending ".lock" to the name of the + cookie file. The server should attempt to create this file + using O_CREAT | O_EXCL. If file creation + fails, the lock fails. Servers should retry for a reasonable + period of time, then they may choose to delete an existing lock + to keep users from having to manually delete a stale + lock. Lockfiles are used instead of real file + locking fcntl() because real locking + implementations are still flaky on network + filesystems. + + + + + Once the lockfile has been created, the server loads the cookie + file. It should then delete any cookies that are old (the + timeout can be fairly short), or more than a reasonable + time in the future (so that cookies never accidentally + become permanent, if the clock was set far into the future + at some point). If no recent keys remain, the + server may generate a new key. + + + + + The pruned and possibly added-to cookie file + must be resaved atomically (using a temporary + file which is rename()'d). + + + + + The lock must be dropped by deleting the lockfile. + + + + + + Clients need not lock the file in order to load it, + because servers are required to save the file atomically. + + + +
+ + Server Addresses + + Server addresses consist of a transport name followed by a colon, and + then an optional, comma-separated list of keys and values in the form key=value. + Each value is escaped. + + + For example: + unix:path=/tmp/dbus-test + Which is the address to a unix socket with the path /tmp/dbus-test. + + + Value escaping is similar to URI escaping but simpler. + + + + The set of optionally-escaped bytes is: + [0-9A-Za-z_-/.\]. To escape, each + byte (note, not character) which is not in the + set of optionally-escaped bytes must be replaced with an ASCII + percent (%) and the value of the byte in hex. + The hex value must always be two digits, even if the first digit is + zero. The optionally-escaped bytes may be escaped if desired. + + + + + To unescape, append each byte in the value; if a byte is an ASCII + percent (%) character then append the following + hex value instead. It is an error if a % byte + does not have two hex digits following. It is an error if a + non-optionally-escaped byte is seen unescaped. + + + + The set of optionally-escaped bytes is intended to preserve address + readability and convenience. + + + + A server may specify a key-value pair with the key guid + and the value a hex-encoded 16-byte sequence. + describes the format of the guid field. If present, + this UUID may be used to distinguish one server address from another. A + server should use a different UUID for each address it listens on. For + example, if a message bus daemon offers both UNIX domain socket and TCP + connections, but treats clients the same regardless of how they connect, + those two connections are equivalent post-connection but should have + distinct UUIDs to distinguish the kinds of connection. + + + + The intent of the address UUID feature is to allow a client to avoid + opening multiple identical connections to the same server, by allowing the + client to check whether an address corresponds to an already-existing + connection. Comparing two addresses is insufficient, because addresses + can be recycled by distinct servers, and equivalent addresses may look + different if simply compared as strings (for example, the host in a TCP + address can be given as an IP address or as a hostname). + + + + Note that the address key is guid even though the + rest of the API and documentation says "UUID," for historical reasons. + + + + [FIXME clarify if attempting to connect to each is a requirement + or just a suggestion] + When connecting to a server, multiple server addresses can be + separated by a semi-colon. The library will then try to connect + to the first address and if that fails, it'll try to connect to + the next one specified, and so forth. For example + unix:path=/tmp/dbus-test;unix:path=/tmp/dbus-test2 + + + + + + Transports + + [FIXME we need to specify in detail each transport and its possible arguments] + + Current transports include: unix domain sockets (including + abstract namespace on linux), TCP/IP, and a debug/testing transport using + in-process pipes. Future possible transports include one that + tunnels over X11 protocol. + + + + Unix Domain Sockets + + Unix domain sockets can be either paths in the file system or on Linux + kernels, they can be abstract which are similar to paths but + do not show up in the file system. + + + + When a socket is opened by the D-Bus library it truncates the path + name right before the first trailing Nul byte. This is true for both + normal paths and abstract paths. Note that this is a departure from + previous versions of D-Bus that would create sockets with a fixed + length path name. Names which were shorter than the fixed length + would be padded by Nul bytes. + + + + + + Naming Conventions + + + D-Bus namespaces are all lowercase and correspond to reversed domain + names, as with Java. e.g. "org.freedesktop" + + + Interface, signal, method, and property names are "WindowsStyleCaps", note + that the first letter is capitalized, unlike Java. + + + Object paths are normally all lowercase with underscores used rather than + hyphens. + + + + + UUIDs + + A working D-Bus implementation uses universally-unique IDs in two places. + First, each server address has a UUID identifying the address, + as described in . Second, each operating + system kernel instance running a D-Bus client or server has a UUID + identifying that kernel, retrieved by invoking the method + org.freedesktop.DBus.Peer.GetMachineId() (see ). + + + The term "UUID" in this document is intended literally, i.e. an + identifier that is universally unique. It is not intended to refer to + RFC4122, and in fact the D-Bus UUID is not compatible with that RFC. + + + The UUID must contain 128 bits of data and be hex-encoded. The + hex-encoded string may not contain hyphens or other non-hex-digit + characters, and it must be exactly 32 characters long. To generate a + UUID, the current reference implementation concatenates 96 bits of random + data followed by the 32-bit time in seconds since the UNIX epoch (in big + endian byte order). + + + It would also be acceptable and probably better to simply generate 128 + bits of random data, as long as the random number generator is of high + quality. The timestamp could conceivably help if the random bits are not + very random. With a quality random number generator, collisions are + extremely unlikely even with only 96 bits, so it's somewhat academic. + + + Implementations should, however, stick to random data for the first 96 bits + of the UUID. + + + + + Standard Interfaces + + See for details on + the notation used in this section. There are some standard interfaces + that may be useful across various D-Bus applications. + + + <literal>org.freedesktop.DBus.Peer</literal> + + The org.freedesktop.DBus.Peer interface + has two methods: + + org.freedesktop.DBus.Peer.Ping () + org.freedesktop.DBus.Peer.GetMachineId (out STRING machine_uuid) + + + + On receipt of the METHOD_CALL message + org.freedesktop.DBus.Peer.Ping, an application should do + nothing other than reply with a METHOD_RETURN as + usual. It does not matter which object path a ping is sent to. The + reference implementation handles this method automatically. + + + On receipt of the METHOD_CALL message + org.freedesktop.DBus.Peer.GetMachineId, an application should + reply with a METHOD_RETURN containing a hex-encoded + UUID representing the identity of the machine the process is running on. + This UUID must be the same for all processes on a single system at least + until that system next reboots. It should be the same across reboots + if possible, but this is not always possible to implement and is not + guaranteed. + It does not matter which object path a GetMachineId is sent to. The + reference implementation handles this method automatically. + + + The UUID is intended to be per-instance-of-the-operating-system, so may represent + a virtual machine running on a hypervisor, rather than a physical machine. + Basically if two processes see the same UUID, they should also see the same + shared memory, UNIX domain sockets, process IDs, and other features that require + a running OS kernel in common between the processes. + + + The UUID is often used where other programs might use a hostname. Hostnames + can change without rebooting, however, or just be "localhost" - so the UUID + is more robust. + + + explains the format of the UUID. + + + + + <literal>org.freedesktop.DBus.Introspectable</literal> + + This interface has one method: + + org.freedesktop.DBus.Introspectable.Introspect (out STRING xml_data) + + + + Objects instances may implement + Introspect which returns an XML description of + the object, including its interfaces (with signals and methods), objects + below it in the object path tree, and its properties. + + + describes the format of this XML string. + + + + <literal>org.freedesktop.DBus.Properties</literal> + + Many native APIs will have a concept of object properties + or attributes. These can be exposed via the + org.freedesktop.DBus.Properties interface. + + + + org.freedesktop.DBus.Properties.Get (in STRING interface_name, + in STRING property_name, + out VARIANT value); + org.freedesktop.DBus.Properties.Set (in STRING interface_name, + in STRING property_name, + in VARIANT value); + org.freedesktop.DBus.Properties.GetAll (in STRING interface_name, + out DICT<STRING,VARIANT> props); + + + + The available properties and whether they are writable can be determined + by calling org.freedesktop.DBus.Introspectable.Introspect, + see . + + + An empty string may be provided for the interface name; in this case, + if there are multiple properties on an object with the same name, + the results are undefined (picking one by according to an arbitrary + deterministic rule, or returning an error, are the reasonable + possibilities). + + + + + + Introspection Data Format + + As described in , + objects may be introspected at runtime, returning an XML string + that describes the object. The same XML format may be used in + other contexts as well, for example as an "IDL" for generating + static language bindings. + + + Here is an example of introspection data: + + <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> + <node name="/org/freedesktop/sample_object"> + <interface name="org.freedesktop.SampleInterface"> + <method name="Frobate"> + <arg name="foo" type="i" direction="in"/> + <arg name="bar" type="s" direction="out"/> + <arg name="baz" type="a{us}" direction="out"/> + <annotation name="org.freedesktop.DBus.Deprecated" value="true"/> + </method> + <method name="Bazify"> + <arg name="bar" type="(iiu)" direction="in"/> + <arg name="bar" type="v" direction="out"/> + </method> + <method name="Mogrify"> + <arg name="bar" type="(iiav)" direction="in"/> + </method> + <signal name="Changed"> + <arg name="new_value" type="b"/> + </signal> + <property name="Bar" type="y" access="readwrite"/> + </interface> + <node name="child_of_sample_object"/> + <node name="another_child_of_sample_object"/> + </node> + + + + A more formal DTD and spec needs writing, but here are some quick notes. + + + + Only the root <node> element can omit the node name, as it's + known to be the object that was introspected. If the root + <node> does have a name attribute, it must be an absolute + object path. If child <node> have object paths, they must be + relative. + + + + + If a child <node> has any sub-elements, then they + must represent a complete introspection of the child. + If a child <node> is empty, then it may or may + not have sub-elements; the child must be introspected + in order to find out. The intent is that if an object + knows that its children are "fast" to introspect + it can go ahead and return their information, but + otherwise it can omit it. + + + + + The direction element on <arg> may be omitted, + in which case it defaults to "in" for method calls + and "out" for signals. Signals only allow "out" + so while direction may be specified, it's pointless. + + + + + The possible directions are "in" and "out", + unlike CORBA there is no "inout" + + + + + The possible property access flags are + "readwrite", "read", and "write" + + + + + Multiple interfaces can of course be listed for + one <node>. + + + + + The "name" attribute on arguments is optional. + + + + + + Method, interface, property, and signal elements may have + "annotations", which are generic key/value pairs of metadata. + They are similar conceptually to Java's annotations and C# attributes. + Well-known annotations: + + + + + + Name + Values (separated by ,) + Description + + + + + org.freedesktop.DBus.Deprecated + true,false + Whether or not the entity is deprecated; defaults to false + + + org.freedesktop.DBus.GLib.CSymbol + (string) + The C symbol; may be used for methods and interfaces + + + org.freedesktop.DBus.Method.NoReply + true,false + If set, don't expect a reply to the method call; defaults to false. + + + + + + + Message Bus Specification + + Message Bus Overview + + The message bus accepts connections from one or more applications. + Once connected, applications can exchange messages with other + applications that are also connected to the bus. + + + In order to route messages among connections, the message bus keeps a + mapping from names to connections. Each connection has one + unique-for-the-lifetime-of-the-bus name automatically assigned. + Applications may request additional names for a connection. Additional + names are usually "well-known names" such as + "org.freedesktop.TextEditor". When a name is bound to a connection, + that connection is said to own the name. + + + The bus itself owns a special name, org.freedesktop.DBus. + This name routes messages to the bus, allowing applications to make + administrative requests. For example, applications can ask the bus + to assign a name to a connection. + + + Each name may have queued owners. When an + application requests a name for a connection and the name is already in + use, the bus will optionally add the connection to a queue waiting for + the name. If the current owner of the name disconnects or releases + the name, the next connection in the queue will become the new owner. + + + + This feature causes the right thing to happen if you start two text + editors for example; the first one may request "org.freedesktop.TextEditor", + and the second will be queued as a possible owner of that name. When + the first exits, the second will take over. + + + + Messages may have a DESTINATION field (see ). If the + DESTINATION field is present, it specifies a message + recipient by name. Method calls and replies normally specify this field. + + + + Signals normally do not specify a destination; they are sent to all + applications with message matching rules that + match the message. + + + + When the message bus receives a method call, if the + DESTINATION field is absent, the call is taken to be + a standard one-to-one message and interpreted by the message bus + itself. For example, sending an + org.freedesktop.DBus.Peer.Ping message with no + DESTINATION will cause the message bus itself to + reply to the ping immediately; the message bus will not make this + message visible to other applications. + + + + Continuing the org.freedesktop.DBus.Peer.Ping example, if + the ping message were sent with a DESTINATION name of + com.yoyodyne.Screensaver, then the ping would be + forwarded, and the Yoyodyne Corporation screensaver application would be + expected to reply to the ping. + + + + + Message Bus Names + + Each connection has at least one name, assigned at connection time and + returned in response to the + org.freedesktop.DBus.Hello method call. This + automatically-assigned name is called the connection's unique + name. Unique names are never reused for two different + connections to the same bus. + + + Ownership of a unique name is a prerequisite for interaction with + the message bus. It logically follows that the unique name is always + the first name that an application comes to own, and the last + one that it loses ownership of. + + + Unique connection names must begin with the character ':' (ASCII colon + character); bus names that are not unique names must not begin + with this character. (The bus must reject any attempt by an application + to manually request a name beginning with ':'.) This restriction + categorically prevents "spoofing"; messages sent to a unique name + will always go to the expected connection. + + + When a connection is closed, all the names that it owns are deleted (or + transferred to the next connection in the queue if any). + + + A connection can request additional names to be associated with it using + the org.freedesktop.DBus.RequestName message. describes the format of a valid + name. These names can be released again using the + org.freedesktop.DBus.ReleaseName message. + + + + <literal>org.freedesktop.DBus.RequestName</literal> + + As a method: + + UINT32 RequestName (in STRING name, in UINT32 flags) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Name to request + + + 1 + UINT32 + Flags + + + + + Reply arguments: + + + + + Argument + Type + Description + + + + + 0 + UINT32 + Return value + + + + + + + This method call should be sent to + org.freedesktop.DBus and asks the message bus to + assign the given name to the method caller. Each name maintains a + queue of possible owners, where the head of the queue is the primary + or current owner of the name. Each potential owner in the queue + maintains the DBUS_NAME_FLAG_ALLOW_REPLACEMENT and + DBUS_NAME_FLAG_DO_NOT_QUEUE settings from its latest RequestName + call. When RequestName is invoked the following occurs: + + + + If the method caller is currently the primary owner of the name, + the DBUS_NAME_FLAG_ALLOW_REPLACEMENT and DBUS_NAME_FLAG_DO_NOT_QUEUE + values are updated with the values from the new RequestName call, + and nothing further happens. + + + + + + If the current primary owner (head of the queue) has + DBUS_NAME_FLAG_ALLOW_REPLACEMENT set, and the RequestName + invocation has the DBUS_NAME_FLAG_REPLACE_EXISTING flag, then + the caller of RequestName replaces the current primary owner at + the head of the queue and the current primary owner moves to the + second position in the queue. If the caller of RequestName was + in the queue previously its flags are updated with the values from + the new RequestName in addition to moving it to the head of the queue. + + + + + + If replacement is not possible, and the method caller is + currently in the queue but not the primary owner, its flags are + updated with the values from the new RequestName call. + + + + + + If replacement is not possible, and the method caller is + currently not in the queue, the method caller is appended to the + queue. + + + + + + If any connection in the queue has DBUS_NAME_FLAG_DO_NOT_QUEUE + set and is not the primary owner, it is removed from the + queue. This can apply to the previous primary owner (if it + was replaced) or the method caller (if it updated the + DBUS_NAME_FLAG_DO_NOT_QUEUE flag while still stuck in the + queue, or if it was just added to the queue with that flag set). + + + + + + Note that DBUS_NAME_FLAG_REPLACE_EXISTING results in "jumping the + queue," even if another application already in the queue had specified + DBUS_NAME_FLAG_REPLACE_EXISTING. This comes up if a primary owner + that does not allow replacement goes away, and the next primary owner + does allow replacement. In this case, queued items that specified + DBUS_NAME_FLAG_REPLACE_EXISTING do not + automatically replace the new primary owner. In other words, + DBUS_NAME_FLAG_REPLACE_EXISTING is not saved, it is only used at the + time RequestName is called. This is deliberate to avoid an infinite loop + anytime two applications are both DBUS_NAME_FLAG_ALLOW_REPLACEMENT + and DBUS_NAME_FLAG_REPLACE_EXISTING. + + + The flags argument contains any of the following values logically ORed + together: + + + + + + Conventional Name + Value + Description + + + + + DBUS_NAME_FLAG_ALLOW_REPLACEMENT + 0x1 + + + If an application A specifies this flag and succeeds in + becoming the owner of the name, and another application B + later calls RequestName with the + DBUS_NAME_FLAG_REPLACE_EXISTING flag, then application A + will lose ownership and receive a + org.freedesktop.DBus.NameLost signal, and + application B will become the new owner. If DBUS_NAME_FLAG_ALLOW_REPLACEMENT + is not specified by application A, or DBUS_NAME_FLAG_REPLACE_EXISTING + is not specified by application B, then application B will not replace + application A as the owner. + + + + + DBUS_NAME_FLAG_REPLACE_EXISTING + 0x2 + + + Try to replace the current owner if there is one. If this + flag is not set the application will only become the owner of + the name if there is no current owner. If this flag is set, + the application will replace the current owner if + the current owner specified DBUS_NAME_FLAG_ALLOW_REPLACEMENT. + + + + + DBUS_NAME_FLAG_DO_NOT_QUEUE + 0x4 + + + Without this flag, if an application requests a name that is + already owned, the application will be placed in a queue to + own the name when the current owner gives it up. If this + flag is given, the application will not be placed in the + queue, the request for the name will simply fail. This flag + also affects behavior when an application is replaced as + name owner; by default the application moves back into the + waiting queue, unless this flag was provided when the application + became the name owner. + + + + + + + + The return code can be one of the following values: + + + + + + Conventional Name + Value + Description + + + + + DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER + 1 The caller is now the primary owner of + the name, replacing any previous owner. Either the name had no + owner before, or the caller specified + DBUS_NAME_FLAG_REPLACE_EXISTING and the current owner specified + DBUS_NAME_FLAG_ALLOW_REPLACEMENT. + + + DBUS_REQUEST_NAME_REPLY_IN_QUEUE + 2 + + The name already had an owner, + DBUS_NAME_FLAG_DO_NOT_QUEUE was not specified, and either + the current owner did not specify + DBUS_NAME_FLAG_ALLOW_REPLACEMENT or the requesting + application did not specify DBUS_NAME_FLAG_REPLACE_EXISTING. + + + + DBUS_REQUEST_NAME_REPLY_EXISTS 3 + The name already has an owner, + DBUS_NAME_FLAG_DO_NOT_QUEUE was specified, and either + DBUS_NAME_FLAG_ALLOW_REPLACEMENT was not specified by the + current owner, or DBUS_NAME_FLAG_REPLACE_EXISTING was not + specified by the requesting application. + + + DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER + 4 + The application trying to request ownership of a name is already the owner of it. + + + + + + + + + <literal>org.freedesktop.DBus.ReleaseName</literal> + + As a method: + + UINT32 ReleaseName (in STRING name) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Name to release + + + + + Reply arguments: + + + + + Argument + Type + Description + + + + + 0 + UINT32 + Return value + + + + + + + This method call should be sent to + org.freedesktop.DBus and asks the message bus to + release the method caller's claim to the given name. If the caller is + the primary owner, a new primary owner will be selected from the + queue if any other owners are waiting. If the caller is waiting in + the queue for the name, the caller will removed from the queue and + will not be made an owner of the name if it later becomes available. + If there are no other owners in the queue for the name, it will be + removed from the bus entirely. + + The return code can be one of the following values: + + + + + + Conventional Name + Value + Description + + + + + DBUS_RELEASE_NAME_REPLY_RELEASED + 1 The caller has released his claim on + the given name. Either the caller was the primary owner of + the name, and the name is now unused or taken by somebody + waiting in the queue for the name, or the caller was waiting + in the queue for the name and has now been removed from the + queue. + + + DBUS_RELEASE_NAME_REPLY_NON_EXISTENT + 2 + The given name does not exist on this bus. + + + DBUS_RELEASE_NAME_REPLY_NOT_OWNER + 3 + The caller was not the primary owner of this name, + and was also not waiting in the queue to own this name. + + + + + + + + + + Message Bus Message Routing + + FIXME + + + Match Rules + + An important part of the message bus routing protocol is match + rules. Match rules describe what messages can be sent to a client + based on the contents of the message. When a message is routed + through the bus it is compared to clients' match rules. If any + of the rules match, the message is dispatched to the client. + If none of the rules match the message never leaves the bus. This + is an effective way to control traffic over the bus and to make sure + only relevant message need to be processed by the client. + + + Match rules are added using the AddMatch bus method + (see xref linkend="bus-messages-add-match"/>). Rules are + specified as a string of comma separated key/value pairs. + Excluding a key from the rule indicates a wildcard match. + For instance excluding the the member from a match rule but + adding a sender would let all messages from that sender through. + An example of a complete rule would be + "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',path='/bar/foo',destination=':452345.34',arg2='bar'" + + + The following table describes the keys that can be used to create + a match rule: + The following table summarizes the D-Bus types. + + + + + Key + Possible Values + Description + + + + + type + 'signal', 'method_call', 'method_return', 'error' + Match on the message type. An example of a type match is type='signal' + + + sender + A bus or unique name (see + and respectively) + + Match messages sent by a particular sender. An example of a sender match + is sender='org.freedesktop.Hal' + + + interface + An interface name (see ) + Match messages sent over or to a particular interface. An example of an + interface match is interface='org.freedesktop.Hal.Manager'. + If a message omits the interface header, it must not match any rule + that specifies this key. + + + member + Any valid method or signal name + Matches messages which have the give method or signal name. An example of + a member match is member='NameOwnerChanged' + + + path + An object path (see ) + Matches messages which are sent from or to the given object. An example of a + path match is path='/org/freedesktop/Hal/Manager' + + + destination + A unique name (see ) + Matches messages which are being sent to the given unique name. An + example of a destination match is destination=':1.0' + + + arg[0, 1, 2, 3, ...] + Any string + Arg matches are special and are used for further restricting the + match based on the arguments in the body of a message. As of this time + only string arguments can be matched. An example of an argument match + would be arg3='Foo'. Only argument indexes from 0 to 63 should be + accepted. + + + arg[0, 1, 2, 3, ...]path + Any string + Argument path matches provide a specialised form of wildcard + matching for path-like namespaces. As with normal argument matches, + if the argument is exactly equal to the string given in the match + rule then the rule is satisfied. Additionally, there is also a + match when either the string given in the match rule or the + appropriate message argument ends with '/' and is a prefix of the + other. An example argument path match is arg0path='/aa/bb/'. This + would match messages with first arguments of '/', '/aa/', + '/aa/bb/', '/aa/bb/cc/' and '/aa/bb/cc'. It would not match + messages with first arguments of '/aa/b', '/aa' or even '/aa/bb'. + + + + + + + + + Message Bus Starting Services + + The message bus can start applications on behalf of other applications. + In CORBA terms, this would be called activation. + An application that can be started in this way is called a + service. + + + With D-Bus, starting a service is normally done by name. That is, + applications ask the message bus to start some program that will own a + well-known name, such as org.freedesktop.TextEditor. + This implies a contract documented along with the name + org.freedesktop.TextEditor for which objects + the owner of that name will provide, and what interfaces those + objects will have. + + + To find an executable corresponding to a particular name, the bus daemon + looks for service description files. Service + description files define a mapping from names to executables. Different + kinds of message bus will look for these files in different places, see + . + + + [FIXME the file format should be much better specified than "similar to + .desktop entries" esp. since desktop entries are already + badly-specified. ;-)] Service description files have the ".service" file + extension. The message bus will only load service description files + ending with .service; all other files will be ignored. The file format + is similar to that of desktop + entries. All service description files must be in UTF-8 + encoding. To ensure that there will be no name collisions, service files + must be namespaced using the same mechanism as messages and service + names. + +
+ Example service description file + + # Sample service description file + [D-BUS Service] + Names=org.freedesktop.ConfigurationDatabase;org.gnome.GConf; + Exec=/usr/libexec/gconfd-2 + +
+
+ + When an application asks to start a service by name, the bus daemon tries to + find a service that will own that name. It then tries to spawn the + executable associated with it. If this fails, it will report an + error. [FIXME what happens if two .service files offer the same service; + what kind of error is reported, should we have a way for the client to + choose one?] + + + The executable launched will have the environment variable + DBUS_STARTER_ADDRESS set to the address of the + message bus so it can connect and request the appropriate names. + + + The executable being launched may want to know whether the message bus + starting it is one of the well-known message buses (see ). To facilitate this, the bus must also set + the DBUS_STARTER_BUS_TYPE environment variable if it is one + of the well-known buses. The currently-defined values for this variable + are system for the systemwide message bus, + and session for the per-login-session message + bus. The new executable must still connect to the address given + in DBUS_STARTER_ADDRESS, but may assume that the + resulting connection is to the well-known bus. + + + [FIXME there should be a timeout somewhere, either specified + in the .service file, by the client, or just a global value + and if the client being activated fails to connect within that + timeout, an error should be sent back.] + + + + Message Bus Service Scope + + The "scope" of a service is its "per-", such as per-session, + per-machine, per-home-directory, or per-display. The reference + implementation doesn't yet support starting services in a different + scope from the message bus itself. So e.g. if you start a service + on the session bus its scope is per-session. + + + We could add an optional scope to a bus name. For example, for + per-(display,session pair), we could have a unique ID for each display + generated automatically at login and set on screen 0 by executing a + special "set display ID" binary. The ID would be stored in a + _DBUS_DISPLAY_ID property and would be a string of + random bytes. This ID would then be used to scope names. + Starting/locating a service could be done by ID-name pair rather than + only by name. + + + Contrast this with a per-display scope. To achieve that, we would + want a single bus spanning all sessions using a given display. + So we might set a _DBUS_DISPLAY_BUS_ADDRESS + property on screen 0 of the display, pointing to this bus. + + +
+ + + Well-known Message Bus Instances + + Two standard message bus instances are defined here, along with how + to locate them and where their service files live. + + + Login session message bus + + Each time a user logs in, a login session message + bus may be started. All applications in the user's login + session may interact with one another using this message bus. + + + The address of the login session message bus is given + in the DBUS_SESSION_BUS_ADDRESS environment + variable. If that variable is not set, applications may + also try to read the address from the X Window System root + window property _DBUS_SESSION_BUS_ADDRESS. + The root window property must have type STRING. + The environment variable should have precedence over the + root window property. + + + [FIXME specify location of .service files, probably using + DESKTOP_DIRS etc. from basedir specification, though login session + bus is not really desktop-specific] + + + + System message bus + + A computer may have a system message bus, + accessible to all applications on the system. This message bus may be + used to broadcast system events, such as adding new hardware devices, + changes in the printer queue, and so forth. + + + The address of the system message bus is given + in the DBUS_SYSTEM_BUS_ADDRESS environment + variable. If that variable is not set, applications should try + to connect to the well-known address + unix:path=/var/run/dbus/system_bus_socket. + + + The D-Bus reference implementation actually honors the + $(localstatedir) configure option + for this address, on both client and server side. + + + + + [FIXME specify location of system bus .service files] + + + + + + Message Bus Messages + + The special message bus name org.freedesktop.DBus + responds to a number of additional messages. + + + + <literal>org.freedesktop.DBus.Hello</literal> + + As a method: + + STRING Hello () + + Reply arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Unique name assigned to the connection + + + + + + + Before an application is able to send messages to other applications + it must send the org.freedesktop.DBus.Hello message + to the message bus to obtain a unique name. If an application without + a unique name tries to send a message to another application, or a + message to the message bus itself that isn't the + org.freedesktop.DBus.Hello message, it will be + disconnected from the bus. + + + There is no corresponding "disconnect" request; if a client wishes to + disconnect from the bus, it simply closes the socket (or other + communication channel). + + + + <literal>org.freedesktop.DBus.ListNames</literal> + + As a method: + + ARRAY of STRING ListNames () + + Reply arguments: + + + + + Argument + Type + Description + + + + + 0 + ARRAY of STRING + Array of strings where each string is a bus name + + + + + + + Returns a list of all currently-owned names on the bus. + + + + <literal>org.freedesktop.DBus.ListActivatableNames</literal> + + As a method: + + ARRAY of STRING ListActivatableNames () + + Reply arguments: + + + + + Argument + Type + Description + + + + + 0 + ARRAY of STRING + Array of strings where each string is a bus name + + + + + + + Returns a list of all names that can be activated on the bus. + + + + <literal>org.freedesktop.DBus.NameHasOwner</literal> + + As a method: + + BOOLEAN NameHasOwner (in STRING name) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Name to check + + + + + Reply arguments: + + + + + Argument + Type + Description + + + + + 0 + BOOLEAN + Return value, true if the name exists + + + + + + + Checks if the specified name exists (currently has an owner). + + + + + <literal>org.freedesktop.DBus.NameOwnerChanged</literal> + + This is a signal: + + NameOwnerChanged (STRING name, STRING old_owner, STRING new_owner) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Name with a new owner + + + 1 + STRING + Old owner or empty string if none + + + 2 + STRING + New owner or empty string if none + + + + + + + This signal indicates that the owner of a name has changed. + It's also the signal to use to detect the appearance of + new names on the bus. + + + + <literal>org.freedesktop.DBus.NameLost</literal> + + This is a signal: + + NameLost (STRING name) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Name which was lost + + + + + + + This signal is sent to a specific application when it loses + ownership of a name. + + + + + <literal>org.freedesktop.DBus.NameAcquired</literal> + + This is a signal: + + NameAcquired (STRING name) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Name which was acquired + + + + + + + This signal is sent to a specific application when it gains + ownership of a name. + + + + + <literal>org.freedesktop.DBus.StartServiceByName</literal> + + As a method: + + UINT32 StartServiceByName (in STRING name, in UINT32 flags) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Name of the service to start + + + 1 + UINT32 + Flags (currently not used) + + + + + Reply arguments: + + + + + Argument + Type + Description + + + + + 0 + UINT32 + Return value + + + + + Tries to launch the executable associated with a name. For more information, see . + + + + The return value can be one of the following values: + + + + + Identifier + Value + Description + + + + + DBUS_START_REPLY_SUCCESS + 1 + The service was successfully started. + + + DBUS_START_REPLY_ALREADY_RUNNING + 2 + A connection already owns the given name. + + + + + + + + + + <literal>org.freedesktop.DBus.UpdateActivationEnvironment</literal> + + As a method: + + UpdateActivationEnvironment (in ARRAY of DICT<STRING,STRING> environment) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + ARRAY of DICT<STRING,STRING> + Environment to add or update + + + + + Normally, session bus activated services inherit the environment of the bus daemon. This method adds to or modifies that environment when activating services. + + + Some bus instances, such as the standard system bus, may disable access to this method for some or all callers. + + + + + + <literal>org.freedesktop.DBus.GetNameOwner</literal> + + As a method: + + STRING GetNameOwner (in STRING name) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Name to get the owner of + + + + + Reply arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Return value, a unique connection name + + + + + Returns the unique connection name of the primary owner of the name + given. If the requested name doesn't have an owner, returns a + org.freedesktop.DBus.Error.NameHasNoOwner error. + + + + + <literal>org.freedesktop.DBus.GetConnectionUnixUser</literal> + + As a method: + + UINT32 GetConnectionUnixUser (in STRING connection_name) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Name of the connection to query + + + + + Reply arguments: + + + + + Argument + Type + Description + + + + + 0 + UINT32 + unix user id + + + + + Returns the unix uid of the process connected to the server. If unable to + determine it, a org.freedesktop.DBus.Error.Failed + error is returned. + + + + + <literal>org.freedesktop.DBus.AddMatch</literal> + + As a method: + + AddMatch (in STRING rule) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Match rule to add to the connection + + + + + Adds a match rule to match messages going through the message bus (see ). + If the bus does not have enough resources the org.freedesktop.DBus.Error.OOM + error is returned. + + + + <literal>org.freedesktop.DBus.RemoveMatch</literal> + + As a method: + + RemoveMatch (in STRING rule) + + Message arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Match rule to remove from the connection + + + + + Removes the first rule that matches (see ). + If the rule is not found the org.freedesktop.DBus.Error.MatchRuleNotFound + error is returned. + + + + + <literal>org.freedesktop.DBus.GetId</literal> + + As a method: + + GetId (out STRING id) + + Reply arguments: + + + + + Argument + Type + Description + + + + + 0 + STRING + Unique ID identifying the bus daemon + + + + + Gets the unique ID of the bus. The unique ID here is shared among all addresses the + bus daemon is listening on (TCP, UNIX domain socket, etc.) and its format is described in + . Each address the bus is listening on also has its own unique + ID, as described in . The per-bus and per-address IDs are not related. + There is also a per-machine ID, described in and returned + by org.freedesktop.DBus.Peer.GetMachineId(). + For a desktop session bus, the bus ID can be used as a way to uniquely identify a user's session. + + + + + +
+ + + Glossary + + This glossary defines some of the terms used in this specification. + + + Bus Name + + + The message bus maintains an association between names and + connections. (Normally, there's one connection per application.) A + bus name is simply an identifier used to locate connections. For + example, the hypothetical com.yoyodyne.Screensaver + name might be used to send a message to a screensaver from Yoyodyne + Corporation. An application is said to own a + name if the message bus has associated the application's connection + with the name. Names may also have queued + owners (see ). + The bus assigns a unique name to each connection, + see . Other names + can be thought of as "well-known names" and are + used to find applications that offer specific functionality. + + + + + Message + + + A message is the atomic unit of communication via the D-Bus + protocol. It consists of a header and a + body; the body is made up of + arguments. + + + + + Message Bus + + + The message bus is a special application that forwards + or routes messages between a group of applications + connected to the message bus. It also manages + names used for routing + messages. + + + + + Name + + + See . "Name" may + also be used to refer to some of the other names + in D-Bus, such as interface names. + + + + + Namespace + + + Used to prevent collisions when defining new interfaces or bus + names. The convention used is the same one Java uses for defining + classes: a reversed domain name. + + + + + Object + + + Each application contains objects, which have + interfaces and + methods. Objects are referred to by a name, + called a path. + + + + + One-to-One + + + An application talking directly to another application, without going + through a message bus. One-to-one connections may be "peer to peer" or + "client to server." The D-Bus protocol has no concept of client + vs. server after a connection has authenticated; the flow of messages + is symmetrical (full duplex). + + + + + Path + + + Object references (object names) in D-Bus are organized into a + filesystem-style hierarchy, so each object is named by a path. As in + LDAP, there's no difference between "files" and "directories"; a path + can refer to an object, while still having child objects below it. + + + + + Queued Name Owner + + + Each bus name has a primary owner; messages sent to the name go to the + primary owner. However, certain names also maintain a queue of + secondary owners "waiting in the wings." If the primary owner releases + the name, then the first secondary owner in the queue automatically + becomes the new owner of the name. + + + + + Service + + + A service is an executable that can be launched by the bus daemon. + Services normally guarantee some particular features, for example they + may guarantee that they will request a specific name such as + "org.freedesktop.Screensaver", have a singleton object + "/org/freedesktop/Application", and that object will implement the + interface "org.freedesktop.ScreensaverControl". + + + + + Service Description Files + + + ".service files" tell the bus about service applications that can be + launched (see ). Most importantly they + provide a mapping from bus names to services that will request those + names when they start up. + + + + + Unique Connection Name + + + The special name automatically assigned to each connection by the + message bus. This name will never change owner, and will be unique + (never reused during the lifetime of the message bus). + It will begin with a ':' character. + + + + + +
+ diff --git a/doc/dbus-test-plan.html b/doc/dbus-test-plan.html new file mode 100644 index 00000000..e9e70a11 --- /dev/null +++ b/doc/dbus-test-plan.html @@ -0,0 +1,141 @@ +D-Bus Test Plan

D-Bus Test Plan

Anders Carlsson

CodeFactory AB

Introduction

+ This document tries to explain the details of the test plan for D-Bus +

The importance of testing

+ As with any big library or program, testing is important. It + can help find bugs and regressions and make the code better + overall. +

+ D-Bus is a large and complex piece of software (about 25,000 + lines of code for the client library, and 2,500 lines of code + for the bus daemon) and it's therefore important to try to make sure + that all parts of the software is functioning correctly. +

+ D-Bus can be built with support for testing by passing + --enable-tests. to the configure script. It + is recommended that production systems build without testing + since that reduces the D-Bus client library size. +

Testing the D-Bus client library

+ The tests for the client library consist of the dbus-test + program which is a unit test for all aspects of the client + library. Whenever a bug in the client library is found and + fixed, a test is added to make sure that the bug won't occur again. +

Data Structures

+ The D-Bus client library consists of some data structures that + are used internally; a linked list class, a hashtable class and + a string class. All aspects of those are tested by dbus-test. +

Message loader

+ The message loader is the part of D-Bus that takes messages in + raw character form and parses them, turning them into DBusMessages. +

+ This is one of the parts of D-Bus that + must be absolutely bug-free and + robust. The message loader should be able to handle invalid + and incomplete messages without crashing. Not doing so is a + serious issue and can easily result in D-Bus being exploitable + to DoS attacks. +

+ To solve these problems, there is a testing feature called the + Message Builder. The message builder can take a serialized + message in string-form and convert it into a raw character + string which can then be loaded by the message loader. +

Figure 1. Example of a message in string form

+          # Standard org.freedesktop.DBus.Hello message
+
+          VALID_HEADER
+          FIELD_NAME name
+          TYPE STRING
+          STRING 'org.freedesktop.DBus.Hello'
+          FIELD_NAME srvc
+          TYPE STRING
+          STRING 'org.freedesktop.DBus'
+          ALIGN 8
+          END_LENGTH Header
+          START_LENGTH Body
+          END_LENGTH Body
+        

+ The file format of messages in string form is documented in + the D-Bus Reference Manual. +

+ The message test part of dbus-test is using the message + builder to build different kinds of messages, both valid, + invalid, and invalid ones, to make sure that the loader won't + crash or leak memory of any of those, and that the loader + knows if a message is valid or not. +

+ There is also a test program called + break-loader that loads a message in + string-form into raw character form using the message + builder. It then randomly changes the message, it can for + example replace single bytes of data or modify the length of + the message. This is to simulate network errors. The + break-loader program saves all the messages leading to errors + so it can easily be run for a long period of time. +

Authentication

+ For testing authentication, there is a testing feature that + can read authentication sequences from a file and play them + back to a dummy server and client to make sure that + authentication is working according to the specification. +

Figure 2. Example of an authentication script

+          ## this tests a successful auth of type EXTERNAL
+          
+          SERVER
+          SEND 'AUTH EXTERNAL USERNAME_HEX'
+          EXPECT_COMMAND OK
+          EXPECT_STATE WAITING_FOR_INPUT
+          SEND 'BEGIN'
+          EXPECT_STATE AUTHENTICATED
+        

Testing the D-Bus bus daemon

+ Since the D-Bus bus daemon is using the D-Bus client library it + will benefit from all tests done on the client library, but + there is still the issue of testing client-server communication. + This is more complicated since it it may require another process + running. +

The debug transport

+ In D-Bus, a transport is a class that + handles sending and receiving raw data over a certain + medium. The transport that is used most in D-Bus is the UNIX + transport with sends and recevies data over a UNIX socket. A + transport that tunnels data through X11 client messages is + also under development. +

+ The D-Bus debug transport is a specialized transport that + works in-process. This means that a client and server that + exists in the same process can talk to eachother without using + a socket. +

The bus-test program

+ The bus-test program is a program that is used to test various + parts of the D-Bus bus daemon; robustness and that it conforms + to the specifications. +

+ The test program has the necessary code from the bus daemon + linked in, and it uses the debug transport for + communication. This means that the bus daemon code can be + tested without the real bus actually running, which makes + testing easier. +

+ The bus-test program should test all major features of the + bus, such as service registration, notification when things + occurs and message matching. +

Other tests

Out-Of-Memory robustness

+ Since D-Bus should be able to be used in embedded devices, and + also as a system service, it should be able to cope with + low-memory situations without exiting or crashing. +

+ In practice, this means that both the client and server code + must be able to handle dbus_malloc returning NULL. +

+ To test this, two environment variables + exist. DBUS_MALLOC_FAIL_NTH will make every + nth call to dbus_malloc return NULL, and + DBUS_MALLOC_FAIL_GREATER_THAN will make any + dbus_malloc call with a request for more than the specified + number of bytes fail. +

Memory leaks and code robustness

+ Naturally there are some things that tests can't be written + for, for example things like memory leaks and out-of-bounds + memory reading or writing. +

+ Luckily there exists good tools for catching such errors. One + free good tool is Valgrind, which runs the program in a + virtual CPU which makes catching errors easy. All test programs can be run under Valgrind, +

diff --git a/doc/dbus-test-plan.xml b/doc/dbus-test-plan.xml new file mode 100644 index 00000000..e6aafb9a --- /dev/null +++ b/doc/dbus-test-plan.xml @@ -0,0 +1,232 @@ + + + +
+ + D-Bus Test Plan + 14 February 2003 + + + Anders + Carlsson + + CodeFactory AB +
andersca@codefactory.se
+
+
+
+
+ + Introduction + + This document tries to explain the details of the test plan for D-Bus + + + The importance of testing + + As with any big library or program, testing is important. It + can help find bugs and regressions and make the code better + overall. + + + D-Bus is a large and complex piece of software (about 25,000 + lines of code for the client library, and 2,500 lines of code + for the bus daemon) and it's therefore important to try to make sure + that all parts of the software is functioning correctly. + + + D-Bus can be built with support for testing by passing + --enable-tests. to the configure script. It + is recommended that production systems build without testing + since that reduces the D-Bus client library size. + + + + + Testing the D-Bus client library + + The tests for the client library consist of the dbus-test + program which is a unit test for all aspects of the client + library. Whenever a bug in the client library is found and + fixed, a test is added to make sure that the bug won't occur again. + + + Data Structures + + The D-Bus client library consists of some data structures that + are used internally; a linked list class, a hashtable class and + a string class. All aspects of those are tested by dbus-test. + + + + Message loader + + The message loader is the part of D-Bus that takes messages in + raw character form and parses them, turning them into DBusMessages. + + + This is one of the parts of D-Bus that + must be absolutely bug-free and + robust. The message loader should be able to handle invalid + and incomplete messages without crashing. Not doing so is a + serious issue and can easily result in D-Bus being exploitable + to DoS attacks. + + + To solve these problems, there is a testing feature called the + Message Builder. The message builder can take a serialized + message in string-form and convert it into a raw character + string which can then be loaded by the message loader. + +
+ Example of a message in string form + + # Standard org.freedesktop.DBus.Hello message + + VALID_HEADER + FIELD_NAME name + TYPE STRING + STRING 'org.freedesktop.DBus.Hello' + FIELD_NAME srvc + TYPE STRING + STRING 'org.freedesktop.DBus' + ALIGN 8 + END_LENGTH Header + START_LENGTH Body + END_LENGTH Body + +
+ + The file format of messages in string form is documented in + the D-Bus Reference Manual. + + + The message test part of dbus-test is using the message + builder to build different kinds of messages, both valid, + invalid, and invalid ones, to make sure that the loader won't + crash or leak memory of any of those, and that the loader + knows if a message is valid or not. + + + There is also a test program called + break-loader that loads a message in + string-form into raw character form using the message + builder. It then randomly changes the message, it can for + example replace single bytes of data or modify the length of + the message. This is to simulate network errors. The + break-loader program saves all the messages leading to errors + so it can easily be run for a long period of time. + +
+ + Authentication + + For testing authentication, there is a testing feature that + can read authentication sequences from a file and play them + back to a dummy server and client to make sure that + authentication is working according to the specification. + +
+ Example of an authentication script + + ## this tests a successful auth of type EXTERNAL + + SERVER + SEND 'AUTH EXTERNAL USERNAME_HEX' + EXPECT_COMMAND OK + EXPECT_STATE WAITING_FOR_INPUT + SEND 'BEGIN' + EXPECT_STATE AUTHENTICATED + +
+
+
+ + Testing the D-Bus bus daemon + + Since the D-Bus bus daemon is using the D-Bus client library it + will benefit from all tests done on the client library, but + there is still the issue of testing client-server communication. + This is more complicated since it it may require another process + running. + + + The debug transport + + In D-Bus, a transport is a class that + handles sending and receiving raw data over a certain + medium. The transport that is used most in D-Bus is the UNIX + transport with sends and recevies data over a UNIX socket. A + transport that tunnels data through X11 client messages is + also under development. + + + The D-Bus debug transport is a specialized transport that + works in-process. This means that a client and server that + exists in the same process can talk to eachother without using + a socket. + + + + The bus-test program + + The bus-test program is a program that is used to test various + parts of the D-Bus bus daemon; robustness and that it conforms + to the specifications. + + + The test program has the necessary code from the bus daemon + linked in, and it uses the debug transport for + communication. This means that the bus daemon code can be + tested without the real bus actually running, which makes + testing easier. + + + The bus-test program should test all major features of the + bus, such as service registration, notification when things + occurs and message matching. + + + + + Other tests + + + Out-Of-Memory robustness + + Since D-Bus should be able to be used in embedded devices, and + also as a system service, it should be able to cope with + low-memory situations without exiting or crashing. + + + In practice, this means that both the client and server code + must be able to handle dbus_malloc returning NULL. + + + To test this, two environment variables + exist. DBUS_MALLOC_FAIL_NTH will make every + nth call to dbus_malloc return NULL, and + DBUS_MALLOC_FAIL_GREATER_THAN will make any + dbus_malloc call with a request for more than the specified + number of bytes fail. + + + + + Memory leaks and code robustness + + Naturally there are some things that tests can't be written + for, for example things like memory leaks and out-of-bounds + memory reading or writing. + + + Luckily there exists good tools for catching such errors. One + free good tool is Valgrind, which runs the program in a + virtual CPU which makes catching errors easy. All test programs can be run under Valgrind, + + + +
diff --git a/doc/dbus-tutorial.html b/doc/dbus-tutorial.html new file mode 100644 index 00000000..957afaf1 --- /dev/null +++ b/doc/dbus-tutorial.html @@ -0,0 +1,991 @@ +D-Bus Tutorial

D-Bus Tutorial

Havoc Pennington

Red Hat, Inc.

David Wheeler

John Palmieri

Red Hat, Inc.

Colin Walters

Red Hat, Inc.

Version 0.5.0


Tutorial Work In Progress

+ This tutorial is not complete; it probably contains some useful information, but + also has plenty of gaps. Right now, you'll also need to refer to the D-Bus specification, + Doxygen reference documentation, and look at some examples of how other apps use D-Bus. +

+ Enhancing the tutorial is definitely encouraged - send your patches or suggestions to the + mailing list. If you create a D-Bus binding, please add a section to the tutorial for your + binding, if only a short section with a couple of examples. +

What is D-Bus?

+ D-Bus is a system for interprocess communication + (IPC). Architecturally, it has several layers: + +

  • + A library, libdbus, that allows two + applications to connect to each other and exchange messages. +

  • + A message bus daemon executable, built on + libdbus, that multiple applications can connect to. The daemon can + route messages from one application to zero or more other + applications. +

  • + Wrapper libraries or bindings + based on particular application frameworks. For example, libdbus-glib and + libdbus-qt. There are also bindings to languages such as + Python. These wrapper libraries are the API most people should use, + as they simplify the details of D-Bus programming. libdbus is + intended to be a low-level backend for the higher level bindings. + Much of the libdbus API is only useful for binding implementation. +

+

+ libdbus only supports one-to-one connections, just like a raw network + socket. However, rather than sending byte streams over the connection, you + send messages. Messages have a header identifying + the kind of message, and a body containing a data payload. libdbus also + abstracts the exact transport used (sockets vs. whatever else), and + handles details such as authentication. +

+ The message bus daemon forms the hub of a wheel. Each spoke of the wheel + is a one-to-one connection to an application using libdbus. An + application sends a message to the bus daemon over its spoke, and the bus + daemon forwards the message to other connected applications as + appropriate. Think of the daemon as a router. +

+ The bus daemon has multiple instances on a typical computer. The + first instance is a machine-global singleton, that is, a system daemon + similar to sendmail or Apache. This instance has heavy security + restrictions on what messages it will accept, and is used for systemwide + communication. The other instances are created one per user login session. + These instances allow applications in the user's session to communicate + with one another. +

+ The systemwide and per-user daemons are separate. Normal within-session + IPC does not involve the systemwide message bus process and vice versa. +

D-Bus applications

+ There are many, many technologies in the world that have "Inter-process + communication" or "networking" in their stated purpose: CORBA, DCE, DCOM, DCOP, XML-RPC, SOAP, MBUS, Internet Communications Engine (ICE), + and probably hundreds more. + Each of these is tailored for particular kinds of application. + D-Bus is designed for two specific cases: +

  • + Communication between desktop applications in the same desktop + session; to allow integration of the desktop session as a whole, + and address issues of process lifecycle (when do desktop components + start and stop running). +

  • + Communication between the desktop session and the operating system, + where the operating system would typically include the kernel + and any system daemons or processes. +

+

+ For the within-desktop-session use case, the GNOME and KDE desktops + have significant previous experience with different IPC solutions + such as CORBA and DCOP. D-Bus is built on that experience and + carefully tailored to meet the needs of these desktop projects + in particular. D-Bus may or may not be appropriate for other + applications; the FAQ has some comparisons to other IPC systems. +

+ The problem solved by the systemwide or communication-with-the-OS case + is explained well by the following text from the Linux Hotplug project: +

+ A gap in current Linux support is that policies with any sort of + dynamic "interact with user" component aren't currently + supported. For example, that's often needed the first time a network + adapter or printer is connected, and to determine appropriate places + to mount disk drives. It would seem that such actions could be + supported for any case where a responsible human can be identified: + single user workstations, or any system which is remotely + administered. +

+ This is a classic "remote sysadmin" problem, where in this case + hotplugging needs to deliver an event from one security domain + (operating system kernel, in this case) to another (desktop for + logged-in user, or remote sysadmin). Any effective response must go + the other way: the remote domain taking some action that lets the + kernel expose the desired device capabilities. (The action can often + be taken asynchronously, for example letting new hardware be idle + until a meeting finishes.) At this writing, Linux doesn't have + widely adopted solutions to such problems. However, the new D-Bus + work may begin to solve that problem. +

+

+ D-Bus may happen to be useful for purposes other than the one it was + designed for. Its general properties that distinguish it from + other forms of IPC are: +

  • + Binary protocol designed to be used asynchronously + (similar in spirit to the X Window System protocol). +

  • + Stateful, reliable connections held open over time. +

  • + The message bus is a daemon, not a "swarm" or + distributed architecture. +

  • + Many implementation and deployment issues are specified rather + than left ambiguous/configurable/pluggable. +

  • + Semantics are similar to the existing DCOP system, allowing + KDE to adopt it more easily. +

  • + Security features to support the systemwide mode of the + message bus. +

+

Concepts

+ Some basic concepts apply no matter what application framework you're + using to write a D-Bus application. The exact code you write will be + different for GLib vs. Qt vs. Python applications, however. +

+ Here is a diagram (png svg) that may help you visualize the concepts + that follow. +

Native Objects and Object Paths

+ Your programming framework probably defines what an "object" is like; + usually with a base class. For example: java.lang.Object, GObject, QObject, + python's base Object, or whatever. Let's call this a native object. +

+ The low-level D-Bus protocol, and corresponding libdbus API, does not care about native objects. + However, it provides a concept called an + object path. The idea of an object path is that + higher-level bindings can name native object instances, and allow remote applications + to refer to them. +

+ The object path + looks like a filesystem path, for example an object could be + named /org/kde/kspread/sheets/3/cells/4/5. + Human-readable paths are nice, but you are free to create an + object named /com/mycompany/c5yo817y0c1y1c5b + if it makes sense for your application. +

+ Namespacing object paths is smart, by starting them with the components + of a domain name you own (e.g. /org/kde). This + keeps different code modules in the same process from stepping + on one another's toes. +

Methods and Signals

+ Each object has members; the two kinds of member + are methods and + signals. Methods are operations that can be + invoked on an object, with optional input (aka arguments or "in + parameters") and output (aka return values or "out parameters"). + Signals are broadcasts from the object to any interested observers + of the object; signals may contain a data payload. +

+ Both methods and signals are referred to by name, such as + "Frobate" or "OnClicked". +

Interfaces

+ Each object supports one or more interfaces. + Think of an interface as a named group of methods and signals, + just as it is in GLib or Qt or Java. Interfaces define the + type of an object instance. +

+ DBus identifies interfaces with a simple namespaced string, + something like org.freedesktop.Introspectable. + Most bindings will map these interface names directly to + the appropriate programming language construct, for example + to Java interfaces or C++ pure virtual classes. +

Proxies

+ A proxy object is a convenient native object created to + represent a remote object in another process. The low-level DBus API involves manually creating + a method call message, sending it, then manually receiving and processing + the method reply message. Higher-level bindings provide proxies as an alternative. + Proxies look like a normal native object; but when you invoke a method on the proxy + object, the binding converts it into a DBus method call message, waits for the reply + message, unpacks the return value, and returns it from the native method.. +

+ In pseudocode, programming without proxies might look like this: +

+          Message message = new Message("/remote/object/path", "MethodName", arg1, arg2);
+          Connection connection = getBusConnection();
+          connection.send(message);
+          Message reply = connection.waitForReply(message);
+          if (reply.isError()) {
+             
+          } else {
+             Object returnValue = reply.getReturnValue();
+          }
+        

+

+ Programming with proxies might look like this: +

+          Proxy proxy = new Proxy(getBusConnection(), "/remote/object/path");
+          Object returnValue = proxy.MethodName(arg1, arg2);
+        

+

Bus Names

+ When each application connects to the bus daemon, the daemon immediately + assigns it a name, called the unique connection name. + A unique name begins with a ':' (colon) character. These names are never + reused during the lifetime of the bus daemon - that is, you know + a given name will always refer to the same application. + An example of a unique name might be + :34-907. The numbers after the colon have + no meaning other than their uniqueness. +

+ When a name is mapped + to a particular application's connection, that application is said to + own that name. +

+ Applications may ask to own additional well-known + names. For example, you could write a specification to + define a name called com.mycompany.TextEditor. + Your definition could specify that to own this name, an application + should have an object at the path + /com/mycompany/TextFileManager supporting the + interface org.freedesktop.FileHandler. +

+ Applications could then send messages to this bus name, + object, and interface to execute method calls. +

+ You could think of the unique names as IP addresses, and the + well-known names as domain names. So + com.mycompany.TextEditor might map to something like + :34-907 just as mycompany.com maps + to something like 192.168.0.5. +

+ Names have a second important use, other than routing messages. They + are used to track lifecycle. When an application exits (or crashes), its + connection to the message bus will be closed by the operating system + kernel. The message bus then sends out notification messages telling + remaining applications that the application's names have lost their + owner. By tracking these notifications, your application can reliably + monitor the lifetime of other applications. +

+ Bus names can also be used to coordinate single-instance applications. + If you want to be sure only one + com.mycompany.TextEditor application is running for + example, have the text editor application exit if the bus name already + has an owner. +

Addresses

+ Applications using D-Bus are either servers or clients. A server + listens for incoming connections; a client connects to a server. Once + the connection is established, it is a symmetric flow of messages; the + client-server distinction only matters when setting up the + connection. +

+ If you're using the bus daemon, as you probably are, your application + will be a client of the bus daemon. That is, the bus daemon listens + for connections and your application initiates a connection to the bus + daemon. +

+ A D-Bus address specifies where a server will + listen, and where a client will connect. For example, the address + unix:path=/tmp/abcdef specifies that the server will + listen on a UNIX domain socket at the path + /tmp/abcdef and the client will connect to that + socket. An address can also specify TCP/IP sockets, or any other + transport defined in future iterations of the D-Bus specification. +

+ When using D-Bus with a message bus daemon, + libdbus automatically discovers the address of the per-session bus + daemon by reading an environment variable. It discovers the + systemwide bus daemon by checking a well-known UNIX domain socket path + (though you can override this address with an environment variable). +

+ If you're using D-Bus without a bus daemon, it's up to you to + define which application will be the server and which will be + the client, and specify a mechanism for them to agree on + the server's address. This is an unusual case. +

Big Conceptual Picture

+ Pulling all these concepts together, to specify a particular + method call on a particular object instance, a number of + nested components have to be named: +

+          Address -> [Bus Name] -> Path -> Interface -> Method
+        

+ The bus name is in brackets to indicate that it's optional -- you only + provide a name to route the method call to the right application + when using the bus daemon. If you have a direct connection to another + application, bus names aren't used; there's no bus daemon. +

+ The interface is also optional, primarily for historical + reasons; DCOP does not require specifying the interface, + instead simply forbidding duplicate method names + on the same object instance. D-Bus will thus let you + omit the interface, but if your method name is ambiguous + it is undefined which method will be invoked. +

Messages - Behind the Scenes

+ D-Bus works by sending messages between processes. If you're using + a sufficiently high-level binding, you may never work with messages directly. +

+ There are 4 message types: +

  • + Method call messages ask to invoke a method + on an object. +

  • + Method return messages return the results + of invoking a method. +

  • + Error messages return an exception caused by + invoking a method. +

  • + Signal messages are notifications that a given signal + has been emitted (that an event has occurred). + You could also think of these as "event" messages. +

+

+ A method call maps very simply to messages: you send a method call + message, and receive either a method return message or an error message + in reply. +

+ Each message has a header, including fields, + and a body, including arguments. You can think + of the header as the routing information for the message, and the body as the payload. + Header fields might include the sender bus name, destination bus name, method or signal name, + and so forth. One of the header fields is a type signature describing the + values found in the body. For example, the letter "i" means "32-bit integer" so the signature + "ii" means the payload has two 32-bit integers. +

Calling a Method - Behind the Scenes

+ A method call in DBus consists of two messages; a method call message sent from process A to process B, + and a matching method reply message sent from process B to process A. Both the call and the reply messages + are routed through the bus daemon. The caller includes a different serial number in each call message, and the + reply message includes this number to allow the caller to match replies to calls. +

+ The call message will contain any arguments to the method. + The reply message may indicate an error, or may contain data returned by the method. +

+ A method invocation in DBus happens as follows: +

  • + The language binding may provide a proxy, such that invoking a method on + an in-process object invokes a method on a remote object in another process. If so, the + application calls a method on the proxy, and the proxy + constructs a method call message to send to the remote process. +

  • + For more low-level APIs, the application may construct a method call message itself, without + using a proxy. +

  • + In either case, the method call message contains: a bus name belonging to the remote process; the name of the method; + the arguments to the method; an object path inside the remote process; and optionally the name of the + interface that specifies the method. +

  • + The method call message is sent to the bus daemon. +

  • + The bus daemon looks at the destination bus name. If a process owns that name, + the bus daemon forwards the method call to that process. Otherwise, the bus daemon + creates an error message and sends it back as the reply to the method call message. +

  • + The receiving process unpacks the method call message. In a simple low-level API situation, it + may immediately run the method and send a method reply message to the bus daemon. + When using a high-level binding API, the binding might examine the object path, interface, + and method name, and convert the method call message into an invocation of a method on + a native object (GObject, java.lang.Object, QObject, etc.), then convert the return + value from the native method into a method reply message. +

  • + The bus daemon receives the method reply message and sends it to the process that + made the method call. +

  • + The process that made the method call looks at the method reply and makes use of any + return values included in the reply. The reply may also indicate that an error occurred. + When using a binding, the method reply message may be converted into the return value of + of a proxy method, or into an exception. +

+

+ The bus daemon never reorders messages. That is, if you send two method call messages to the same recipient, + they will be received in the order they were sent. The recipient is not required to reply to the calls + in order, however; for example, it may process each method call in a separate thread, and return reply messages + in an undefined order depending on when the threads complete. Method calls have a unique serial + number used by the method caller to match reply messages to call messages. +

Emitting a Signal - Behind the Scenes

+ A signal in DBus consists of a single message, sent by one process to any number of other processes. + That is, a signal is a unidirectional broadcast. The signal may contain arguments (a data payload), but + because it is a broadcast, it never has a "return value." Contrast this with a method call + (see the section called “Calling a Method - Behind the Scenes”) where the method call message has a matching method reply message. +

+ The emitter (aka sender) of a signal has no knowledge of the signal recipients. Recipients register + with the bus daemon to receive signals based on "match rules" - these rules would typically include the sender and + the signal name. The bus daemon sends each signal only to recipients who have expressed interest in that + signal. +

+ A signal in DBus happens as follows: +

  • + A signal message is created and sent to the bus daemon. When using the low-level API this may be + done manually, with certain bindings it may be done for you by the binding when a native object + emits a native signal or event. +

  • + The signal message contains the name of the interface that specifies the signal; + the name of the signal; the bus name of the process sending the signal; and + any arguments +

  • + Any process on the message bus can register "match rules" indicating which signals it + is interested in. The bus has a list of registered match rules. +

  • + The bus daemon examines the signal and determines which processes are interested in it. + It sends the signal message to these processes. +

  • + Each process receiving the signal decides what to do with it; if using a binding, + the binding may choose to emit a native signal on a proxy object. If using the + low-level API, the process may just look at the signal sender and name and decide + what to do based on that. +

+

Introspection

+ D-Bus objects may support the interface org.freedesktop.DBus.Introspectable. + This interface has one method Introspect which takes no arguments and returns + an XML string. The XML string describes the interfaces, methods, and signals of the object. + See the D-Bus specification for more details on this introspection format. +

GLib API: Using Remote Objects

+ The GLib binding is defined in the header file + <dbus/dbus-glib.h>. +

D-Bus - GLib type mappings

+ The heart of the GLib bindings for D-Bus is the mapping it + provides between D-Bus "type signatures" and GLib types + (GType). The D-Bus type system is composed of + a number of "basic" types, along with several "container" types. +

Basic type mappings

+ Below is a list of the basic types, along with their associated + mapping to a GType. +

D-Bus basic typeGTypeFree functionNotes
BYTEG_TYPE_UCHAR  
BOOLEANG_TYPE_BOOLEAN  
INT16G_TYPE_INT Will be changed to a G_TYPE_INT16 once GLib has it
UINT16G_TYPE_UINT Will be changed to a G_TYPE_UINT16 once GLib has it
INT32G_TYPE_INT Will be changed to a G_TYPE_INT32 once GLib has it
UINT32G_TYPE_UINT Will be changed to a G_TYPE_UINT32 once GLib has it
INT64G_TYPE_GINT64  
UINT64G_TYPE_GUINT64  
DOUBLEG_TYPE_DOUBLE  
STRINGG_TYPE_STRINGg_free 
OBJECT_PATHDBUS_TYPE_G_PROXYg_object_unrefThe returned proxy does not have an interface set; use dbus_g_proxy_set_interface to invoke methods

+ As you can see, the basic mapping is fairly straightforward. +

Container type mappings

+ The D-Bus type system also has a number of "container" + types, such as DBUS_TYPE_ARRAY and + DBUS_TYPE_STRUCT. The D-Bus type system + is fully recursive, so one can for example have an array of + array of strings (i.e. type signature + aas). +

+ However, not all of these types are in common use; for + example, at the time of this writing the author knows of no + one using DBUS_TYPE_STRUCT, or a + DBUS_TYPE_ARRAY containing any non-basic + type. The approach the GLib bindings take is pragmatic; try + to map the most common types in the most obvious way, and + let using less common and more complex types be less + "natural". +

+ First, D-Bus type signatures which have an "obvious" + corresponding built-in GLib type are mapped using that type: +

D-Bus type signatureDescriptionGTypeC typedefFree functionNotes
asArray of stringsG_TYPE_STRVchar **g_strfreev 
vGeneric value containerG_TYPE_VALUEGValue *g_value_unsetThe calling conventions for values expect that method callers have allocated return values; see below.

+

+ The next most common recursive type signatures are arrays of + basic values. The most obvious mapping for arrays of basic + types is a GArray. Now, GLib does not + provide a builtin GType for + GArray. However, we actually need more than + that - we need a "parameterized" type which includes the + contained type. Why we need this we will see below. +

+ The approach taken is to create these types in the D-Bus GLib + bindings; however, there is nothing D-Bus specific about them. + In the future, we hope to include such "fundamental" types in GLib + itself. +

D-Bus type signatureDescriptionGTypeC typedefFree functionNotes
ayArray of bytesDBUS_TYPE_G_BYTE_ARRAYGArray *g_array_free 
auArray of uintDBUS_TYPE_G_UINT_ARRAYGArray *g_array_free 
aiArray of intDBUS_TYPE_G_INT_ARRAYGArray *g_array_free 
axArray of int64DBUS_TYPE_G_INT64_ARRAYGArray *g_array_free 
atArray of uint64DBUS_TYPE_G_UINT64_ARRAYGArray *g_array_free 
adArray of doubleDBUS_TYPE_G_DOUBLE_ARRAYGArray *g_array_free 
abArray of booleanDBUS_TYPE_G_BOOLEAN_ARRAYGArray *g_array_free 

+

+ D-Bus also includes a special type DBUS_TYPE_DICT_ENTRY which + is only valid in arrays. It's intended to be mapped to a "dictionary" + type by bindings. The obvious GLib mapping here is GHashTable. Again, + however, there is no builtin GType for a GHashTable. + Moreover, just like for arrays, we need a parameterized type so that + the bindings can communiate which types are contained in the hash table. +

+ At present, only strings are supported. Work is in progress to + include more types. +

D-Bus type signatureDescriptionGTypeC typedefFree functionNotes
a{ss}Dictionary mapping strings to stringsDBUS_TYPE_G_STRING_STRING_HASHTABLEGHashTable *g_hash_table_destroy 

+

Arbitrarily recursive type mappings

+ Finally, it is possible users will want to write or invoke D-Bus + methods which have arbitrarily complex type signatures not + directly supported by these bindings. For this case, we have a + DBusGValue which acts as a kind of special + variant value which may be iterated over manually. The + GType associated is + DBUS_TYPE_G_VALUE. +

+ TODO insert usage of DBUS_TYPE_G_VALUE here. +

A sample program

Here is a D-Bus program using the GLib bindings. +

      
+int
+main (int argc, char **argv)
+{
+  DBusGConnection *connection;
+  GError *error;
+  DBusGProxy *proxy;
+  char **name_list;
+  char **name_list_ptr;
+  
+  g_type_init ();
+
+  error = NULL;
+  connection = dbus_g_bus_get (DBUS_BUS_SESSION,
+                               &error);
+  if (connection == NULL)
+    {
+      g_printerr ("Failed to open connection to bus: %s\n",
+                  error->message);
+      g_error_free (error);
+      exit (1);
+    }
+
+  /* Create a proxy object for the "bus driver" (name "org.freedesktop.DBus") */
+  
+  proxy = dbus_g_proxy_new_for_name (connection,
+                                     DBUS_SERVICE_DBUS,
+                                     DBUS_PATH_DBUS,
+                                     DBUS_INTERFACE_DBUS);
+
+  /* Call ListNames method, wait for reply */
+  error = NULL;
+  if (!dbus_g_proxy_call (proxy, "ListNames", &error, G_TYPE_INVALID,
+                          G_TYPE_STRV, &name_list, G_TYPE_INVALID))
+    {
+      /* Just do demonstrate remote exceptions versus regular GError */
+      if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION)
+        g_printerr ("Caught remote method exception %s: %s",
+	            dbus_g_error_get_name (error),
+	            error->message);
+      else
+        g_printerr ("Error: %s\n", error->message);
+      g_error_free (error);
+      exit (1);
+    }
+
+  /* Print the results */
+ 
+  g_print ("Names on the message bus:\n");
+  
+  for (name_list_ptr = name_list; *name_list_ptr; name_list_ptr++)
+    {
+      g_print ("  %s\n", *name_list_ptr);
+    }
+  g_strfreev (name_list);
+
+  g_object_unref (proxy);
+
+  return 0;
+}
+

+

Program initalization

+ A connection to the bus is acquired using + dbus_g_bus_get. Next, a proxy + is created for the object "/org/freedesktop/DBus" with + interface org.freedesktop.DBus + on the service org.freedesktop.DBus. + This is a proxy for the message bus itself. +

Understanding method invocation

+ You have a number of choices for method invocation. First, as + used above, dbus_g_proxy_call sends a + method call to the remote object, and blocks until a reply is + recieved. The outgoing arguments are specified in the varargs + array, terminated with G_TYPE_INVALID. + Next, pointers to return values are specified, followed again + by G_TYPE_INVALID. +

+ To invoke a method asynchronously, use + dbus_g_proxy_begin_call. This returns a + DBusGPendingCall object; you may then set a + notification function using + dbus_g_pending_call_set_notify. +

Connecting to object signals

+ You may connect to signals using + dbus_g_proxy_add_signal and + dbus_g_proxy_connect_signal. You must + invoke dbus_g_proxy_add_signal to specify + the signature of your signal handlers; you may then invoke + dbus_g_proxy_connect_signal multiple times. +

+ Note that it will often be the case that there is no builtin + marshaller for the type signature of a remote signal. In that + case, you must generate a marshaller yourself by using + glib-genmarshal, and then register + it using dbus_g_object_register_marshaller. +

Error handling and remote exceptions

+ All of the GLib binding methods such as + dbus_g_proxy_end_call return a + GError. This GError can + represent two different things: +

  • + An internal D-Bus error, such as an out-of-memory + condition, an I/O error, or a network timeout. Errors + generated by the D-Bus library itself have the domain + DBUS_GERROR, and a corresponding code + such as DBUS_GERROR_NO_MEMORY. It will + not be typical for applications to handle these errors + specifically. +

  • + A remote D-Bus exception, thrown by the peer, bus, or + service. D-Bus remote exceptions have both a textual + "name" and a "message". The GLib bindings store this + information in the GError, but some + special rules apply. +

    + The set error will have the domain + DBUS_GERROR as above, and will also + have the code + DBUS_GERROR_REMOTE_EXCEPTION. In order + to access the remote exception name, you must use a + special accessor, such as + dbus_g_error_has_name or + dbus_g_error_get_name. The remote + exception detailed message is accessible via the regular + GError message member. +

+

More examples of method invocation

Sending an integer and string, receiving an array of bytes

+

+  GArray *arr;
+  
+  error = NULL;
+  if (!dbus_g_proxy_call (proxy, "Foobar", &error,
+                          G_TYPE_INT, 42, G_TYPE_STRING, "hello",
+			  G_TYPE_INVALID,
+			  DBUS_TYPE_G_UCHAR_ARRAY, &arr, G_TYPE_INVALID))
+    {
+      /* Handle error */
+    }
+   g_assert (arr != NULL);
+   printf ("got back %u values", arr->len);
+

+

Sending a GHashTable

+

+  GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
+  guint32 ret;
+  
+  g_hash_table_insert (hash, "foo", "bar");
+  g_hash_table_insert (hash, "baz", "whee");
+
+  error = NULL;
+  if (!dbus_g_proxy_call (proxy, "HashSize", &error,
+                          DBUS_TYPE_G_STRING_STRING_HASH, hash, G_TYPE_INVALID,
+			  G_TYPE_UINT, &ret, G_TYPE_INVALID))
+    {
+      /* Handle error */
+    }
+  g_assert (ret == 2);
+  g_hash_table_destroy (hash);
+

+

Receiving a boolean and a string

+

+  gboolean boolret;
+  char *strret;
+  
+  error = NULL;
+  if (!dbus_g_proxy_call (proxy, "GetStuff", &error,
+			  G_TYPE_INVALID,
+                          G_TYPE_BOOLEAN, &boolret,
+                          G_TYPE_STRING, &strret,
+			  G_TYPE_INVALID))
+    {
+      /* Handle error */
+    }
+  printf ("%s %s", boolret ? "TRUE" : "FALSE", strret);
+  g_free (strret);
+

+

Sending two arrays of strings

+

+  /* NULL terminate */
+  char *strs_static[] = {"foo", "bar", "baz", NULL};
+  /* Take pointer to array; cannot pass array directly */
+  char **strs_static_p = strs_static;
+  char **strs_dynamic;
+
+  strs_dynamic = g_new (char *, 4);
+  strs_dynamic[0] = g_strdup ("hello");
+  strs_dynamic[1] = g_strdup ("world");
+  strs_dynamic[2] = g_strdup ("!");
+  /* NULL terminate */
+  strs_dynamic[3] = NULL;
+  
+  error = NULL;
+  if (!dbus_g_proxy_call (proxy, "TwoStrArrays", &error,
+                          G_TYPE_STRV, strs_static_p,
+                          G_TYPE_STRV, strs_dynamic,
+			  G_TYPE_INVALID,
+			  G_TYPE_INVALID))
+    {
+      /* Handle error */
+    }
+   g_strfreev (strs_dynamic);
+

+

Sending a boolean, receiving an array of strings

+

+  char **strs;
+  char **strs_p;
+  gboolean blah;
+
+  error = NULL;
+  blah = TRUE;
+  if (!dbus_g_proxy_call (proxy, "GetStrs", &error,
+                          G_TYPE_BOOLEAN, blah,
+			  G_TYPE_INVALID,
+                          G_TYPE_STRV, &strs,
+			  G_TYPE_INVALID))
+    {
+      /* Handle error */
+    }
+   for (strs_p = strs; *strs_p; strs_p++)
+     printf ("got string: \"%s\"", *strs_p);
+   g_strfreev (strs);
+

+

Sending a variant

+

+  GValue val = {0, };
+
+  g_value_init (&val, G_TYPE_STRING);
+  g_value_set_string (&val, "hello world");
+  
+  error = NULL;
+  if (!dbus_g_proxy_call (proxy, "SendVariant", &error,
+                          G_TYPE_VALUE, &val, G_TYPE_INVALID,
+			  G_TYPE_INVALID))
+    {
+      /* Handle error */
+    }
+  g_assert (ret == 2);
+  g_value_unset (&val);
+

+

Receiving a variant

+

+  GValue val = {0, };
+
+  error = NULL;
+  if (!dbus_g_proxy_call (proxy, "GetVariant", &error, G_TYPE_INVALID,
+                          G_TYPE_VALUE, &val, G_TYPE_INVALID))
+    {
+      /* Handle error */
+    }
+  if (G_VALUE_TYPE (&val) == G_TYPE_STRING)
+    printf ("%s\n", g_value_get_string (&val));
+  else if (G_VALUE_TYPE (&val) == G_TYPE_INT)
+    printf ("%d\n", g_value_get_int (&val));
+  else
+    ...
+  g_value_unset (&val);
+

+

Generated Bindings

+ By using the Introspection XML files, convenient client-side bindings + can be automatically created to ease the use of a remote DBus object. +

+ Here is a sample XML file which describes an object that exposes + one method, named ManyArgs. +

+<?xml version="1.0" encoding="UTF-8" ?>
+<node name="/com/example/MyObject">
+  <interface name="com.example.MyObject">
+    <method name="ManyArgs">
+      <arg type="u" name="x" direction="in" />
+      <arg type="s" name="str" direction="in" />
+      <arg type="d" name="trouble" direction="in" />
+      <arg type="d" name="d_ret" direction="out" />
+      <arg type="s" name="str_ret" direction="out" />
+    </method>
+  </interface>
+</node>
+

+

+ Run dbus-binding-tool --mode=glib-client + FILENAME > + HEADER_NAME to generate the header + file. For example: dbus-binding-tool --mode=glib-client + my-object.xml > my-object-bindings.h. This will generate + inline functions with the following prototypes: +

+/* This is a blocking call */
+gboolean
+com_example_MyObject_many_args (DBusGProxy *proxy, const guint IN_x,
+                                const char * IN_str, const gdouble IN_trouble,
+                                gdouble* OUT_d_ret, char ** OUT_str_ret,
+                                GError **error);
+
+/* This is a non-blocking call */
+DBusGProxyCall*
+com_example_MyObject_many_args_async (DBusGProxy *proxy, const guint IN_x,
+                                      const char * IN_str, const gdouble IN_trouble,
+                                      com_example_MyObject_many_args_reply callback,
+                                      gpointer userdata);
+
+/* This is the typedef for the non-blocking callback */
+typedef void
+(*com_example_MyObject_many_args_reply)
+(DBusGProxy *proxy, gdouble OUT_d_ret, char * OUT_str_ret,
+ GError *error, gpointer userdata);
+

+ The first argument in all functions is a DBusGProxy + *, which you should create with the usual + dbus_g_proxy_new_* functions. Following that are the + "in" arguments, and then either the "out" arguments and a + GError * for the synchronous (blocking) function, or + callback and user data arguments for the asynchronous (non-blocking) + function. The callback in the asynchronous function passes the + DBusGProxy *, the returned "out" arguments, an + GError * which is set if there was an error otherwise + NULL, and the user data. +

+ As with the server-side bindings support (see the section called “GLib API: Implementing Objects”), the exact behaviour of the client-side + bindings can be manipulated using "annotations". Currently the only + annotation used by the client bindings is + org.freedesktop.DBus.GLib.NoReply, which sets the + flag indicating that the client isn't expecting a reply to the method + call, so a reply shouldn't be sent. This is often used to speed up + rapid method calls where there are no "out" arguments, and not knowing + if the method succeeded is an acceptable compromise to half the traffic + on the bus. +

GLib API: Implementing Objects

+ At the moment, to expose a GObject via D-Bus, you must + write XML by hand which describes the methods exported + by the object. In the future, this manual step will + be obviated by the upcoming GLib introspection support. +

+ Here is a sample XML file which describes an object that exposes + one method, named ManyArgs. +

+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/com/example/MyObject">
+
+  <interface name="com.example.MyObject">
+    <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object"/>
+    <method name="ManyArgs">
+      <!-- This is optional, and in this case is redunundant -->
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_many_args"/>
+      <arg type="u" name="x" direction="in" />
+      <arg type="s" name="str" direction="in" />
+      <arg type="d" name="trouble" direction="in" />
+      <arg type="d" name="d_ret" direction="out" />
+      <arg type="s" name="str_ret" direction="out" />
+    </method>
+  </interface>
+</node>
+

+

+ This XML is in the same format as the D-Bus introspection XML + format. Except we must include an "annotation" which give the C + symbols corresponding to the object implementation prefix + (my_object). In addition, if particular + methods symbol names deviate from C convention + (i.e. ManyArgs -> + many_args), you may specify an annotation + giving the C symbol. +

+ Once you have written this XML, run dbus-binding-tool --mode=glib-server FILENAME > HEADER_NAME. to + generate a header file. For example: dbus-binding-tool --mode=glib-server my-object.xml > my-object-glue.h. +

+ Next, include the generated header in your program, and invoke + dbus_g_object_class_install_info in the class + initializer, passing the object class and "object info" included in the + header. For example: +

+	dbus_g_object_type_install_info (COM_FOO_TYPE_MY_OBJECT, &com_foo_my_object_info);
+      

+ This should be done exactly once per object class. +

+ To actually implement the method, just define a C function named e.g. + my_object_many_args in the same file as the info + header is included. At the moment, it is required that this function + conform to the following rules: +

  • + The function must return a value of type gboolean; + TRUE on success, and FALSE + otherwise. +

  • + The first parameter is a pointer to an instance of the object. +

  • + Following the object instance pointer are the method + input values. +

  • + Following the input values are pointers to return values. +

  • + The final parameter must be a GError **. + If the function returns FALSE for an + error, the error parameter must be initalized with + g_set_error. +

+

+ Finally, you can export an object using dbus_g_connection_register_g_object. For example: +

+	  dbus_g_connection_register_g_object (connection,
+                                               "/com/foo/MyObject",
+                                               obj);
+      

+

Server-side Annotations

+ There are several annotations that are used when generating the + server-side bindings. The most common annotation is + org.freedesktop.DBus.GLib.CSymbol but there are other + annotations which are often useful. +

org.freedesktop.DBus.GLib.CSymbol

+ This annotation is used to specify the C symbol names for + the various types (interface, method, etc), if it differs from the + name DBus generates. +

org.freedesktop.DBus.GLib.Async

+ This annotation marks the method implementation as an + asynchronous function, which doesn't return a response straight + away but will send the response at some later point to complete + the call. This is used to implement non-blocking services where + method calls can take time. +

+ When a method is asynchronous, the function prototype is + different. It is required that the function conform to the + following rules: +

  • + The function must return a value of type gboolean; + TRUE on success, and FALSE + otherwise. TODO: the return value is currently ignored. +

  • + The first parameter is a pointer to an instance of the object. +

  • + Following the object instance pointer are the method + input values. +

  • + The final parameter must be a + DBusGMethodInvocation *. This is used + when sending the response message back to the client, by + calling dbus_g_method_return or + dbus_g_method_return_error. +

+

org.freedesktop.DBus.GLib.Const

This attribute can only be applied to "out" + <arg> nodes, and specifies that the + parameter isn't being copied when returned. For example, this + turns a 's' argument from a char ** to a + const char **, and results in the argument not + being freed by DBus after the message is sent. +

org.freedesktop.DBus.GLib.ReturnVal

+ This attribute can only be applied to "out" + <arg> nodes, and alters the expected + function signature. It currently can be set to two values: + "" or "error". The + argument marked with this attribute is not returned via a + pointer argument, but by the function's return value. If the + attribute's value is the empty string, the GError + * argument is also omitted so there is no standard way + to return an error value. This is very useful for interfacing + with existing code, as it is possible to match existing APIs. + If the attribute's value is "error", then the + final argument is a GError * as usual. +

+ Some examples to demonstrate the usage. This introspection XML: +

+<method name="Increment">
+  <arg type="u" name="x" />
+  <arg type="u" direction="out" />
+</method>
+                

+ Expects the following function declaration: +

+gboolean
+my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error);
+                

+

+ This introspection XML: +

+<method name="IncrementRetval">
+  <arg type="u" name="x" />
+  <arg type="u" direction="out" >
+    <annotation name="org.freedesktop.DBus.GLib.ReturnVal" value=""/>
+  </arg>
+</method>
+                

+ Expects the following function declaration: +

+gint32
+my_object_increment_retval (MyObject *obj, gint32 x)
+                

+

+ This introspection XML: +

+<method name="IncrementRetvalError">
+  <arg type="u" name="x" />
+  <arg type="u" direction="out" >
+    <annotation name="org.freedesktop.DBus.GLib.ReturnVal" value="error"/>
+  </arg>
+</method>
+                

+ Expects the following function declaration: +

+gint32
+my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error)
+                

+

+

Python API

+ The Python API, dbus-python, is now documented separately in + the dbus-python tutorial (also available in doc/tutorial.txt, + and doc/tutorial.html if built with python-docutils, in the dbus-python + source distribution). +

Qt API: Using Remote Objects

+ + The Qt bindings are not yet documented. + +

Qt API: Implementing Objects

+ The Qt bindings are not yet documented. +

diff --git a/doc/dbus-tutorial.xml b/doc/dbus-tutorial.xml new file mode 100644 index 00000000..5c385f0e --- /dev/null +++ b/doc/dbus-tutorial.xml @@ -0,0 +1,1667 @@ + + + +
+ + D-Bus Tutorial + Version 0.5.0 + 20 August 2006 + + + Havoc + Pennington + + Red Hat, Inc. +
hp@pobox.com
+
+
+ + David + Wheeler + + + John + Palmieri + + Red Hat, Inc. +
johnp@redhat.com
+
+
+ + Colin + Walters + + Red Hat, Inc. +
walters@redhat.com
+
+
+
+
+ + + Tutorial Work In Progress + + + This tutorial is not complete; it probably contains some useful information, but + also has plenty of gaps. Right now, you'll also need to refer to the D-Bus specification, + Doxygen reference documentation, and look at some examples of how other apps use D-Bus. + + + + Enhancing the tutorial is definitely encouraged - send your patches or suggestions to the + mailing list. If you create a D-Bus binding, please add a section to the tutorial for your + binding, if only a short section with a couple of examples. + + + + + + What is D-Bus? + + D-Bus is a system for interprocess communication + (IPC). Architecturally, it has several layers: + + + + + A library, libdbus, that allows two + applications to connect to each other and exchange messages. + + + + + A message bus daemon executable, built on + libdbus, that multiple applications can connect to. The daemon can + route messages from one application to zero or more other + applications. + + + + + Wrapper libraries or bindings + based on particular application frameworks. For example, libdbus-glib and + libdbus-qt. There are also bindings to languages such as + Python. These wrapper libraries are the API most people should use, + as they simplify the details of D-Bus programming. libdbus is + intended to be a low-level backend for the higher level bindings. + Much of the libdbus API is only useful for binding implementation. + + + + + + + libdbus only supports one-to-one connections, just like a raw network + socket. However, rather than sending byte streams over the connection, you + send messages. Messages have a header identifying + the kind of message, and a body containing a data payload. libdbus also + abstracts the exact transport used (sockets vs. whatever else), and + handles details such as authentication. + + + + The message bus daemon forms the hub of a wheel. Each spoke of the wheel + is a one-to-one connection to an application using libdbus. An + application sends a message to the bus daemon over its spoke, and the bus + daemon forwards the message to other connected applications as + appropriate. Think of the daemon as a router. + + + + The bus daemon has multiple instances on a typical computer. The + first instance is a machine-global singleton, that is, a system daemon + similar to sendmail or Apache. This instance has heavy security + restrictions on what messages it will accept, and is used for systemwide + communication. The other instances are created one per user login session. + These instances allow applications in the user's session to communicate + with one another. + + + + The systemwide and per-user daemons are separate. Normal within-session + IPC does not involve the systemwide message bus process and vice versa. + + + + D-Bus applications + + There are many, many technologies in the world that have "Inter-process + communication" or "networking" in their stated purpose: CORBA, DCE, DCOM, DCOP, XML-RPC, SOAP, MBUS, Internet Communications Engine (ICE), + and probably hundreds more. + Each of these is tailored for particular kinds of application. + D-Bus is designed for two specific cases: + + + + Communication between desktop applications in the same desktop + session; to allow integration of the desktop session as a whole, + and address issues of process lifecycle (when do desktop components + start and stop running). + + + + + Communication between the desktop session and the operating system, + where the operating system would typically include the kernel + and any system daemons or processes. + + + + + + For the within-desktop-session use case, the GNOME and KDE desktops + have significant previous experience with different IPC solutions + such as CORBA and DCOP. D-Bus is built on that experience and + carefully tailored to meet the needs of these desktop projects + in particular. D-Bus may or may not be appropriate for other + applications; the FAQ has some comparisons to other IPC systems. + + + The problem solved by the systemwide or communication-with-the-OS case + is explained well by the following text from the Linux Hotplug project: +
+ + A gap in current Linux support is that policies with any sort of + dynamic "interact with user" component aren't currently + supported. For example, that's often needed the first time a network + adapter or printer is connected, and to determine appropriate places + to mount disk drives. It would seem that such actions could be + supported for any case where a responsible human can be identified: + single user workstations, or any system which is remotely + administered. + + + + This is a classic "remote sysadmin" problem, where in this case + hotplugging needs to deliver an event from one security domain + (operating system kernel, in this case) to another (desktop for + logged-in user, or remote sysadmin). Any effective response must go + the other way: the remote domain taking some action that lets the + kernel expose the desired device capabilities. (The action can often + be taken asynchronously, for example letting new hardware be idle + until a meeting finishes.) At this writing, Linux doesn't have + widely adopted solutions to such problems. However, the new D-Bus + work may begin to solve that problem. + +
+
+ + D-Bus may happen to be useful for purposes other than the one it was + designed for. Its general properties that distinguish it from + other forms of IPC are: + + + + Binary protocol designed to be used asynchronously + (similar in spirit to the X Window System protocol). + + + + + Stateful, reliable connections held open over time. + + + + + The message bus is a daemon, not a "swarm" or + distributed architecture. + + + + + Many implementation and deployment issues are specified rather + than left ambiguous/configurable/pluggable. + + + + + Semantics are similar to the existing DCOP system, allowing + KDE to adopt it more easily. + + + + + Security features to support the systemwide mode of the + message bus. + + + + +
+
+ + Concepts + + Some basic concepts apply no matter what application framework you're + using to write a D-Bus application. The exact code you write will be + different for GLib vs. Qt vs. Python applications, however. + + + + Here is a diagram (png svg) that may help you visualize the concepts + that follow. + + + + Native Objects and Object Paths + + Your programming framework probably defines what an "object" is like; + usually with a base class. For example: java.lang.Object, GObject, QObject, + python's base Object, or whatever. Let's call this a native object. + + + The low-level D-Bus protocol, and corresponding libdbus API, does not care about native objects. + However, it provides a concept called an + object path. The idea of an object path is that + higher-level bindings can name native object instances, and allow remote applications + to refer to them. + + + The object path + looks like a filesystem path, for example an object could be + named /org/kde/kspread/sheets/3/cells/4/5. + Human-readable paths are nice, but you are free to create an + object named /com/mycompany/c5yo817y0c1y1c5b + if it makes sense for your application. + + + Namespacing object paths is smart, by starting them with the components + of a domain name you own (e.g. /org/kde). This + keeps different code modules in the same process from stepping + on one another's toes. + + + + + Methods and Signals + + + Each object has members; the two kinds of member + are methods and + signals. Methods are operations that can be + invoked on an object, with optional input (aka arguments or "in + parameters") and output (aka return values or "out parameters"). + Signals are broadcasts from the object to any interested observers + of the object; signals may contain a data payload. + + + + Both methods and signals are referred to by name, such as + "Frobate" or "OnClicked". + + + + + + Interfaces + + Each object supports one or more interfaces. + Think of an interface as a named group of methods and signals, + just as it is in GLib or Qt or Java. Interfaces define the + type of an object instance. + + + DBus identifies interfaces with a simple namespaced string, + something like org.freedesktop.Introspectable. + Most bindings will map these interface names directly to + the appropriate programming language construct, for example + to Java interfaces or C++ pure virtual classes. + + + + + Proxies + + A proxy object is a convenient native object created to + represent a remote object in another process. The low-level DBus API involves manually creating + a method call message, sending it, then manually receiving and processing + the method reply message. Higher-level bindings provide proxies as an alternative. + Proxies look like a normal native object; but when you invoke a method on the proxy + object, the binding converts it into a DBus method call message, waits for the reply + message, unpacks the return value, and returns it from the native method.. + + + In pseudocode, programming without proxies might look like this: + + Message message = new Message("/remote/object/path", "MethodName", arg1, arg2); + Connection connection = getBusConnection(); + connection.send(message); + Message reply = connection.waitForReply(message); + if (reply.isError()) { + + } else { + Object returnValue = reply.getReturnValue(); + } + + + + Programming with proxies might look like this: + + Proxy proxy = new Proxy(getBusConnection(), "/remote/object/path"); + Object returnValue = proxy.MethodName(arg1, arg2); + + + + + + Bus Names + + + When each application connects to the bus daemon, the daemon immediately + assigns it a name, called the unique connection name. + A unique name begins with a ':' (colon) character. These names are never + reused during the lifetime of the bus daemon - that is, you know + a given name will always refer to the same application. + An example of a unique name might be + :34-907. The numbers after the colon have + no meaning other than their uniqueness. + + + + When a name is mapped + to a particular application's connection, that application is said to + own that name. + + + + Applications may ask to own additional well-known + names. For example, you could write a specification to + define a name called com.mycompany.TextEditor. + Your definition could specify that to own this name, an application + should have an object at the path + /com/mycompany/TextFileManager supporting the + interface org.freedesktop.FileHandler. + + + + Applications could then send messages to this bus name, + object, and interface to execute method calls. + + + + You could think of the unique names as IP addresses, and the + well-known names as domain names. So + com.mycompany.TextEditor might map to something like + :34-907 just as mycompany.com maps + to something like 192.168.0.5. + + + + Names have a second important use, other than routing messages. They + are used to track lifecycle. When an application exits (or crashes), its + connection to the message bus will be closed by the operating system + kernel. The message bus then sends out notification messages telling + remaining applications that the application's names have lost their + owner. By tracking these notifications, your application can reliably + monitor the lifetime of other applications. + + + + Bus names can also be used to coordinate single-instance applications. + If you want to be sure only one + com.mycompany.TextEditor application is running for + example, have the text editor application exit if the bus name already + has an owner. + + + + + + Addresses + + + Applications using D-Bus are either servers or clients. A server + listens for incoming connections; a client connects to a server. Once + the connection is established, it is a symmetric flow of messages; the + client-server distinction only matters when setting up the + connection. + + + + If you're using the bus daemon, as you probably are, your application + will be a client of the bus daemon. That is, the bus daemon listens + for connections and your application initiates a connection to the bus + daemon. + + + + A D-Bus address specifies where a server will + listen, and where a client will connect. For example, the address + unix:path=/tmp/abcdef specifies that the server will + listen on a UNIX domain socket at the path + /tmp/abcdef and the client will connect to that + socket. An address can also specify TCP/IP sockets, or any other + transport defined in future iterations of the D-Bus specification. + + + + When using D-Bus with a message bus daemon, + libdbus automatically discovers the address of the per-session bus + daemon by reading an environment variable. It discovers the + systemwide bus daemon by checking a well-known UNIX domain socket path + (though you can override this address with an environment variable). + + + + If you're using D-Bus without a bus daemon, it's up to you to + define which application will be the server and which will be + the client, and specify a mechanism for them to agree on + the server's address. This is an unusual case. + + + + + + Big Conceptual Picture + + + Pulling all these concepts together, to specify a particular + method call on a particular object instance, a number of + nested components have to be named: + + Address -> [Bus Name] -> Path -> Interface -> Method + + The bus name is in brackets to indicate that it's optional -- you only + provide a name to route the method call to the right application + when using the bus daemon. If you have a direct connection to another + application, bus names aren't used; there's no bus daemon. + + + + The interface is also optional, primarily for historical + reasons; DCOP does not require specifying the interface, + instead simply forbidding duplicate method names + on the same object instance. D-Bus will thus let you + omit the interface, but if your method name is ambiguous + it is undefined which method will be invoked. + + + + + + Messages - Behind the Scenes + + D-Bus works by sending messages between processes. If you're using + a sufficiently high-level binding, you may never work with messages directly. + + + There are 4 message types: + + + + Method call messages ask to invoke a method + on an object. + + + + + Method return messages return the results + of invoking a method. + + + + + Error messages return an exception caused by + invoking a method. + + + + + Signal messages are notifications that a given signal + has been emitted (that an event has occurred). + You could also think of these as "event" messages. + + + + + + A method call maps very simply to messages: you send a method call + message, and receive either a method return message or an error message + in reply. + + + Each message has a header, including fields, + and a body, including arguments. You can think + of the header as the routing information for the message, and the body as the payload. + Header fields might include the sender bus name, destination bus name, method or signal name, + and so forth. One of the header fields is a type signature describing the + values found in the body. For example, the letter "i" means "32-bit integer" so the signature + "ii" means the payload has two 32-bit integers. + + + + + Calling a Method - Behind the Scenes + + + A method call in DBus consists of two messages; a method call message sent from process A to process B, + and a matching method reply message sent from process B to process A. Both the call and the reply messages + are routed through the bus daemon. The caller includes a different serial number in each call message, and the + reply message includes this number to allow the caller to match replies to calls. + + + + The call message will contain any arguments to the method. + The reply message may indicate an error, or may contain data returned by the method. + + + + A method invocation in DBus happens as follows: + + + + The language binding may provide a proxy, such that invoking a method on + an in-process object invokes a method on a remote object in another process. If so, the + application calls a method on the proxy, and the proxy + constructs a method call message to send to the remote process. + + + + + For more low-level APIs, the application may construct a method call message itself, without + using a proxy. + + + + + In either case, the method call message contains: a bus name belonging to the remote process; the name of the method; + the arguments to the method; an object path inside the remote process; and optionally the name of the + interface that specifies the method. + + + + + The method call message is sent to the bus daemon. + + + + + The bus daemon looks at the destination bus name. If a process owns that name, + the bus daemon forwards the method call to that process. Otherwise, the bus daemon + creates an error message and sends it back as the reply to the method call message. + + + + + The receiving process unpacks the method call message. In a simple low-level API situation, it + may immediately run the method and send a method reply message to the bus daemon. + When using a high-level binding API, the binding might examine the object path, interface, + and method name, and convert the method call message into an invocation of a method on + a native object (GObject, java.lang.Object, QObject, etc.), then convert the return + value from the native method into a method reply message. + + + + + The bus daemon receives the method reply message and sends it to the process that + made the method call. + + + + + The process that made the method call looks at the method reply and makes use of any + return values included in the reply. The reply may also indicate that an error occurred. + When using a binding, the method reply message may be converted into the return value of + of a proxy method, or into an exception. + + + + + + + The bus daemon never reorders messages. That is, if you send two method call messages to the same recipient, + they will be received in the order they were sent. The recipient is not required to reply to the calls + in order, however; for example, it may process each method call in a separate thread, and return reply messages + in an undefined order depending on when the threads complete. Method calls have a unique serial + number used by the method caller to match reply messages to call messages. + + + + + + Emitting a Signal - Behind the Scenes + + + A signal in DBus consists of a single message, sent by one process to any number of other processes. + That is, a signal is a unidirectional broadcast. The signal may contain arguments (a data payload), but + because it is a broadcast, it never has a "return value." Contrast this with a method call + (see ) where the method call message has a matching method reply message. + + + + The emitter (aka sender) of a signal has no knowledge of the signal recipients. Recipients register + with the bus daemon to receive signals based on "match rules" - these rules would typically include the sender and + the signal name. The bus daemon sends each signal only to recipients who have expressed interest in that + signal. + + + + A signal in DBus happens as follows: + + + + A signal message is created and sent to the bus daemon. When using the low-level API this may be + done manually, with certain bindings it may be done for you by the binding when a native object + emits a native signal or event. + + + + + The signal message contains the name of the interface that specifies the signal; + the name of the signal; the bus name of the process sending the signal; and + any arguments + + + + + Any process on the message bus can register "match rules" indicating which signals it + is interested in. The bus has a list of registered match rules. + + + + + The bus daemon examines the signal and determines which processes are interested in it. + It sends the signal message to these processes. + + + + + Each process receiving the signal decides what to do with it; if using a binding, + the binding may choose to emit a native signal on a proxy object. If using the + low-level API, the process may just look at the signal sender and name and decide + what to do based on that. + + + + + + + + + Introspection + + + D-Bus objects may support the interface org.freedesktop.DBus.Introspectable. + This interface has one method Introspect which takes no arguments and returns + an XML string. The XML string describes the interfaces, methods, and signals of the object. + See the D-Bus specification for more details on this introspection format. + + + + + + + + GLib API: Using Remote Objects + + + The GLib binding is defined in the header file + <dbus/dbus-glib.h>. + + + + D-Bus - GLib type mappings + + The heart of the GLib bindings for D-Bus is the mapping it + provides between D-Bus "type signatures" and GLib types + (GType). The D-Bus type system is composed of + a number of "basic" types, along with several "container" types. + + + Basic type mappings + + Below is a list of the basic types, along with their associated + mapping to a GType. + + + + + D-Bus basic type + GType + Free function + Notes + + + + + BYTE + G_TYPE_UCHAR + + + + BOOLEAN + G_TYPE_BOOLEAN + + + + INT16 + G_TYPE_INT + + Will be changed to a G_TYPE_INT16 once GLib has it + + UINT16 + G_TYPE_UINT + + Will be changed to a G_TYPE_UINT16 once GLib has it + + INT32 + G_TYPE_INT + + Will be changed to a G_TYPE_INT32 once GLib has it + + UINT32 + G_TYPE_UINT + + Will be changed to a G_TYPE_UINT32 once GLib has it + + INT64 + G_TYPE_GINT64 + + + + UINT64 + G_TYPE_GUINT64 + + + + DOUBLE + G_TYPE_DOUBLE + + + + STRING + G_TYPE_STRING + g_free + + + OBJECT_PATH + DBUS_TYPE_G_PROXY + g_object_unref + The returned proxy does not have an interface set; use dbus_g_proxy_set_interface to invoke methods + + + + + As you can see, the basic mapping is fairly straightforward. + + + + Container type mappings + + The D-Bus type system also has a number of "container" + types, such as DBUS_TYPE_ARRAY and + DBUS_TYPE_STRUCT. The D-Bus type system + is fully recursive, so one can for example have an array of + array of strings (i.e. type signature + aas). + + + However, not all of these types are in common use; for + example, at the time of this writing the author knows of no + one using DBUS_TYPE_STRUCT, or a + DBUS_TYPE_ARRAY containing any non-basic + type. The approach the GLib bindings take is pragmatic; try + to map the most common types in the most obvious way, and + let using less common and more complex types be less + "natural". + + + First, D-Bus type signatures which have an "obvious" + corresponding built-in GLib type are mapped using that type: + + + + + D-Bus type signature + Description + GType + C typedef + Free function + Notes + + + + + as + Array of strings + G_TYPE_STRV + char ** + g_strfreev + + + v + Generic value container + G_TYPE_VALUE + GValue * + g_value_unset + The calling conventions for values expect that method callers have allocated return values; see below. + + + + + + + The next most common recursive type signatures are arrays of + basic values. The most obvious mapping for arrays of basic + types is a GArray. Now, GLib does not + provide a builtin GType for + GArray. However, we actually need more than + that - we need a "parameterized" type which includes the + contained type. Why we need this we will see below. + + + The approach taken is to create these types in the D-Bus GLib + bindings; however, there is nothing D-Bus specific about them. + In the future, we hope to include such "fundamental" types in GLib + itself. + + + + + D-Bus type signature + Description + GType + C typedef + Free function + Notes + + + + + ay + Array of bytes + DBUS_TYPE_G_BYTE_ARRAY + GArray * + g_array_free + + + + au + Array of uint + DBUS_TYPE_G_UINT_ARRAY + GArray * + g_array_free + + + + ai + Array of int + DBUS_TYPE_G_INT_ARRAY + GArray * + g_array_free + + + + ax + Array of int64 + DBUS_TYPE_G_INT64_ARRAY + GArray * + g_array_free + + + + at + Array of uint64 + DBUS_TYPE_G_UINT64_ARRAY + GArray * + g_array_free + + + + ad + Array of double + DBUS_TYPE_G_DOUBLE_ARRAY + GArray * + g_array_free + + + + ab + Array of boolean + DBUS_TYPE_G_BOOLEAN_ARRAY + GArray * + g_array_free + + + + + + + + D-Bus also includes a special type DBUS_TYPE_DICT_ENTRY which + is only valid in arrays. It's intended to be mapped to a "dictionary" + type by bindings. The obvious GLib mapping here is GHashTable. Again, + however, there is no builtin GType for a GHashTable. + Moreover, just like for arrays, we need a parameterized type so that + the bindings can communiate which types are contained in the hash table. + + + At present, only strings are supported. Work is in progress to + include more types. + + + + + D-Bus type signature + Description + GType + C typedef + Free function + Notes + + + + + a{ss} + Dictionary mapping strings to strings + DBUS_TYPE_G_STRING_STRING_HASHTABLE + GHashTable * + g_hash_table_destroy + + + + + + + + + Arbitrarily recursive type mappings + + Finally, it is possible users will want to write or invoke D-Bus + methods which have arbitrarily complex type signatures not + directly supported by these bindings. For this case, we have a + DBusGValue which acts as a kind of special + variant value which may be iterated over manually. The + GType associated is + DBUS_TYPE_G_VALUE. + + + TODO insert usage of DBUS_TYPE_G_VALUE here. + + + + + A sample program + Here is a D-Bus program using the GLib bindings. + +int +main (int argc, char **argv) +{ + DBusGConnection *connection; + GError *error; + DBusGProxy *proxy; + char **name_list; + char **name_list_ptr; + + g_type_init (); + + error = NULL; + connection = dbus_g_bus_get (DBUS_BUS_SESSION, + &error); + if (connection == NULL) + { + g_printerr ("Failed to open connection to bus: %s\n", + error->message); + g_error_free (error); + exit (1); + } + + /* Create a proxy object for the "bus driver" (name "org.freedesktop.DBus") */ + + proxy = dbus_g_proxy_new_for_name (connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + + /* Call ListNames method, wait for reply */ + error = NULL; + if (!dbus_g_proxy_call (proxy, "ListNames", &error, G_TYPE_INVALID, + G_TYPE_STRV, &name_list, G_TYPE_INVALID)) + { + /* Just do demonstrate remote exceptions versus regular GError */ + if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) + g_printerr ("Caught remote method exception %s: %s", + dbus_g_error_get_name (error), + error->message); + else + g_printerr ("Error: %s\n", error->message); + g_error_free (error); + exit (1); + } + + /* Print the results */ + + g_print ("Names on the message bus:\n"); + + for (name_list_ptr = name_list; *name_list_ptr; name_list_ptr++) + { + g_print (" %s\n", *name_list_ptr); + } + g_strfreev (name_list); + + g_object_unref (proxy); + + return 0; +} + + + + + Program initalization + + A connection to the bus is acquired using + dbus_g_bus_get. Next, a proxy + is created for the object "/org/freedesktop/DBus" with + interface org.freedesktop.DBus + on the service org.freedesktop.DBus. + This is a proxy for the message bus itself. + + + + Understanding method invocation + + You have a number of choices for method invocation. First, as + used above, dbus_g_proxy_call sends a + method call to the remote object, and blocks until a reply is + recieved. The outgoing arguments are specified in the varargs + array, terminated with G_TYPE_INVALID. + Next, pointers to return values are specified, followed again + by G_TYPE_INVALID. + + + To invoke a method asynchronously, use + dbus_g_proxy_begin_call. This returns a + DBusGPendingCall object; you may then set a + notification function using + dbus_g_pending_call_set_notify. + + + + Connecting to object signals + + You may connect to signals using + dbus_g_proxy_add_signal and + dbus_g_proxy_connect_signal. You must + invoke dbus_g_proxy_add_signal to specify + the signature of your signal handlers; you may then invoke + dbus_g_proxy_connect_signal multiple times. + + + Note that it will often be the case that there is no builtin + marshaller for the type signature of a remote signal. In that + case, you must generate a marshaller yourself by using + glib-genmarshal, and then register + it using dbus_g_object_register_marshaller. + + + + Error handling and remote exceptions + + All of the GLib binding methods such as + dbus_g_proxy_end_call return a + GError. This GError can + represent two different things: + + + + An internal D-Bus error, such as an out-of-memory + condition, an I/O error, or a network timeout. Errors + generated by the D-Bus library itself have the domain + DBUS_GERROR, and a corresponding code + such as DBUS_GERROR_NO_MEMORY. It will + not be typical for applications to handle these errors + specifically. + + + + + A remote D-Bus exception, thrown by the peer, bus, or + service. D-Bus remote exceptions have both a textual + "name" and a "message". The GLib bindings store this + information in the GError, but some + special rules apply. + + + The set error will have the domain + DBUS_GERROR as above, and will also + have the code + DBUS_GERROR_REMOTE_EXCEPTION. In order + to access the remote exception name, you must use a + special accessor, such as + dbus_g_error_has_name or + dbus_g_error_get_name. The remote + exception detailed message is accessible via the regular + GError message member. + + + + + + + More examples of method invocation + + Sending an integer and string, receiving an array of bytes + + + GArray *arr; + + error = NULL; + if (!dbus_g_proxy_call (proxy, "Foobar", &error, + G_TYPE_INT, 42, G_TYPE_STRING, "hello", + G_TYPE_INVALID, + DBUS_TYPE_G_UCHAR_ARRAY, &arr, G_TYPE_INVALID)) + { + /* Handle error */ + } + g_assert (arr != NULL); + printf ("got back %u values", arr->len); + + + + + Sending a GHashTable + + + GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal); + guint32 ret; + + g_hash_table_insert (hash, "foo", "bar"); + g_hash_table_insert (hash, "baz", "whee"); + + error = NULL; + if (!dbus_g_proxy_call (proxy, "HashSize", &error, + DBUS_TYPE_G_STRING_STRING_HASH, hash, G_TYPE_INVALID, + G_TYPE_UINT, &ret, G_TYPE_INVALID)) + { + /* Handle error */ + } + g_assert (ret == 2); + g_hash_table_destroy (hash); + + + + + Receiving a boolean and a string + + + gboolean boolret; + char *strret; + + error = NULL; + if (!dbus_g_proxy_call (proxy, "GetStuff", &error, + G_TYPE_INVALID, + G_TYPE_BOOLEAN, &boolret, + G_TYPE_STRING, &strret, + G_TYPE_INVALID)) + { + /* Handle error */ + } + printf ("%s %s", boolret ? "TRUE" : "FALSE", strret); + g_free (strret); + + + + + Sending two arrays of strings + + + /* NULL terminate */ + char *strs_static[] = {"foo", "bar", "baz", NULL}; + /* Take pointer to array; cannot pass array directly */ + char **strs_static_p = strs_static; + char **strs_dynamic; + + strs_dynamic = g_new (char *, 4); + strs_dynamic[0] = g_strdup ("hello"); + strs_dynamic[1] = g_strdup ("world"); + strs_dynamic[2] = g_strdup ("!"); + /* NULL terminate */ + strs_dynamic[3] = NULL; + + error = NULL; + if (!dbus_g_proxy_call (proxy, "TwoStrArrays", &error, + G_TYPE_STRV, strs_static_p, + G_TYPE_STRV, strs_dynamic, + G_TYPE_INVALID, + G_TYPE_INVALID)) + { + /* Handle error */ + } + g_strfreev (strs_dynamic); + + + + + Sending a boolean, receiving an array of strings + + + char **strs; + char **strs_p; + gboolean blah; + + error = NULL; + blah = TRUE; + if (!dbus_g_proxy_call (proxy, "GetStrs", &error, + G_TYPE_BOOLEAN, blah, + G_TYPE_INVALID, + G_TYPE_STRV, &strs, + G_TYPE_INVALID)) + { + /* Handle error */ + } + for (strs_p = strs; *strs_p; strs_p++) + printf ("got string: \"%s\"", *strs_p); + g_strfreev (strs); + + + + + Sending a variant + + + GValue val = {0, }; + + g_value_init (&val, G_TYPE_STRING); + g_value_set_string (&val, "hello world"); + + error = NULL; + if (!dbus_g_proxy_call (proxy, "SendVariant", &error, + G_TYPE_VALUE, &val, G_TYPE_INVALID, + G_TYPE_INVALID)) + { + /* Handle error */ + } + g_assert (ret == 2); + g_value_unset (&val); + + + + + Receiving a variant + + + GValue val = {0, }; + + error = NULL; + if (!dbus_g_proxy_call (proxy, "GetVariant", &error, G_TYPE_INVALID, + G_TYPE_VALUE, &val, G_TYPE_INVALID)) + { + /* Handle error */ + } + if (G_VALUE_TYPE (&val) == G_TYPE_STRING) + printf ("%s\n", g_value_get_string (&val)); + else if (G_VALUE_TYPE (&val) == G_TYPE_INT) + printf ("%d\n", g_value_get_int (&val)); + else + ... + g_value_unset (&val); + + + + + + + Generated Bindings + + By using the Introspection XML files, convenient client-side bindings + can be automatically created to ease the use of a remote DBus object. + + + Here is a sample XML file which describes an object that exposes + one method, named ManyArgs. + +<?xml version="1.0" encoding="UTF-8" ?> +<node name="/com/example/MyObject"> + <interface name="com.example.MyObject"> + <method name="ManyArgs"> + <arg type="u" name="x" direction="in" /> + <arg type="s" name="str" direction="in" /> + <arg type="d" name="trouble" direction="in" /> + <arg type="d" name="d_ret" direction="out" /> + <arg type="s" name="str_ret" direction="out" /> + </method> + </interface> +</node> + + + + Run dbus-binding-tool --mode=glib-client + FILENAME > + HEADER_NAME to generate the header + file. For example: dbus-binding-tool --mode=glib-client + my-object.xml > my-object-bindings.h. This will generate + inline functions with the following prototypes: + +/* This is a blocking call */ +gboolean +com_example_MyObject_many_args (DBusGProxy *proxy, const guint IN_x, + const char * IN_str, const gdouble IN_trouble, + gdouble* OUT_d_ret, char ** OUT_str_ret, + GError **error); + +/* This is a non-blocking call */ +DBusGProxyCall* +com_example_MyObject_many_args_async (DBusGProxy *proxy, const guint IN_x, + const char * IN_str, const gdouble IN_trouble, + com_example_MyObject_many_args_reply callback, + gpointer userdata); + +/* This is the typedef for the non-blocking callback */ +typedef void +(*com_example_MyObject_many_args_reply) +(DBusGProxy *proxy, gdouble OUT_d_ret, char * OUT_str_ret, + GError *error, gpointer userdata); + + The first argument in all functions is a DBusGProxy + *, which you should create with the usual + dbus_g_proxy_new_* functions. Following that are the + "in" arguments, and then either the "out" arguments and a + GError * for the synchronous (blocking) function, or + callback and user data arguments for the asynchronous (non-blocking) + function. The callback in the asynchronous function passes the + DBusGProxy *, the returned "out" arguments, an + GError * which is set if there was an error otherwise + NULL, and the user data. + + + As with the server-side bindings support (see ), the exact behaviour of the client-side + bindings can be manipulated using "annotations". Currently the only + annotation used by the client bindings is + org.freedesktop.DBus.GLib.NoReply, which sets the + flag indicating that the client isn't expecting a reply to the method + call, so a reply shouldn't be sent. This is often used to speed up + rapid method calls where there are no "out" arguments, and not knowing + if the method succeeded is an acceptable compromise to half the traffic + on the bus. + + + + + + GLib API: Implementing Objects + + At the moment, to expose a GObject via D-Bus, you must + write XML by hand which describes the methods exported + by the object. In the future, this manual step will + be obviated by the upcoming GLib introspection support. + + + Here is a sample XML file which describes an object that exposes + one method, named ManyArgs. + +<?xml version="1.0" encoding="UTF-8" ?> + +<node name="/com/example/MyObject"> + + <interface name="com.example.MyObject"> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object"/> + <method name="ManyArgs"> + <!-- This is optional, and in this case is redunundant --> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_many_args"/> + <arg type="u" name="x" direction="in" /> + <arg type="s" name="str" direction="in" /> + <arg type="d" name="trouble" direction="in" /> + <arg type="d" name="d_ret" direction="out" /> + <arg type="s" name="str_ret" direction="out" /> + </method> + </interface> +</node> + + + + This XML is in the same format as the D-Bus introspection XML + format. Except we must include an "annotation" which give the C + symbols corresponding to the object implementation prefix + (my_object). In addition, if particular + methods symbol names deviate from C convention + (i.e. ManyArgs -> + many_args), you may specify an annotation + giving the C symbol. + + + Once you have written this XML, run dbus-binding-tool --mode=glib-server FILENAME > HEADER_NAME. to + generate a header file. For example: dbus-binding-tool --mode=glib-server my-object.xml > my-object-glue.h. + + + Next, include the generated header in your program, and invoke + dbus_g_object_class_install_info in the class + initializer, passing the object class and "object info" included in the + header. For example: + + dbus_g_object_type_install_info (COM_FOO_TYPE_MY_OBJECT, &com_foo_my_object_info); + + This should be done exactly once per object class. + + + To actually implement the method, just define a C function named e.g. + my_object_many_args in the same file as the info + header is included. At the moment, it is required that this function + conform to the following rules: + + + + The function must return a value of type gboolean; + TRUE on success, and FALSE + otherwise. + + + + + The first parameter is a pointer to an instance of the object. + + + + + Following the object instance pointer are the method + input values. + + + + + Following the input values are pointers to return values. + + + + + The final parameter must be a GError **. + If the function returns FALSE for an + error, the error parameter must be initalized with + g_set_error. + + + + + + Finally, you can export an object using dbus_g_connection_register_g_object. For example: + + dbus_g_connection_register_g_object (connection, + "/com/foo/MyObject", + obj); + + + + + Server-side Annotations + + There are several annotations that are used when generating the + server-side bindings. The most common annotation is + org.freedesktop.DBus.GLib.CSymbol but there are other + annotations which are often useful. + + + org.freedesktop.DBus.GLib.CSymbol + + + This annotation is used to specify the C symbol names for + the various types (interface, method, etc), if it differs from the + name DBus generates. + + + + + org.freedesktop.DBus.GLib.Async + + + This annotation marks the method implementation as an + asynchronous function, which doesn't return a response straight + away but will send the response at some later point to complete + the call. This is used to implement non-blocking services where + method calls can take time. + + + When a method is asynchronous, the function prototype is + different. It is required that the function conform to the + following rules: + + + + The function must return a value of type gboolean; + TRUE on success, and FALSE + otherwise. TODO: the return value is currently ignored. + + + + + The first parameter is a pointer to an instance of the object. + + + + + Following the object instance pointer are the method + input values. + + + + + The final parameter must be a + DBusGMethodInvocation *. This is used + when sending the response message back to the client, by + calling dbus_g_method_return or + dbus_g_method_return_error. + + + + + + + + org.freedesktop.DBus.GLib.Const + + This attribute can only be applied to "out" + <arg> nodes, and specifies that the + parameter isn't being copied when returned. For example, this + turns a 's' argument from a char ** to a + const char **, and results in the argument not + being freed by DBus after the message is sent. + + + + + org.freedesktop.DBus.GLib.ReturnVal + + + This attribute can only be applied to "out" + <arg> nodes, and alters the expected + function signature. It currently can be set to two values: + "" or "error". The + argument marked with this attribute is not returned via a + pointer argument, but by the function's return value. If the + attribute's value is the empty string, the GError + * argument is also omitted so there is no standard way + to return an error value. This is very useful for interfacing + with existing code, as it is possible to match existing APIs. + If the attribute's value is "error", then the + final argument is a GError * as usual. + + + Some examples to demonstrate the usage. This introspection XML: + +<method name="Increment"> + <arg type="u" name="x" /> + <arg type="u" direction="out" /> +</method> + + Expects the following function declaration: + +gboolean +my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error); + + + + This introspection XML: + +<method name="IncrementRetval"> + <arg type="u" name="x" /> + <arg type="u" direction="out" > + <annotation name="org.freedesktop.DBus.GLib.ReturnVal" value=""/> + </arg> +</method> + + Expects the following function declaration: + +gint32 +my_object_increment_retval (MyObject *obj, gint32 x) + + + + This introspection XML: + +<method name="IncrementRetvalError"> + <arg type="u" name="x" /> + <arg type="u" direction="out" > + <annotation name="org.freedesktop.DBus.GLib.ReturnVal" value="error"/> + </arg> +</method> + + Expects the following function declaration: + +gint32 +my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error) + + + + + + + + + + + Python API + + The Python API, dbus-python, is now documented separately in + the dbus-python tutorial (also available in doc/tutorial.txt, + and doc/tutorial.html if built with python-docutils, in the dbus-python + source distribution). + + + + + Qt API: Using Remote Objects + + + The Qt bindings are not yet documented. + + + + + + Qt API: Implementing Objects + + The Qt bindings are not yet documented. + + +
diff --git a/doc/dcop-howto.txt b/doc/dcop-howto.txt new file mode 100644 index 00000000..dfd3bcf8 --- /dev/null +++ b/doc/dcop-howto.txt @@ -0,0 +1,559 @@ + DCOP: Desktop COmmunications Protocol + + Preston Brown + October 14, 1999 + + Revised and extended by Matthias Ettrich + Mar 29, 2000 + + Extended with DCOP Signals by Waldo Bastian + Feb 19, 2001 + + +Motivation and Background: +-------------------------- + +The motivation behind building a protocol like DCOP is simple. For +the past year, we have been attempting to enable interprocess +communication between KDE applications. KDE already has an extremely +simple IPC mechanism called KWMcom, which is (was!) used for communicating +between the panel and the window manager for instance. It is about as +simple as it gets, passing messages via X Atoms. For this reason it +is limited in the size and complexity of the data that can be passed +(X atoms must be small to remain efficient) and it also makes it so +that X is required. CORBA was thought to be a more effective IPC/RPC +solution. However, after a year of attempting to make heavy use of +CORBA in KDE, we have realized that it is a bit slow and memory +intensive for simple use. It also has no authentication available. + +What we really needed was an extremely simple protocol with basic +authorization, along the lines of MIT-MAGIC-COOKIE, as used by X. It +would not be able to do NEARLY what CORBA was able to do, but for the +simple tasks required it would be sufficient. Some examples of such +tasks might be an application sending a message to the panel saying, +"I have started, stop displaying the 'application starting' wait +state," or having a new application that starts query to see if any +other applications of the same name are running. If they are, simply +call a function on the remote application to create a new window, +rather than starting a new process. + +Implementation: +--------------- + +DCOP is a simple IPC/RPC mechanism built to operate over sockets. +Either unix domain sockets or tcp/ip sockets are supported. DCOP is +built on top of the Inter Client Exchange (ICE) protocol, which comes +standard as a part of X11R6 and later. It also depends on Qt, but +beyond that it does not require any other libraries. Because of this, +it is extremely lightweight, enabling it to be linked into all KDE +applications with low overhead. + +Model: +------ + +The model is simple. Each application using DCOP is a client. They +communicate to each other through a DCOP server, which functions like +a traffic director, dispatching messages/calls to the proper +destinations. All clients are peers of each other. + +Two types of actions are possible with DCOP: "send and forget" +messages, which do not block, and "calls," which block waiting for +some data to be returned. + +Any data that will be sent is serialized (marshalled, for you CORBA +types) using the built-in QDataStream operators available in all of +the Qt classes. This is fast and easy. In fact it's so little work +that you can easily write the marshalling code by hand. In addition, +there's a simple IDL-like compiler available (dcopidl and dcopidl2cpp) +that generates stubs and skeletons for you. Using the dcopidl compiler +has the additional benefit of type safety. + +This HOWTO describes the manual method first and covers the dcopidl +compiler later. + +Establishing the Connection: +---------------------------- + +KApplication has gained a method called "KApplication::dcopClient()" +which returns a pointer to a DCOPClient instance. The first time this +method is called, the client class will be created. DCOPClients have +unique identifiers attached to them which are based on what +KApplication::name() returns. In fact, if there is only a single +instance of the program running, the appId will be equal to +KApplication::name(). + +To actually enable DCOP communication to begin, you must use +DCOPClient::attach(). This will attempt to attach to the DCOP server. +If no server is found or there is any other type of error, attach() +will return false. KApplication will catch a dcop signal and display an +appropriate error message box in that case. + +After connecting with the server via DCOPClient::attach(), you need to +register this appId with the server so it knows about you. Otherwise, +you are communicating anonymously. Use the +DCOPClient::registerAs(const QCString &name) to do so. In the simple +case: + +/* + * returns the appId that is actually registered, which _may_ be + * different from what you passed + */ +appId = client->registerAs(kApp->name()); + +If you never retrieve the DCOPClient pointer from KApplication, the +object will not be created and thus there will be no memory overhead. + +You may also detach from the server by calling DCOPClient::detach(). +If you wish to attach again you will need to re-register as well. If +you only wish to change the ID under which you are registered, simply +call DCOPClient::registerAs() with the new name. + +KUniqueApplication automatically registers itself to DCOP. If you +are using KUniqueApplication you should not attach or register +yourself, this is already done. The appId is by definition +equal to kapp->name(). You can retrieve the registered DCOP client +by calling kapp->dcopClient(). + +Sending Data to a Remote Application: +------------------------------------- + +To actually communicate, you have one of two choices. You may either +call the "send" or the "call" method. Both methods require three +identification parameters: an application identifier, a remote object, +a remote function. Sending is asynchronous (i.e. it returns immediately) +and may or may not result in your own application being sent a message at +some point in the future. Then "send" requires one and "call" requires +two data parameters. + +The remote object must be specified as an object hierarchy. That is, +if the toplevel object is called "fooObject" and has the child +"barObject", you would reference this object as "fooObject/barObject". +Functions must be described by a full function signature. If the +remote function is called "doIt", and it takes an int, it would be +described as "doIt(int)". Please note that the return type is not +specified here, as it is not part of the function signature (or at +least the C++ understanding of a function signature). You will get +the return type of a function back as an extra parameter to +DCOPClient::call(). See the section on call() for more details. + +In order to actually get the data to the remote client, it must be +"serialized" via a QDataStream operating on a QByteArray. This is how +the data parameter is "built". A few examples will make clear how this +works. + +Say you want to call "doIt" as described above, and not block (or wait +for a response). You will not receive the return value of the remotely +called function, but you will not hang while the RPC is processed either. +The return value of send() indicates whether DCOP communication succeeded +or not. + +QByteArray data; +QDataStream arg(data, IO_WriteOnly); +arg << 5; +if (!client->send("someAppId", "fooObject/barObject", "doIt(int)", + data)) + qDebug("there was some error using DCOP."); + +OK, now let's say we wanted to get the data back from the remotely +called function. You have to execute a call() instead of a send(). +The returned value will then be available in the data parameter "reply". +The actual return value of call() is still whether or not DCOP +communication was successful. + +QByteArray data, replyData; +QCString replyType; +QDataStream arg(data, IO_WriteOnly); +arg << 5; +if (!client->call("someAppId", "fooObject/barObject", "doIt(int)", + data, replyType, replyData)) + qDebug("there was some error using DCOP."); +else { + QDataStream reply(replyData, IO_ReadOnly); + if (replyType == "QString") { + QString result; + reply >> result; + print("the result is: %s",result.latin1()); + } else + qDebug("doIt returned an unexpected type of reply!"); +} + +N.B.: You cannot call() a method belonging to an application which has +registered with an unique numeric id appended to its textual name (see +dcopclient.h for more info). In this case, DCOP would not know which +application it should connect with to call the method. This is not an issue +with send(), as you can broadcast to all applications that have registered +with appname- by using a wildcard (e.g. 'konsole-*'), which +will send your signal to all applications called 'konsole'. + +Receiving Data via DCOP: +------------------------ + +Currently the only real way to receive data from DCOP is to multiply +inherit from the normal class that you are inheriting (usually some +sort of QWidget subclass or QObject) as well as the DCOPObject class. +DCOPObject provides one very important method: DCOPObject::process(). +This is a pure virtual method that you must implement in order to +process DCOP messages that you receive. It takes a function +signature, QByteArray of parameters, and a reference to a QByteArray +for the reply data that you must fill in. + +Think of DCOPObject::process() as a sort of dispatch agent. In the +future, there will probably be a precompiler for your sources to write +this method for you. However, until that point you need to examine +the incoming function signature and take action accordingly. Here is +an example implementation. + +bool BarObject::process(const QCString &fun, const QByteArray &data, + QCString &replyType, QByteArray &replyData) +{ + if (fun == "doIt(int)") { + QDataStream arg(data, IO_ReadOnly); + int i; // parameter + arg >> i; + QString result = self->doIt (i); + QDataStream reply(replyData, IO_WriteOnly); + reply << result; + replyType = "QString"; + return true; + } else { + qDebug("unknown function call to BarObject::process()"); + return false; + } +} + +Receiving Calls and processing them: +------------------------------------ + +If your applications is able to process incoming function calls +right away the above code is all you need. When your application +needs to do more complex tasks you might want to do the processing +out of 'process' function call and send the result back later when +it becomes available. + +For this you can ask your DCOPClient for a transactionId. You can +then return from the 'process' function and when the result is +available finish the transaction. In the mean time your application +can receive incoming DCOP function calls from other clients. + +Such code could like this: + +bool BarObject::process(const QCString &fun, const QByteArray &data, + QCString &, QByteArray &) +{ + if (fun == "doIt(int)") { + QDataStream arg(data, IO_ReadOnly); + int i; // parameter + arg >> i; + QString result = self->doIt(i); + + DCOPClientTransaction *myTransaction; + myTransaction = kapp->dcopClient()->beginTransaction(); + + // start processing... + // Calls slotProcessingDone when finished. + startProcessing( myTransaction, i); + + return true; + } else { + qDebug("unknown function call to BarObject::process()"); + return false; + } +} + +slotProcessingDone(DCOPClientTransaction *myTransaction, const QString &result) +{ + QCString replyType = "QString"; + QByteArray replyData; + QDataStream reply(replyData, IO_WriteOnly); + reply << result; + kapp->dcopClient()->endTransaction( myTransaction, replyType, replyData ); +} + +DCOP Signals +------------ + +Sometimes a component wants to send notifications via DCOP to other +components but does not know which components will be interested in these +notifications. One could use a broadcast in such a case but this is a very +crude method. For a more sophisticated method DCOP signals have been invented. + +DCOP signals are very similair to Qt signals, there are some differences +though. A DCOP signal can be connected to a DCOP function. Whenever the DCOP +signal gets emitted, the DCOP functions to which the signal is connected are +being called. DCOP signals are, just like Qt signals, one way. They do not +provide a return value. + +A DCOP signal originates from a DCOP Object/DCOP Client combination (sender). +It can be connected to a function of another DCOP Object/DCOP Client +combination (receiver). + +There are two major differences between connections of Qt signals and +connections of DCOP signals. In DCOP, unlike Qt, a signal connections can +have an anonymous sender and, unlike Qt, a DCOP signal connection can be +non-volatile. + +With DCOP one can connect a signal without specifying the sending DCOP Object +or DCOP Client. In that case signals from any DCOP Object and/or DCOP Client +will be delivered. This allows the specification of certain events without +tying oneself to a certain object that implementes the events. + +Another DCOP feature are so called non-volatile connections. With Qt signal +connections, the connection gets deleted when either sender or receiver of +the signal gets deleted. A volatile DCOP signal connection will behave the +same. However, a non-volatile DCOP signal connection will not get deleted +when the sending object gets deleted. Once a new object gets created with +the same name as the original sending object, the connection will be restored. +There is no difference between the two when the receiving object gets deleted, +in that case the signal connection will always be deleted. + +A receiver can create a non-volatile connection while the sender doesn't (yet) +exist. An anonymous DCOP connection should always be non-volatile. + +The following example shows how KLauncher emits a signal whenever it notices +that an application that was started via KLauncher terminates. + + QByteArray params; + QDataStream stream(params, IO_WriteOnly); + stream << pid; + kapp->dcopClient()->emitDCOPSignal("clientDied(pid_t)", params); + +The task manager of the KDE panel connects to this signal. It uses an +anonymous connection (it doesn't require that the signal is being emitted +by KLauncher) that is non-volatile: + + connectDCOPSignal(0, 0, "clientDied(pid_t)", "clientDied(pid_t)", false); + +It connects the clientDied(pid_t) signal to its own clientDied(pid_t) DCOP +function. In this case the signal and the function to call have the same name. +This isn't needed as long as the arguments of both signal and receiving function +match. The receiving function may ignore one or more of the trailing arguments +of the signal. E.g. it is allowed to connect the clientDied(pid_t) signal to +a clientDied(void) DCOP function. + +Using the dcopidl compiler +--------------------- + +dcopidl makes setting up a DCOP server easy. Instead of having to implement +the process() method and unmarshalling (retrieving from QByteArray) parameters +manually, you can let dcopidl create the necessary code on your behalf. + +This also allows you to describe the interface for your class in a +single, separate header file. + +Writing an IDL file is very similar to writing a normal C++ header. An +exception is the keyword 'ASYNC'. It indicates that a call to this +function shall be processed asynchronously. For the C++ compiler, it +expands to 'void'. + +Example: + +#ifndef MY_INTERFACE_H +#define MY_INTERFACE_H + +#include + +class MyInterface : virtual public DCOPObject +{ + K_DCOP + + k_dcop: + + virtual ASYNC myAsynchronousMethod(QString someParameter) = 0; + virtual QRect mySynchronousMethod() = 0; +}; + +#endif + +As you can see, you're essentially declaring an abstract base class, which +virtually inherits from DCOPObject. + +If you're using the standard KDE build scripts, then you can simply +add this file (which you would call MyInterface.h) to your sources +directory. Then you edit your Makefile.am, adding 'MyInterface.skel' +to your SOURCES list and MyInterface.h to include_HEADERS. + +The build scripts will use dcopidl to parse MyInterface.h, converting +it to an XML description in MyInterface.kidl. Next, a file called +MyInterface_skel.cpp will automatically be created, compiled and +linked with your binary. + +The next thing you have to do is to choose which of your classes will +implement the interface described in MyInterface.h. Alter the inheritance +of this class such that it virtually inherits from MyInterface. Then +add declarations to your class interface similar to those on MyInterface.h, +but virtual, not pure virtual. + +Example: + +class MyClass: public QObject, virtual public MyInterface +{ + Q_OBJECT + + public: + MyClass(); + ~MyClass(); + + ASYNC myAsynchronousMethod(QString someParameter); + QRect mySynchronousMethod(); +}; + +Note: (Qt issue) Remember that if you are inheriting from QObject, you must +place it first in the list of inherited classes. + +In the implementation of your class' ctor, you must explicitly initialize +those classes from which you are inheriting from. This is, of course, good +practise, but it is essential here as you need to tell DCOPObject the name of +the interface which your are implementing. + +Example: + +MyClass::MyClass() + : QObject(), + DCOPObject("MyInterface") +{ + // whatever... +} + +Now you can simply implement the methods you have declared in your interface, +exactly the same as you would normally. + +Example: + +void MyClass::myAsynchronousMethod(QString someParameter) +{ + qDebug("myAsyncMethod called with param `" + someParameter + "'"); +} + + +It is not necessary (though very clean) to define an interface as an +abstract class of its own, like we did in the example above. We could +just as well have defined a k_dcop section directly within MyClass: + +class MyClass: public QObject, virtual public DCOPObject +{ + Q_OBJECT + K_DCOP + + public: + MyClass(); + ~MyClass(); + + k_dcop: + ASYNC myAsynchronousMethod(QString someParameter); + QRect mySynchronousMethod(); +}; + +In addition to skeletons, dcopidl2cpp also generate stubs. Those make +it easy to call a DCOP interface without doing the marshalling +manually. To use a stub, add MyInterface.stub to the SOURCES list of +your Makefile.am. The stub class will then be called MyInterface_stub. + +Conclusion: +----------- + +Hopefully this document will get you well on your way into the world +of inter-process communication with KDE! Please direct all comments +and/or suggestions to Preston Brown and Matthias +Ettrich . + + +Inter-user communication +------------------------ + +Sometimes it might be interesting to use DCOP between processes +belonging to different users, e.g. a frontend process running +with the user's id, and a backend process running as root. + +To do this, two steps have to be taken: + +a) both processes need to talk to the same DCOP server +b) the authentication must be ensured + +For the first step, you simply pass the server address (as +found in .DCOPserver) to the second process. For the authentication, +you can use the ICEAUTHORITY environment variable to tell the +second process where to find the authentication information. +(Note that this implies that the second process is able to +read the authentication file, so it will probably only work +if the second process runs as root. If it should run as another +user, a similar approach to what kdesu does with xauth must +be taken. In fact, it would be a very good idea to add DCOP +support to kdesu!) + +For example + +ICEAUTHORITY=~user/.ICEauthority kdesu root -c kcmroot -dcopserver `cat ~user/.DCOPserver` + +will, after kdesu got the root password, execute kcmroot as root, talking +to the user's dcop server. + + +NOTE: DCOP communication is not encrypted, so please do not +pass important information around this way. + + +Performance Tests: +------------------ +A few back-of-the-napkin tests folks: + +Code: + +#include + +int main(int argc, char **argv) +{ + KApplication *app; + + app = new KApplication(argc, argv, "testit"); + return app->exec(); +} + +Compiled with: + +g++ -O2 -o testit testit.cpp -I$QTDIR/include -L$QTDIR/lib -lkdecore + +on Linux yields the following memory use statistics: + +VmSize: 8076 kB +VmLck: 0 kB +VmRSS: 4532 kB +VmData: 208 kB +VmStk: 20 kB +VmExe: 4 kB +VmLib: 6588 kB + +If I create the KApplication's DCOPClient, and call attach() and +registerAs(), it changes to this: + +VmSize: 8080 kB +VmLck: 0 kB +VmRSS: 4624 kB +VmData: 208 kB +VmStk: 20 kB +VmExe: 4 kB +VmLib: 6588 kB + +Basically it appears that using DCOP causes 100k more memory to be +resident, but no more data or stack. So this will be shared between all +processes, right? 100k to enable DCOP in all apps doesn't seem bad at +all. :) + +OK now for some timings. Just creating a KApplication and then exiting +(i.e. removing the call to KApplication::exec) takes this much time: + +0.28user 0.02system 0:00.32elapsed 92%CPU (0avgtext+0avgdata 0maxresident)k +0inputs+0outputs (1084major+62minor)pagefaults 0swaps + +I.e. about 1/3 of a second on my PII-233. Now, if we create our DCOP +object and attach to the server, it takes this long: + +0.27user 0.03system 0:00.34elapsed 87%CPU (0avgtext+0avgdata 0maxresident)k +0inputs+0outputs (1107major+65minor)pagefaults 0swaps + +I.e. about 1/3 of a second. Basically DCOPClient creation and attaching +gets lost in the statistical variation ("noise"). I was getting times +between .32 and .48 over several runs for both of the example programs, so +obviously system load is more relevant than the extra two calls to +DCOPClient::attach and DCOPClient::registerAs, as well as the actual +DCOPClient constructor time. + diff --git a/doc/diagram.png b/doc/diagram.png new file mode 100644 index 00000000..5cb84a99 Binary files /dev/null and b/doc/diagram.png differ diff --git a/doc/diagram.svg b/doc/diagram.svg new file mode 100644 index 00000000..193c5679 --- /dev/null +++ b/doc/diagram.svg @@ -0,0 +1,590 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + Application Process 1 + + DBusConnectionInstance + + C/C++/Python/etc.Object Instance + + Locate Objectvia Object Path + + Bindings Marshalto Method Call + + + Marshal MethodCall to Message + + + Bindings ProxyObject Instance + + Application Code + + IncomingCall + OutgoingCall + + + Bus Daemon Process + + Application Process 2 + Same Stuff as inProcess 1 + (Object Instance Has1 or More Interfaces) + + Socket(Bidirectional Message Stream) + + Socket(Bidirectional Message Stream) + + DBusConnectionInstance + + DBusConnectionInstance + + DBusConnectionInstance + + + Message Dispatcher + + if (message is signal) broadcastelse find destination named by message + + + + Destination Table + Connection 1Connection 2"The Session Manager""The Window Manager""The Screensaver""The Text Editor""The Hardware Directory""The Address Book""The Dictionary" + + + + + + diff --git a/doc/file-boilerplate.c b/doc/file-boilerplate.c new file mode 100644 index 00000000..bc365f80 --- /dev/null +++ b/doc/file-boilerplate.c @@ -0,0 +1,27 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* FILENAME BRIEF FILE DESCRIPTION + * + * Copyright (C) YEAR COPYRIGHT HOLDER + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_FOO_H +#define DBUS_FOO_H + +#endif /* DBUS_FOO_H */ diff --git a/doc/introspect.dtd b/doc/introspect.dtd new file mode 100644 index 00000000..ba263d32 --- /dev/null +++ b/doc/introspect.dtd @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/introspect.xsl b/doc/introspect.xsl new file mode 100644 index 00000000..2a344741 --- /dev/null +++ b/doc/introspect.xsl @@ -0,0 +1,106 @@ + + + + + + + + + + + + + DBUS Introspection data + + + + +
+

+ interface + +

+ +
    + + + + +
  • + + + + +
      + + +
    • + + + + + + + out + + + in + + + + + + + + +
    • +
      +
    + +
  • +
    + +
+
+
+ + +
+ + + +
  • + annotation + = + +
  • +
    + +
    diff --git a/doc/system-activation.txt b/doc/system-activation.txt new file mode 100644 index 00000000..dd195f75 --- /dev/null +++ b/doc/system-activation.txt @@ -0,0 +1,80 @@ +D-BUS System Activation + +Introduction: + +The dbus-daemon runs as the dbus user, and is therefore unprivileged. +Earlier attempts [1] by David Zeuthen at launching system scripts using a +custom DBUS protocol were reviewed, but deemed too difficult to audit, and +also due to a multi-threaded design, too difficult to test. +In the next few paragraphs I will outline a simpler setuid approach for +launching daemons as a configured user. + +Scope: + +Launching programs using dbus has been a topic of interest for many months. +This would allow simple systems to only start services that are needed, +and that are automatically started only when first requested. +This removes the need for an init system, and means that we can trivially +startup services in parallel. +This has immediate pressing need for OLPC, with a longer term evaluation for +perhaps Fedora and RHEL. + +Details: + +Setuid applications have to used only when absolutely necessary. +In this implementation I have an single executable, +dbus-daemon-launch-helper, with the ownership root:dbus. +This has the permissions 4750, i.e. u+rwx g+rx +setuid. +It is located in /usr/libexec/ and thus is not designed to be invoked by a +user directly. + +The helper must not be passed input that can be changed maliciously, and +therefore passing a random path with user id is totally out of the question. +In this implementation a similar idea as discussed with Davids' patch was +taken, that to pass a single name argument to the helper. +The service filename of "org.me.test.service" is then searched for in +/usr/share/dbus-1/system-services or other specified directories. + +If applications want to be activated on the system _and_ session busses, then +service files should be installed in both directories. + +A typical service file would look like: + +[D-BUS Service] +Name=org.me.test +Exec=/usr/sbin/dbus-test-server.py +User=ftp + +This gives the user to switch to, and also the path of the executable. +The service name must match that specified in the /etc/dbus-1/system.d conf file. + +Precautions taken: + +* Only the bus name is passed to the helper, and this is validated +* We are super paranoid about the user that called us, and what permissions we have. +* We clear all environment variables except for DBUS_VERBOSE which is used for debugging +* Anything out of the ordinary causes the helper to abort. + +Launching services: + +Trivial methods on services can be called directly and the launch helper will +start the service and execute the method on the service. The lauching of the +service is completely transparent to the caller, e.g.: + +dbus-send --system --print-reply \ + --dest=org.freedesktop.Hal \ + /org/freedesktop/Hal/Manager \ + org.freedesktop.Hal.Manager.DeviceExists \ + string:/org/freedesktop/Hal/devices/computer + +If you wish to activate the service without calling a well known method, +the standard dbus method StartServiceByName can be used: + +dbus-send --system --print-reply \ + --dest=org.freedesktop.DBus \ + /org/freedesktop/DBus \ + org.freedesktop.DBus.StartServiceByName \ + string:org.freedesktop.Hal uint32:0 + +[1] http://lists.freedesktop.org/archives/dbus/2006-October/006096.html + diff --git a/install-sh b/install-sh new file mode 100755 index 00000000..6781b987 --- /dev/null +++ b/install-sh @@ -0,0 +1,520 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2009-04-28.21; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# 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. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # 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 $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/ltmain.sh b/ltmain.sh new file mode 100755 index 00000000..a72f2fd7 --- /dev/null +++ b/ltmain.sh @@ -0,0 +1,8406 @@ +# Generated from ltmain.m4sh. + +# ltmain.sh (GNU libtool) 2.2.6b +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that 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 GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print informational messages (default) +# --version print version information +# -h, --help print short or long help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.2.6b +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION=2.2.6b +TIMESTAMP="" +package_revision=1.3017 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# NLS nuisances: We save the old values to restore during execute mode. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done + +$lt_unset CDPATH + + + + + +: ${CP="cp -f"} +: ${ECHO="echo"} +: ${EGREP="/bin/grep -E"} +: ${FGREP="/bin/grep -F"} +: ${GREP="/bin/grep"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SED="/bin/sed"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` +} + +# Generated shell functions inserted here. + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +# In the unlikely event $progname began with a '-', it would play havoc with +# func_echo (imagine progname=-n), so we prepend ./ in that case: +func_dirname_and_basename "$progpath" +progname=$func_basename_result +case $progname in + -*) progname=./$progname ;; +esac + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=: + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname${mode+: }$mode: $*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` + done + my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "X$my_tmpdir" | $Xsed +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "X$1" | $Xsed \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + + + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $SED -n '/^# Usage:/,/# -h/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + $ECHO + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help +# Echo long help message to standard output and exit. +func_help () +{ + $SED -n '/^# Usage:/,/# Report bugs to/ { + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ + p + }' < "$progpath" + exit $? +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + func_error "missing argument for $1" + exit_cmd=exit +} + +exit_cmd=: + + + + + +# Check that we have a working $ECHO. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then + # Yippee, $ECHO works! + : +else + # Restart under the correct shell, and then maybe $ECHO will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# Parse options once, thoroughly. This comes as soon as possible in +# the script to make things like `libtool --version' happen quickly. +{ + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + esac + + # Parse non-mode specific arguments: + while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --config) func_config ;; + + --debug) preserve_args="$preserve_args $opt" + func_echo "enabling shell trace mode" + opt_debug='set -x' + $opt_debug + ;; + + -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break + execute_dlfiles="$execute_dlfiles $1" + shift + ;; + + --dry-run | -n) opt_dry_run=: ;; + --features) func_features ;; + --finish) mode="finish" ;; + + --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break + case $1 in + # Valid mode arguments: + clean) ;; + compile) ;; + execute) ;; + finish) ;; + install) ;; + link) ;; + relink) ;; + uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; + esac + + mode="$1" + shift + ;; + + --preserve-dup-deps) + opt_duplicate_deps=: ;; + + --quiet|--silent) preserve_args="$preserve_args $opt" + opt_silent=: + ;; + + --verbose| -v) preserve_args="$preserve_args $opt" + opt_silent=false + ;; + + --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break + preserve_args="$preserve_args $opt $1" + func_enable_tag "$1" # tagname is set here + shift + ;; + + # Separate optargs to long options: + -dlopen=*|--mode=*|--tag=*) + func_opt_split "$opt" + set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} + shift + ;; + + -\?|-h) func_usage ;; + --help) opt_help=: ;; + --version) func_version ;; + + -*) func_fatal_help "unrecognized option \`$opt'" ;; + + *) nonopt="$opt" + break + ;; + esac + done + + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_duplicate_deps + ;; + esac + + # Having warned about all mis-specified options, bail out if + # anything was wrong. + $exit_cmd $EXIT_FAILURE +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +## ----------- ## +## Main. ## +## ----------- ## + +$opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + test -z "$mode" && func_fatal_error "error: you must specify a MODE." + + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$mode' for more information." +} + + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_ltwrapper_scriptname_result="" + if func_ltwrapper_executable_p "$1"; then + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" + fi +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + case "$@ " in + " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T <?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + removelist="$removelist $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + removelist="$removelist $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + command="$command -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { +test "$mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$mode'" + ;; + esac + + $ECHO + $ECHO "Try \`$progname --help' for more information about other modes." + + exit $? +} + + # Now that we've collected a possible --mode arg, show help if necessary + $opt_help && func_mode_help + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_quote_for_eval "$file" + args="$args $func_quote_for_eval_result" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + $ECHO "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + $ECHO "X----------------------------------------------------------------------" | $Xsed + $ECHO "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + $ECHO + $ECHO "If you ever happen to want to link against installed libraries" + $ECHO "in a given directory, LIBDIR, you must either use libtool, and" + $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'" + $ECHO "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable" + $ECHO " during execution" + fi + if test -n "$runpath_var"; then + $ECHO " - add LIBDIR to the \`$runpath_var' environment variable" + $ECHO " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $ECHO + + $ECHO "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual" + $ECHO "pages." + ;; + *) + $ECHO "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + $ECHO "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS +} + +test "$mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $ECHO "X$nonopt" | $GREP shtool >/dev/null; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + install_prog="$install_prog$func_quote_for_eval_result" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + install_prog="$install_prog $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_verbose "extracting global C symbols from \`$progfile'" + $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + $ECHO >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +" + case $host in + *cygwin* | *mingw* | *cegcc* ) + $ECHO >> "$output_objdir/$my_dlsyms" "\ +/* DATA imports from DLLs on WIN32 con't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs. */" + lt_dlsym_const= ;; + *osf5*) + echo >> "$output_objdir/$my_dlsyms" "\ +/* This system does not cope well with relocations in const data */" + lt_dlsym_const= ;; + *) + lt_dlsym_const=const ;; + esac + + $ECHO >> "$output_objdir/$my_dlsyms" "\ +extern $lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +$lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + $ECHO >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) symtab_cflags="$symtab_cflags $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?' + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + + +# func_emit_wrapper_part1 [arg=no] +# +# Emit the first part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part1 () +{ + func_emit_wrapper_part1_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part1_arg1=$1 + fi + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + ECHO=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$ECHO works! + : + else + # Restart under the correct shell, and then maybe \$ECHO will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $ECHO "\ + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done +" +} +# end: func_emit_wrapper_part1 + +# func_emit_wrapper_part2 [arg=no] +# +# Emit the second part of a libtool wrapper script on stdout. +# For more information, see the description associated with +# func_emit_wrapper(), below. +func_emit_wrapper_part2 () +{ + func_emit_wrapper_part2_arg1=no + if test -n "$1" ; then + func_emit_wrapper_part2_arg1=$1 + fi + + $ECHO "\ + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} +# end: func_emit_wrapper_part2 + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=no + if test -n "$1" ; then + func_emit_wrapper_arg1=$1 + fi + + # split this up so that func_emit_cwrapperexe_src + # can call each part independently. + func_emit_wrapper_part1 "${func_emit_wrapper_arg1}" + func_emit_wrapper_part2 "${func_emit_wrapper_arg1}" +} + + +# func_to_host_path arg +# +# Convert paths to host format when used with build tools. +# Intended for use with "native" mingw (where libtool itself +# is running under the msys shell), or in the following cross- +# build environments: +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# where wine is equipped with the `winepath' executable. +# In the native mingw case, the (msys) shell automatically +# converts paths for any non-msys applications it launches, +# but that facility isn't available from inside the cwrapper. +# Similar accommodations are necessary for $host mingw and +# $build cygwin. Calling this function does no harm for other +# $host/$build combinations not listed above. +# +# ARG is the path (on $build) that should be converted to +# the proper representation for $host. The result is stored +# in $func_to_host_path_result. +func_to_host_path () +{ + func_to_host_path_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + case $build in + *mingw* ) # actually, msys + # awkward: cmd appends spaces to result + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_path_tmp1=`( cmd //c echo "$1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_path_tmp1=`cygpath -w "$1"` + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # Unfortunately, winepath does not exit with a non-zero + # error code, so we are forced to check the contents of + # stdout. On the other hand, if the command is not + # found, the shell will set an exit code of 127 and print + # *an error message* to stdout. So we must check for both + # error code of zero AND non-empty stdout, which explains + # the odd construction: + func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` + if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then + func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ + $SED -e "$lt_sed_naive_backslashify"` + else + # Allow warning below. + func_to_host_path_result="" + fi + ;; + esac + if test -z "$func_to_host_path_result" ; then + func_error "Could not determine host path corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_path_result="$1" + fi + ;; + esac + fi +} +# end: func_to_host_path + +# func_to_host_pathlist arg +# +# Convert pathlists to host format when used with build tools. +# See func_to_host_path(), above. This function supports the +# following $build/$host combinations (but does no harm for +# combinations not listed here): +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# +# Path separators are also converted from $build format to +# $host format. If ARG begins or ends with a path separator +# character, it is preserved (but converted to $host format) +# on output. +# +# ARG is a pathlist (on $build) that should be converted to +# the proper representation on $host. The result is stored +# in $func_to_host_pathlist_result. +func_to_host_pathlist () +{ + func_to_host_pathlist_result="$1" + if test -n "$1" ; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_to_host_pathlist_tmp2="$1" + # Once set for this call, this variable should not be + # reassigned. It is used in tha fallback case. + func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e 's|^:*||' -e 's|:*$||'` + case $build in + *mingw* ) # Actually, msys. + # Awkward: cmd appends spaces to result. + lt_sed_strip_trailing_spaces="s/[ ]*\$//" + func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"` + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # unfortunately, winepath doesn't convert pathlists + func_to_host_pathlist_result="" + func_to_host_pathlist_oldIFS=$IFS + IFS=: + for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do + IFS=$func_to_host_pathlist_oldIFS + if test -n "$func_to_host_pathlist_f" ; then + func_to_host_path "$func_to_host_pathlist_f" + if test -n "$func_to_host_path_result" ; then + if test -z "$func_to_host_pathlist_result" ; then + func_to_host_pathlist_result="$func_to_host_path_result" + else + func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result" + fi + fi + fi + IFS=: + done + IFS=$func_to_host_pathlist_oldIFS + ;; + esac + if test -z "$func_to_host_pathlist_result" ; then + func_error "Could not determine the host path(s) corresponding to" + func_error " '$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This may break if $1 contains DOS-style drive + # specifications. The fix is not to complicate the expression + # below, but for the user to provide a working wine installation + # with winepath so that path translation in the cross-to-mingw + # case works properly. + lt_replace_pathsep_nix_to_dos="s|:|;|g" + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_replace_pathsep_nix_to_dos"` + fi + # Now, add the leading and trailing path separators back + case "$1" in + :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" + ;; + esac + case "$1" in + *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;" + ;; + esac + ;; + esac + fi +} +# end: func_to_host_pathlist + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +# define setmode _setmode +#else +# include +# include +# ifdef __CYGWIN__ +# include +# define HAVE_SETENV +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +#ifdef _MSC_VER +# define S_IXUSR _S_IEXEC +# define stat _stat +# ifndef _INTPTR_T_DEFINED +# define intptr_t int +# endif +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifdef __CYGWIN__ +# define FOPEN_WB "wb" +#endif + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#undef LTWRAPPER_DEBUGPRINTF +#if defined DEBUGWRAPPER +# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args +static void +ltwrapper_debugprintf (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); +} +#else +# define LTWRAPPER_DEBUGPRINTF(args) +#endif + +const char *program_name = NULL; + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_fatal (const char *message, ...); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_opt_process_env_set (const char *arg); +void lt_opt_process_env_prepend (const char *arg); +void lt_opt_process_env_append (const char *arg); +int lt_split_name_value (const char *arg, char** name, char** value); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); + +static const char *script_text_part1 = +EOF + + func_emit_wrapper_part1 yes | + $SED -e 's/\([\\"]\)/\\\1/g' \ + -e 's/^/ "/' -e 's/$/\\n"/' + echo ";" + cat <"))); + for (i = 0; i < newargc; i++) + { + LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : ""))); + } + +EOF + + case $host_os in + mingw*) + cat <<"EOF" + /* execv doesn't actually work on mingw as expected on unix */ + rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); + if (rval == -1) + { + /* failed to start process */ + LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); + return 127; + } + return rval; +EOF + ;; + *) + cat <<"EOF" + execv (lt_argv_zero, newargz); + return rval; /* =127, but avoids unused variable warning */ +EOF + ;; + esac + + cat <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void *p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), + string) : NULL; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char) name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable (const char *path) +{ + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", + wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", + tmp_pathspec)); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + char *errstr = strerror (errno); + lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal ("Could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} + +void +lt_setenv (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", + (name ? name : ""), + (value ? value : ""))); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +int +lt_split_name_value (const char *arg, char** name, char** value) +{ + const char *p; + int len; + if (!arg || !*arg) + return 1; + + p = strchr (arg, (int)'='); + + if (!p) + return 1; + + *value = xstrdup (++p); + + len = strlen (arg) - strlen (*value); + *name = XMALLOC (char, len); + strncpy (*name, arg, len-1); + (*name)[len - 1] = '\0'; + + return 0; +} + +void +lt_opt_process_env_set (const char *arg) +{ + char *name = NULL; + char *value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg); + } + + lt_setenv (name, value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_prepend (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_opt_process_env_append (const char *arg) +{ + char *name = NULL; + char *value = NULL; + char *new_value = NULL; + + if (lt_split_name_value (arg, &name, &value) != 0) + { + XFREE (name); + XFREE (value); + lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg); + } + + new_value = lt_extend_str (getenv (name), value, 1); + lt_setenv (name, new_value); + XFREE (new_value); + XFREE (name); + XFREE (value); +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + (name ? name : ""), + (value ? value : ""))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + (name ? name : ""), + (value ? value : ""))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + + +EOF +} +# end: func_emit_cwrapperexe_src + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) deplibs="$deplibs $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + weak_libs="$weak_libs $arg" + prev= + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname '-L' '' "$arg" + dir=$func_stripname_result + if test -z "$dir"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" + linker_flags="$linker_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -F/path gives path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_duplicate_deps ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + case $lib in + *.la) func_source "$lib" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"` + case " $weak_libs " in + *" $deplib_base "*) ;; + *) deplibs="$deplibs $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + dir=$func_stripname_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $ECHO + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because the file extensions .$libext of this argument makes me believe" + $ECHO "*** that it is just a static archive that I should not use here." + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) temp_rpath="$temp_rpath$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + notinst_deplibs="$notinst_deplibs $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + $ECHO + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $ECHO + $ECHO "*** And there doesn't seem to be a static archive available" + $ECHO "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $ECHO + $ECHO "*** Warning: This system can not link to static lib archive $lib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $ECHO "*** But as you try to build a module library, libtool will still create " + $ECHO "*** a static module, that should work as long as the dlopening application" + $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_dirname "$deplib" "" "." + dir="$func_dirname_result" + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + $ECHO + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + libobjs="$libobjs $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"` + # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"` + # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $ECHO + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + $ECHO "*** I have the capability to make that library automatically link in when" + $ECHO "*** you link to this library. But I can only do this if you have a" + $ECHO "*** shared version of the library, which you do not appear to have" + $ECHO "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \ + -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"` + done + fi + if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' | + $GREP . >/dev/null; then + $ECHO + if test "X$deplibs_check_method" = "Xnone"; then + $ECHO "*** Warning: inter-library dependencies are not supported in this platform." + else + $ECHO "*** Warning: inter-library dependencies are not known to be supported." + fi + $ECHO "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $ECHO + $ECHO "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + $ECHO "*** a static module, that should work as long as the dlopening" + $ECHO "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $ECHO + $ECHO "*** However, this would only work if libtool was able to extract symbol" + $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" + $ECHO "*** not find such a program. So, this module is probably useless." + $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $ECHO "*** The inter-library dependencies that have been dropped here will be" + $ECHO "*** automatically added whenever a program is linked with this library" + $ECHO "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $ECHO + $ECHO "*** Since this library must not contain undefined symbols," + $ECHO "*** because either the platform does not support them or" + $ECHO "*** it was explicitly requested with -no-undefined," + $ECHO "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + delfiles="$delfiles $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + func_len " $cmd" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$ECHO "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + $ECHO 'INPUT (' > $output + for obj in $save_libobjs + do + $ECHO "$obj" >> $output + done + $ECHO ')' >> $output + delfiles="$delfiles $output" + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + $ECHO "$obj" >> $output + done + delfiles="$delfiles $output" + output=$firstobj\"$file_list_spec$output\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + delfiles="$delfiles $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *cegcc) + # Disable wrappers for cegcc, we are cross compiling anyway. + wrappers_required=no + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $ECHO for shipping. + if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + oldobjs="$oldobjs $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $ECHO "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlfiles="$newdlfiles $libdir/$name" + ;; + *) newdlfiles="$newdlfiles $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlprefiles="$newdlprefiles $libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$mode" = link || test "$mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) RM="$RM $arg"; rmforce=yes ;; + -*) RM="$RM $arg" ;; + *) files="$files $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + rmfiles="$rmfiles $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$mode" = uninstall || test "$mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/missing b/missing new file mode 100755 index 00000000..28055d2a --- /dev/null +++ b/missing @@ -0,0 +1,376 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2009-04-28.21; # UTC + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, +# 2008, 2009 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, 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. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and +\`g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# normalize program name to check for. +program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). This is about non-GNU programs, so use $1 not +# $program. +case $1 in + lex*|yacc*) + # Not GNU programs, they don't have --version. + ;; + + tar*) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $program in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te*) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison*|yacc*) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex*|flex*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG="\${$#}" + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit $? + fi + ;; + + makeinfo*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar*) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case $firstarg in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case $firstarg in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 00000000..c759906a --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,158 @@ +## the "name-test" subdir in fact contains a bunch of tests now that need a temporary bus +## to be running to do stuff with. The directory should be renamed. +## We want to build the current directory first to pick up the testutils lib +SUBDIRS= . name-test +DIST_SUBDIRS=name-test + +INCLUDES=-I$(top_srcdir) $(DBUS_TEST_CFLAGS) + +libdbus_testutils_la_SOURCES = test-utils.h test-utils.c + +noinst_LTLIBRARIES = libdbus-testutils.la + +if DBUS_BUILD_TESTS +## break-loader removed for now +## most of these binaries are used in tests but are not themselves tests +TEST_BINARIES=test-service test-names test-shell-service shell-test spawn-test test-segfault test-exit test-sleep-forever + +## these are the things to run in make check (i.e. they are actual tests) +## (binaries in here must also be in TEST_BINARIES) +TESTS=shell-test +else +TEST_BINARIES= +TESTS= +endif + +if DBUS_GCOV_ENABLED +GCOV_BINARIES=decode-gcov +else +GCOV_BINARIES= +endif + +noinst_PROGRAMS= $(TEST_BINARIES) $(GCOV_BINARIES) + +test_service_SOURCES= \ + test-service.c + +test_names_SOURCES= \ + test-names.c + +##break_loader_SOURCES= \ +## break-loader.c + +test_shell_service_SOURCES = \ + test-shell-service.c + +shell_test_SOURCES= \ + shell-test.c + +spawn_test_SOURCES= \ + spawn-test.c + +test_exit_SOURCES = \ + test-exit.c + +test_segfault_SOURCES = \ + test-segfault.c + +test_sleep_forever_SOURCES = \ + test-sleep-forever.c + +decode_gcov_SOURCES= \ + decode-gcov.c + +TEST_LIBS=$(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS) + +test_service_LDADD=$(TEST_LIBS) libdbus-testutils.la +test_service_LDFLAGS=@R_DYNAMIC_LDFLAG@ +test_names_LDADD=$(TEST_LIBS) libdbus-testutils.la +test_names_LDFLAGS=@R_DYNAMIC_LDFLAG@ +## break_loader_LDADD= $(TEST_LIBS) +## break_loader_LDFLAGS=@R_DYNAMIC_LDFLAG@ +test_shell_service_LDADD=$(TEST_LIBS) libdbus-testutils.la +test_shell_service_LDFLAGS=@R_DYNAMIC_LDFLAG@ +shell_test_LDADD=$(TEST_LIBS) libdbus-testutils.la +shell_test_LDFLAGS=@R_DYNAMIC_LDFLAG@ +spawn_test_LDADD=$(TEST_LIBS) +spawn_test_LDFLAGS=@R_DYNAMIC_LDFLAG@ +decode_gcov_LDADD=$(TEST_LIBS) +decode_gcov_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +EXTRA_DIST= + +## keep these in creation order, i.e. uppermost dirs first +TESTDIRS= \ + data \ + data/valid-messages \ + data/invalid-messages \ + data/incomplete-messages \ + data/auth \ + data/sha-1 \ + data/valid-config-files \ + data/valid-config-files-system \ + data/valid-config-files/basic.d \ + data/valid-config-files/session.d \ + data/valid-config-files/system.d \ + data/valid-service-files \ + data/valid-service-files-system \ + data/invalid-service-files-system \ + data/invalid-config-files \ + data/invalid-config-files-system \ + data/equiv-config-files \ + data/equiv-config-files/basic \ + data/equiv-config-files/basic/basic.d \ + data/equiv-config-files/entities \ + data/equiv-config-files/entities/basic.d + + +FIND_TESTS=find . -name "*.message" -o -name "*.message-raw" -o -name "*.auth-script" -o -name "*.sha1" -o -name "*.txt" -o -name "*.conf" -o -name "*.service" + +dist-hook: + for D in $(TESTDIRS); do \ + test -d $(distdir)/$$D || mkdir $(distdir)/$$D || exit 1 ; \ + done ; \ + FILES=`(cd $(srcdir) && $(FIND_TESTS) -o -name "*.in" -a -not -name Makefile.in | grep -Ev "(.svn|CVS)" )` ; \ + for F in $$FILES; do \ + echo '-- Disting file '$$F ; \ + cp -f $(srcdir)/$$F $(distdir)/$$F || exit 1 ; \ + done + +## copy tests to builddir so that generated tests and static tests +## are all in one place. +all-local: + for D in $(TESTDIRS); do \ + test -d $(top_builddir)/test/$$D || mkdir $(top_builddir)/test/$$D || exit 1 ; \ + done ; \ + if ! (test $(srcdir) = . || test $(srcdir) -ef .) ; then \ + FILES=`(cd $(srcdir) && $(FIND_TESTS) | grep -Ev "(.svn|CVS)" )` ; \ + for F in $$FILES; do \ + SRC=$(srcdir)/$$F ; \ + DEST=$(top_builddir)/test/$$F ; \ + echo '-- Copying test file '$$F ; \ + cp $$SRC $$DEST || exit 1 ; \ + chmod u+w $$DEST || exit 1 ; \ + done ; \ + else \ + echo '-- No need to copy test data as srcdir = builddir' ; \ + fi ; \ + echo '-- Copying' $(top_builddir)/bus/*.conf 'to test directory' ; \ + cp $(top_builddir)/bus/*.conf $(top_builddir)/test/data/valid-config-files || exit 1 ; \ + chmod u+w $(top_builddir)/test/data/valid-config-files/*.conf || exit 1 + +## this doesn't clean generated test data files when srcdir=builddir +clean-local: + if test $(srcdir) != . ; then \ + FILES=`(cd $(top_builddir)/test && $(FIND_TESTS) | grep -Ev "(.svn|CVS)" )` ; \ + for F in $$FILES; do \ + DEST=$(top_builddir)/test/$$F ; \ + echo '-- Deleting test file '$$F ; \ + rm $$DEST || exit 1 ; \ + done ; \ + REVERSEDIRS= ; \ + for D in $(TESTDIRS); do \ + REVERSEDIRS="$$D $$REVERSEDIRS" ; \ + done ; \ + for D in $$REVERSEDIRS; do \ + rmdir $(top_builddir)/test/$$D || exit 1 ; \ + done ; \ + fi diff --git a/test/Makefile.in b/test/Makefile.in new file mode 100644 index 00000000..10f5258d --- /dev/null +++ b/test/Makefile.in @@ -0,0 +1,1046 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@DBUS_BUILD_TESTS_TRUE@TESTS = shell-test$(EXEEXT) +noinst_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) +subdir = test +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libdbus_testutils_la_LIBADD = +am_libdbus_testutils_la_OBJECTS = test-utils.lo +libdbus_testutils_la_OBJECTS = $(am_libdbus_testutils_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +@DBUS_BUILD_TESTS_TRUE@am__EXEEXT_1 = test-service$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ test-names$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ test-shell-service$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ shell-test$(EXEEXT) spawn-test$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ test-segfault$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ test-exit$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ test-sleep-forever$(EXEEXT) +@DBUS_GCOV_ENABLED_TRUE@am__EXEEXT_2 = decode-gcov$(EXEEXT) +PROGRAMS = $(noinst_PROGRAMS) +am_decode_gcov_OBJECTS = decode-gcov.$(OBJEXT) +decode_gcov_OBJECTS = $(am_decode_gcov_OBJECTS) +am__DEPENDENCIES_1 = +am__DEPENDENCIES_2 = $(top_builddir)/dbus/libdbus-convenience.la \ + $(am__DEPENDENCIES_1) +decode_gcov_DEPENDENCIES = $(am__DEPENDENCIES_2) +decode_gcov_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(decode_gcov_LDFLAGS) $(LDFLAGS) -o $@ +am_shell_test_OBJECTS = shell-test.$(OBJEXT) +shell_test_OBJECTS = $(am_shell_test_OBJECTS) +shell_test_DEPENDENCIES = $(am__DEPENDENCIES_2) libdbus-testutils.la +shell_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(shell_test_LDFLAGS) $(LDFLAGS) -o $@ +am_spawn_test_OBJECTS = spawn-test.$(OBJEXT) +spawn_test_OBJECTS = $(am_spawn_test_OBJECTS) +spawn_test_DEPENDENCIES = $(am__DEPENDENCIES_2) +spawn_test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(spawn_test_LDFLAGS) $(LDFLAGS) -o $@ +am_test_exit_OBJECTS = test-exit.$(OBJEXT) +test_exit_OBJECTS = $(am_test_exit_OBJECTS) +test_exit_LDADD = $(LDADD) +am_test_names_OBJECTS = test-names.$(OBJEXT) +test_names_OBJECTS = $(am_test_names_OBJECTS) +test_names_DEPENDENCIES = $(am__DEPENDENCIES_2) libdbus-testutils.la +test_names_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(test_names_LDFLAGS) $(LDFLAGS) -o $@ +am_test_segfault_OBJECTS = test-segfault.$(OBJEXT) +test_segfault_OBJECTS = $(am_test_segfault_OBJECTS) +test_segfault_LDADD = $(LDADD) +am_test_service_OBJECTS = test-service.$(OBJEXT) +test_service_OBJECTS = $(am_test_service_OBJECTS) +test_service_DEPENDENCIES = $(am__DEPENDENCIES_2) libdbus-testutils.la +test_service_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(test_service_LDFLAGS) $(LDFLAGS) -o $@ +am_test_shell_service_OBJECTS = test-shell-service.$(OBJEXT) +test_shell_service_OBJECTS = $(am_test_shell_service_OBJECTS) +test_shell_service_DEPENDENCIES = $(am__DEPENDENCIES_2) \ + libdbus-testutils.la +test_shell_service_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(test_shell_service_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_test_sleep_forever_OBJECTS = test-sleep-forever.$(OBJEXT) +test_sleep_forever_OBJECTS = $(am_test_sleep_forever_OBJECTS) +test_sleep_forever_LDADD = $(LDADD) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libdbus_testutils_la_SOURCES) $(decode_gcov_SOURCES) \ + $(shell_test_SOURCES) $(spawn_test_SOURCES) \ + $(test_exit_SOURCES) $(test_names_SOURCES) \ + $(test_segfault_SOURCES) $(test_service_SOURCES) \ + $(test_shell_service_SOURCES) $(test_sleep_forever_SOURCES) +DIST_SOURCES = $(libdbus_testutils_la_SOURCES) $(decode_gcov_SOURCES) \ + $(shell_test_SOURCES) $(spawn_test_SOURCES) \ + $(test_exit_SOURCES) $(test_names_SOURCES) \ + $(test_segfault_SOURCES) $(test_service_SOURCES) \ + $(test_shell_service_SOURCES) $(test_sleep_forever_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DBUS_BINDIR = @DBUS_BINDIR@ +DBUS_BUS_CFLAGS = @DBUS_BUS_CFLAGS@ +DBUS_BUS_LIBS = @DBUS_BUS_LIBS@ +DBUS_CLIENT_CFLAGS = @DBUS_CLIENT_CFLAGS@ +DBUS_CLIENT_LIBS = @DBUS_CLIENT_LIBS@ +DBUS_CONSOLE_AUTH_DIR = @DBUS_CONSOLE_AUTH_DIR@ +DBUS_CONSOLE_OWNER_FILE = @DBUS_CONSOLE_OWNER_FILE@ +DBUS_DAEMONDIR = @DBUS_DAEMONDIR@ +DBUS_DATADIR = @DBUS_DATADIR@ +DBUS_HAVE_INT64 = @DBUS_HAVE_INT64@ +DBUS_INT16_TYPE = @DBUS_INT16_TYPE@ +DBUS_INT32_TYPE = @DBUS_INT32_TYPE@ +DBUS_INT64_CONSTANT = @DBUS_INT64_CONSTANT@ +DBUS_INT64_TYPE = @DBUS_INT64_TYPE@ +DBUS_LAUNCHER_CFLAGS = @DBUS_LAUNCHER_CFLAGS@ +DBUS_LAUNCHER_LIBS = @DBUS_LAUNCHER_LIBS@ +DBUS_LIBEXECDIR = @DBUS_LIBEXECDIR@ +DBUS_MAJOR_VERSION = @DBUS_MAJOR_VERSION@ +DBUS_MICRO_VERSION = @DBUS_MICRO_VERSION@ +DBUS_MINOR_VERSION = @DBUS_MINOR_VERSION@ +DBUS_PATH_OR_ABSTRACT = @DBUS_PATH_OR_ABSTRACT@ +DBUS_SESSION_SOCKET_DIR = @DBUS_SESSION_SOCKET_DIR@ +DBUS_SYSTEM_BUS_DEFAULT_ADDRESS = @DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ +DBUS_SYSTEM_PID_FILE = @DBUS_SYSTEM_PID_FILE@ +DBUS_SYSTEM_SOCKET = @DBUS_SYSTEM_SOCKET@ +DBUS_TEST_CFLAGS = @DBUS_TEST_CFLAGS@ +DBUS_TEST_LIBS = @DBUS_TEST_LIBS@ +DBUS_UINT64_CONSTANT = @DBUS_UINT64_CONSTANT@ +DBUS_USER = @DBUS_USER@ +DBUS_VERSION = @DBUS_VERSION@ +DBUS_X_CFLAGS = @DBUS_X_CFLAGS@ +DBUS_X_LIBS = @DBUS_X_LIBS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPANDED_BINDIR = @EXPANDED_BINDIR@ +EXPANDED_DATADIR = @EXPANDED_DATADIR@ +EXPANDED_LIBDIR = @EXPANDED_LIBDIR@ +EXPANDED_LIBEXECDIR = @EXPANDED_LIBEXECDIR@ +EXPANDED_LOCALSTATEDIR = @EXPANDED_LOCALSTATEDIR@ +EXPANDED_SYSCONFDIR = @EXPANDED_SYSCONFDIR@ +FGREP = @FGREP@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML_CFLAGS = @LIBXML_CFLAGS@ +LIBXML_LIBS = @LIBXML_LIBS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_AGE = @LT_AGE@ +LT_CURRENT = @LT_CURRENT@ +LT_REVISION = @LT_REVISION@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIC_CFLAGS = @PIC_CFLAGS@ +PIC_LDFLAGS = @PIC_LDFLAGS@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +R_DYNAMIC_LDFLAG = @R_DYNAMIC_LDFLAG@ +SECTION_FLAGS = @SECTION_FLAGS@ +SECTION_LDFLAGS = @SECTION_LDFLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TEST_BUS_BINARY = @TEST_BUS_BINARY@ +TEST_EXIT_BINARY = @TEST_EXIT_BINARY@ +TEST_INVALID_SERVICE_DIR = @TEST_INVALID_SERVICE_DIR@ +TEST_INVALID_SERVICE_SYSTEM_DIR = @TEST_INVALID_SERVICE_SYSTEM_DIR@ +TEST_LAUNCH_HELPER_BINARY = @TEST_LAUNCH_HELPER_BINARY@ +TEST_PRIVSERVER_BINARY = @TEST_PRIVSERVER_BINARY@ +TEST_SEGFAULT_BINARY = @TEST_SEGFAULT_BINARY@ +TEST_SERVICE_BINARY = @TEST_SERVICE_BINARY@ +TEST_SHELL_SERVICE_BINARY = @TEST_SHELL_SERVICE_BINARY@ +TEST_SLEEP_FOREVER_BINARY = @TEST_SLEEP_FOREVER_BINARY@ +TEST_SOCKET_DIR = @TEST_SOCKET_DIR@ +TEST_VALID_SERVICE_DIR = @TEST_VALID_SERVICE_DIR@ +TEST_VALID_SERVICE_SYSTEM_DIR = @TEST_VALID_SERVICE_SYSTEM_DIR@ +VERSION = @VERSION@ +XMKMF = @XMKMF@ +XMLTO = @XMLTO@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = . name-test +DIST_SUBDIRS = name-test +INCLUDES = -I$(top_srcdir) $(DBUS_TEST_CFLAGS) +libdbus_testutils_la_SOURCES = test-utils.h test-utils.c +noinst_LTLIBRARIES = libdbus-testutils.la +@DBUS_BUILD_TESTS_FALSE@TEST_BINARIES = +@DBUS_BUILD_TESTS_TRUE@TEST_BINARIES = test-service test-names test-shell-service shell-test spawn-test test-segfault test-exit test-sleep-forever +@DBUS_GCOV_ENABLED_FALSE@GCOV_BINARIES = +@DBUS_GCOV_ENABLED_TRUE@GCOV_BINARIES = decode-gcov +test_service_SOURCES = \ + test-service.c + +test_names_SOURCES = \ + test-names.c + +test_shell_service_SOURCES = \ + test-shell-service.c + +shell_test_SOURCES = \ + shell-test.c + +spawn_test_SOURCES = \ + spawn-test.c + +test_exit_SOURCES = \ + test-exit.c + +test_segfault_SOURCES = \ + test-segfault.c + +test_sleep_forever_SOURCES = \ + test-sleep-forever.c + +decode_gcov_SOURCES = \ + decode-gcov.c + +TEST_LIBS = $(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS) +test_service_LDADD = $(TEST_LIBS) libdbus-testutils.la +test_service_LDFLAGS = @R_DYNAMIC_LDFLAG@ +test_names_LDADD = $(TEST_LIBS) libdbus-testutils.la +test_names_LDFLAGS = @R_DYNAMIC_LDFLAG@ +test_shell_service_LDADD = $(TEST_LIBS) libdbus-testutils.la +test_shell_service_LDFLAGS = @R_DYNAMIC_LDFLAG@ +shell_test_LDADD = $(TEST_LIBS) libdbus-testutils.la +shell_test_LDFLAGS = @R_DYNAMIC_LDFLAG@ +spawn_test_LDADD = $(TEST_LIBS) +spawn_test_LDFLAGS = @R_DYNAMIC_LDFLAG@ +decode_gcov_LDADD = $(TEST_LIBS) +decode_gcov_LDFLAGS = @R_DYNAMIC_LDFLAG@ +EXTRA_DIST = +TESTDIRS = \ + data \ + data/valid-messages \ + data/invalid-messages \ + data/incomplete-messages \ + data/auth \ + data/sha-1 \ + data/valid-config-files \ + data/valid-config-files-system \ + data/valid-config-files/basic.d \ + data/valid-config-files/session.d \ + data/valid-config-files/system.d \ + data/valid-service-files \ + data/valid-service-files-system \ + data/invalid-service-files-system \ + data/invalid-config-files \ + data/invalid-config-files-system \ + data/equiv-config-files \ + data/equiv-config-files/basic \ + data/equiv-config-files/basic/basic.d \ + data/equiv-config-files/entities \ + data/equiv-config-files/entities/basic.d + +FIND_TESTS = find . -name "*.message" -o -name "*.message-raw" -o -name "*.auth-script" -o -name "*.sha1" -o -name "*.txt" -o -name "*.conf" -o -name "*.service" +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu test/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libdbus-testutils.la: $(libdbus_testutils_la_OBJECTS) $(libdbus_testutils_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libdbus_testutils_la_OBJECTS) $(libdbus_testutils_la_LIBADD) $(LIBS) + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +decode-gcov$(EXEEXT): $(decode_gcov_OBJECTS) $(decode_gcov_DEPENDENCIES) + @rm -f decode-gcov$(EXEEXT) + $(AM_V_CCLD)$(decode_gcov_LINK) $(decode_gcov_OBJECTS) $(decode_gcov_LDADD) $(LIBS) +shell-test$(EXEEXT): $(shell_test_OBJECTS) $(shell_test_DEPENDENCIES) + @rm -f shell-test$(EXEEXT) + $(AM_V_CCLD)$(shell_test_LINK) $(shell_test_OBJECTS) $(shell_test_LDADD) $(LIBS) +spawn-test$(EXEEXT): $(spawn_test_OBJECTS) $(spawn_test_DEPENDENCIES) + @rm -f spawn-test$(EXEEXT) + $(AM_V_CCLD)$(spawn_test_LINK) $(spawn_test_OBJECTS) $(spawn_test_LDADD) $(LIBS) +test-exit$(EXEEXT): $(test_exit_OBJECTS) $(test_exit_DEPENDENCIES) + @rm -f test-exit$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_exit_OBJECTS) $(test_exit_LDADD) $(LIBS) +test-names$(EXEEXT): $(test_names_OBJECTS) $(test_names_DEPENDENCIES) + @rm -f test-names$(EXEEXT) + $(AM_V_CCLD)$(test_names_LINK) $(test_names_OBJECTS) $(test_names_LDADD) $(LIBS) +test-segfault$(EXEEXT): $(test_segfault_OBJECTS) $(test_segfault_DEPENDENCIES) + @rm -f test-segfault$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_segfault_OBJECTS) $(test_segfault_LDADD) $(LIBS) +test-service$(EXEEXT): $(test_service_OBJECTS) $(test_service_DEPENDENCIES) + @rm -f test-service$(EXEEXT) + $(AM_V_CCLD)$(test_service_LINK) $(test_service_OBJECTS) $(test_service_LDADD) $(LIBS) +test-shell-service$(EXEEXT): $(test_shell_service_OBJECTS) $(test_shell_service_DEPENDENCIES) + @rm -f test-shell-service$(EXEEXT) + $(AM_V_CCLD)$(test_shell_service_LINK) $(test_shell_service_OBJECTS) $(test_shell_service_LDADD) $(LIBS) +test-sleep-forever$(EXEEXT): $(test_sleep_forever_OBJECTS) $(test_sleep_forever_DEPENDENCIES) + @rm -f test-sleep-forever$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_sleep_forever_OBJECTS) $(test_sleep_forever_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode-gcov.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shell-test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spawn-test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-exit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-names.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-segfault.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-service.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-shell-service.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-sleep-forever.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-utils.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) all-local +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-local \ + clean-noinstLTLIBRARIES clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am all-local check check-TESTS check-am clean \ + clean-generic clean-libtool clean-local \ + clean-noinstLTLIBRARIES clean-noinstPROGRAMS ctags \ + ctags-recursive dist-hook distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am + + +dist-hook: + for D in $(TESTDIRS); do \ + test -d $(distdir)/$$D || mkdir $(distdir)/$$D || exit 1 ; \ + done ; \ + FILES=`(cd $(srcdir) && $(FIND_TESTS) -o -name "*.in" -a -not -name Makefile.in | grep -Ev "(.svn|CVS)" )` ; \ + for F in $$FILES; do \ + echo '-- Disting file '$$F ; \ + cp -f $(srcdir)/$$F $(distdir)/$$F || exit 1 ; \ + done + +all-local: + for D in $(TESTDIRS); do \ + test -d $(top_builddir)/test/$$D || mkdir $(top_builddir)/test/$$D || exit 1 ; \ + done ; \ + if ! (test $(srcdir) = . || test $(srcdir) -ef .) ; then \ + FILES=`(cd $(srcdir) && $(FIND_TESTS) | grep -Ev "(.svn|CVS)" )` ; \ + for F in $$FILES; do \ + SRC=$(srcdir)/$$F ; \ + DEST=$(top_builddir)/test/$$F ; \ + echo '-- Copying test file '$$F ; \ + cp $$SRC $$DEST || exit 1 ; \ + chmod u+w $$DEST || exit 1 ; \ + done ; \ + else \ + echo '-- No need to copy test data as srcdir = builddir' ; \ + fi ; \ + echo '-- Copying' $(top_builddir)/bus/*.conf 'to test directory' ; \ + cp $(top_builddir)/bus/*.conf $(top_builddir)/test/data/valid-config-files || exit 1 ; \ + chmod u+w $(top_builddir)/test/data/valid-config-files/*.conf || exit 1 + +clean-local: + if test $(srcdir) != . ; then \ + FILES=`(cd $(top_builddir)/test && $(FIND_TESTS) | grep -Ev "(.svn|CVS)" )` ; \ + for F in $$FILES; do \ + DEST=$(top_builddir)/test/$$F ; \ + echo '-- Deleting test file '$$F ; \ + rm $$DEST || exit 1 ; \ + done ; \ + REVERSEDIRS= ; \ + for D in $(TESTDIRS); do \ + REVERSEDIRS="$$D $$REVERSEDIRS" ; \ + done ; \ + for D in $$REVERSEDIRS; do \ + rmdir $(top_builddir)/test/$$D || exit 1 ; \ + done ; \ + fi + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/data/auth/anonymous-client-successful.auth-script b/test/data/auth/anonymous-client-successful.auth-script new file mode 100644 index 00000000..9a1620bc --- /dev/null +++ b/test/data/auth/anonymous-client-successful.auth-script @@ -0,0 +1,16 @@ +## this tests that a client can login anonymously + +CLIENT + +## Reject whatever mechanism the client picks first +EXPECT_COMMAND AUTH +SEND 'REJECTED DBUS_TEST_NONEXISTENT_MECH1 ANONYMOUS DBUS_TEST_NONEXISTENT_MECH2' + +## And this time we get ANONYMOUS + +EXPECT_COMMAND AUTH +## of course real DBUS_COOKIE_SHA1 would not send this here... +SEND 'OK 1234deadbeef' + +EXPECT_COMMAND BEGIN +EXPECT_STATE AUTHENTICATED diff --git a/test/data/auth/anonymous-server-successful.auth-script b/test/data/auth/anonymous-server-successful.auth-script new file mode 100644 index 00000000..172ae9de --- /dev/null +++ b/test/data/auth/anonymous-server-successful.auth-script @@ -0,0 +1,13 @@ +## this tests the server side in a successful auth of type ANONYMOUS + +SERVER +## verify that prior to doing anything, we haven't authed as anyone +EXPECT_HAVE_NO_CREDENTIALS +SEND 'AUTH ANONYMOUS 442d42757320312e312e31' +EXPECT_COMMAND OK +EXPECT_STATE WAITING_FOR_INPUT +SEND 'BEGIN' +EXPECT_STATE AUTHENTICATED +## verify that we are still anonymous +EXPECT_HAVE_NO_CREDENTIALS + diff --git a/test/data/auth/cancel.auth-script b/test/data/auth/cancel.auth-script new file mode 100644 index 00000000..f2c519aa --- /dev/null +++ b/test/data/auth/cancel.auth-script @@ -0,0 +1,19 @@ +## this tests canceling EXTERNAL + +SERVER +SEND 'AUTH EXTERNAL USERID_HEX' +EXPECT_COMMAND OK +EXPECT_STATE WAITING_FOR_INPUT +SEND 'CANCEL' +EXPECT_COMMAND REJECTED +EXPECT_STATE WAITING_FOR_INPUT + +## now start over and see if it works +SEND 'AUTH EXTERNAL USERID_HEX' +EXPECT_COMMAND OK +EXPECT_STATE WAITING_FOR_INPUT +SEND 'BEGIN' +EXPECT_STATE AUTHENTICATED + + + diff --git a/test/data/auth/client-out-of-mechanisms.auth-script b/test/data/auth/client-out-of-mechanisms.auth-script new file mode 100644 index 00000000..ce6d3ad4 --- /dev/null +++ b/test/data/auth/client-out-of-mechanisms.auth-script @@ -0,0 +1,7 @@ +## this tests that tests that the client disconnects when it's out of +## known mechanisms + +CLIENT +EXPECT_COMMAND AUTH +SEND 'REJECTED BONGO_MD5' +EXPECT_STATE NEED_DISCONNECT diff --git a/test/data/auth/external-failed.auth-script b/test/data/auth/external-failed.auth-script new file mode 100644 index 00000000..7c4e9001 --- /dev/null +++ b/test/data/auth/external-failed.auth-script @@ -0,0 +1,11 @@ +## this tests that auth of type EXTERNAL without credentials will fail + +SERVER +NO_CREDENTIALS +## verify that prior to doing anything, we haven't authed as anyone +EXPECT_HAVE_NO_CREDENTIALS +SEND 'AUTH EXTERNAL USERID_HEX' +EXPECT_COMMAND REJECTED +EXPECT_STATE WAITING_FOR_INPUT +## verify that we still haven't authed as anyone +EXPECT_HAVE_NO_CREDENTIALS diff --git a/test/data/auth/external-root.auth-script b/test/data/auth/external-root.auth-script new file mode 100644 index 00000000..b4c4b439 --- /dev/null +++ b/test/data/auth/external-root.auth-script @@ -0,0 +1,11 @@ +## this tests we can auth EXTERNAL as ourselves, with root credentials +UNIX_ONLY +SERVER +ROOT_CREDENTIALS +## 30 is ASCII '0' in hex +SEND 'AUTH EXTERNAL 30' +EXPECT_COMMAND OK +EXPECT_STATE WAITING_FOR_INPUT +SEND 'BEGIN' +EXPECT_STATE AUTHENTICATED + diff --git a/test/data/auth/external-silly.auth-script b/test/data/auth/external-silly.auth-script new file mode 100644 index 00000000..4e18ee8d --- /dev/null +++ b/test/data/auth/external-silly.auth-script @@ -0,0 +1,12 @@ +## this tests we can't auth if socket reports silly credentials but we ask for our own uid + +SERVER +## verify that prior to doing anything, we haven't authed as anyone +EXPECT_HAVE_NO_CREDENTIALS +SILLY_CREDENTIALS +SEND 'AUTH EXTERNAL USERID_HEX' +EXPECT_COMMAND REJECTED +EXPECT_STATE WAITING_FOR_INPUT +## verify that we still haven't authed as anyone +EXPECT_HAVE_NO_CREDENTIALS + diff --git a/test/data/auth/external-successful.auth-script b/test/data/auth/external-successful.auth-script new file mode 100644 index 00000000..222938cc --- /dev/null +++ b/test/data/auth/external-successful.auth-script @@ -0,0 +1,12 @@ +## this tests a successful auth of type EXTERNAL + +SERVER +## verify that prior to doing anything, we haven't authed as anyone +EXPECT_HAVE_NO_CREDENTIALS +SEND 'AUTH EXTERNAL USERID_HEX' +EXPECT_COMMAND OK +EXPECT_STATE WAITING_FOR_INPUT +SEND 'BEGIN' +EXPECT_STATE AUTHENTICATED +## verify that we now have some credentials +EXPECT_HAVE_SOME_CREDENTIALS diff --git a/test/data/auth/extra-bytes.auth-script b/test/data/auth/extra-bytes.auth-script new file mode 100644 index 00000000..cd1e01d2 --- /dev/null +++ b/test/data/auth/extra-bytes.auth-script @@ -0,0 +1,10 @@ +## this tests that we have the expected extra bytes at the end + +SERVER +SEND 'AUTH EXTERNAL USERID_HEX' +EXPECT_COMMAND OK +EXPECT_STATE WAITING_FOR_INPUT +SEND 'BEGIN\r\nHello' +EXPECT_STATE AUTHENTICATED_WITH_UNUSED_BYTES +EXPECT_UNUSED 'Hello\r\n' +EXPECT_STATE AUTHENTICATED diff --git a/test/data/auth/fail-after-n-attempts.auth-script b/test/data/auth/fail-after-n-attempts.auth-script new file mode 100644 index 00000000..0ced386b --- /dev/null +++ b/test/data/auth/fail-after-n-attempts.auth-script @@ -0,0 +1,34 @@ +## this tests that after retrying too often we fail + +SERVER +NO_CREDENTIALS + +# 1 +SEND 'AUTH EXTERNAL USERID_HEX' +EXPECT_COMMAND REJECTED +EXPECT_STATE WAITING_FOR_INPUT + +# 2 +SEND 'AUTH EXTERNAL USERID_HEX' +EXPECT_COMMAND REJECTED +EXPECT_STATE WAITING_FOR_INPUT + +# 3 +SEND 'AUTH EXTERNAL USERID_HEX' +EXPECT_COMMAND REJECTED +EXPECT_STATE WAITING_FOR_INPUT + +# 4 +SEND 'AUTH EXTERNAL USERID_HEX' +EXPECT_COMMAND REJECTED +EXPECT_STATE WAITING_FOR_INPUT + +# 5 +SEND 'AUTH EXTERNAL USERID_HEX' +EXPECT_COMMAND REJECTED +EXPECT_STATE WAITING_FOR_INPUT + +# 6 +SEND 'AUTH EXTERNAL USERID_HEX' +EXPECT_COMMAND REJECTED +EXPECT_STATE NEED_DISCONNECT diff --git a/test/data/auth/fallback.auth-script b/test/data/auth/fallback.auth-script new file mode 100644 index 00000000..0d880c00 --- /dev/null +++ b/test/data/auth/fallback.auth-script @@ -0,0 +1,17 @@ +## this tests that a client can fallback to a secondary auth mech + +CLIENT + +## Will try EXTERNAL by default first without first calling AUTH alone. + +EXPECT_COMMAND AUTH +SEND 'REJECTED EXTERNAL DBUS_COOKIE_SHA1 DBUS_TEST_NONEXISTENT_MECH' + +## And this time we get DBUS_COOKIE_SHA1 + +EXPECT_COMMAND AUTH +## of course real DBUS_COOKIE_SHA1 would not send this here... +SEND 'OK 1234deadbeef' + +EXPECT_COMMAND BEGIN +EXPECT_STATE AUTHENTICATED diff --git a/test/data/auth/invalid-command-client.auth-script b/test/data/auth/invalid-command-client.auth-script new file mode 100644 index 00000000..ac17e7be --- /dev/null +++ b/test/data/auth/invalid-command-client.auth-script @@ -0,0 +1,8 @@ +## this tests that receiving a nonexistent command is handled properly +## by a client + +CLIENT +EXPECT_COMMAND AUTH +SEND 'NONEXISTENT_COMMAND foo bar baz blah blah' +EXPECT_COMMAND ERROR +EXPECT_STATE WAITING_FOR_INPUT diff --git a/test/data/auth/invalid-command.auth-script b/test/data/auth/invalid-command.auth-script new file mode 100644 index 00000000..c49cb8d3 --- /dev/null +++ b/test/data/auth/invalid-command.auth-script @@ -0,0 +1,7 @@ +## this tests that receiving a nonexistent command is handled properly +## by a server + +SERVER +SEND 'NONEXISTENT_COMMAND foo bar baz blah blah' +EXPECT_COMMAND ERROR +EXPECT_STATE WAITING_FOR_INPUT diff --git a/test/data/auth/invalid-hex-encoding.auth-script b/test/data/auth/invalid-hex-encoding.auth-script new file mode 100644 index 00000000..1f15c436 --- /dev/null +++ b/test/data/auth/invalid-hex-encoding.auth-script @@ -0,0 +1,6 @@ +## this tests an invalid hex encoding followed by successful authentication + +SERVER +SEND 'AUTH EXTERNAL willy' +EXPECT_COMMAND ERROR +EXPECT_STATE WAITING_FOR_INPUT diff --git a/test/data/auth/mechanisms.auth-script b/test/data/auth/mechanisms.auth-script new file mode 100644 index 00000000..be447916 --- /dev/null +++ b/test/data/auth/mechanisms.auth-script @@ -0,0 +1,8 @@ +## this tests that the server sends a list of mechanisms +## in response to blank AUTH + +SERVER +SEND AUTH +EXPECT_COMMAND REJECTED +EXPECT_STATE WAITING_FOR_INPUT + diff --git a/test/data/equiv-config-files/basic/basic-1.conf b/test/data/equiv-config-files/basic/basic-1.conf new file mode 100644 index 00000000..99f41e80 --- /dev/null +++ b/test/data/equiv-config-files/basic/basic-1.conf @@ -0,0 +1,25 @@ + + + mybususer + unix:path=/foo/bar + tcp:port=1234 + basic.d + /usr/share/foo + nonexistent.conf + + + + + 5000 + 5000 + 300 + 5000 + 6000 + 50 + 80 + 64 + 64 + 256 + + diff --git a/test/data/equiv-config-files/basic/basic-2.conf b/test/data/equiv-config-files/basic/basic-2.conf new file mode 100644 index 00000000..49e707e8 --- /dev/null +++ b/test/data/equiv-config-files/basic/basic-2.conf @@ -0,0 +1,5 @@ + + +basic-1.conf + \ No newline at end of file diff --git a/test/data/equiv-config-files/basic/basic.d/basic.conf b/test/data/equiv-config-files/basic/basic.d/basic.conf new file mode 100644 index 00000000..d109d71d --- /dev/null +++ b/test/data/equiv-config-files/basic/basic.d/basic.conf @@ -0,0 +1,13 @@ + + + mybususer + unix:path=/foo/bar + tcp:port=1234 + basic.d + /usr/share/foo + nonexistent.conf + + + + diff --git a/test/data/equiv-config-files/entities/basic.d/basic.conf b/test/data/equiv-config-files/entities/basic.d/basic.conf new file mode 100644 index 00000000..d109d71d --- /dev/null +++ b/test/data/equiv-config-files/entities/basic.d/basic.conf @@ -0,0 +1,13 @@ + + + mybususer + unix:path=/foo/bar + tcp:port=1234 + basic.d + /usr/share/foo + nonexistent.conf + + + + diff --git a/test/data/equiv-config-files/entities/entities-1.conf b/test/data/equiv-config-files/entities/entities-1.conf new file mode 100644 index 00000000..3d3cea79 --- /dev/null +++ b/test/data/equiv-config-files/entities/entities-1.conf @@ -0,0 +1,14 @@ + + + + mybususer + unix:path=/foo/<bar> + tcp:port=1234 + basic.d + /usr/&share/foo + nonexistent.confn + + + + diff --git a/test/data/equiv-config-files/entities/entities-2.conf b/test/data/equiv-config-files/entities/entities-2.conf new file mode 100644 index 00000000..9ffabeae --- /dev/null +++ b/test/data/equiv-config-files/entities/entities-2.conf @@ -0,0 +1,5 @@ + + +entities-1.conf + \ No newline at end of file diff --git a/test/data/incomplete-messages/missing-body.message b/test/data/incomplete-messages/missing-body.message new file mode 100644 index 00000000..138e9ea5 --- /dev/null +++ b/test/data/incomplete-messages/missing-body.message @@ -0,0 +1,19 @@ +## message that's missing an expected body + +VALID_HEADER method_call +HEADER_FIELD INTERFACE +TYPE STRING +STRING 'org.freedesktop.Foo' +HEADER_FIELD MEMBER +TYPE STRING +STRING 'Bar' +ALIGN 8 +END_LENGTH Header + +## create the body, then chop it off +START_LENGTH Body +TYPE INT32 +INT32 37 +END_LENGTH Body + +CHOP 8 diff --git a/test/data/invalid-config-files/badselinux-1.conf b/test/data/invalid-config-files/badselinux-1.conf new file mode 100644 index 00000000..4852ded2 --- /dev/null +++ b/test/data/invalid-config-files/badselinux-1.conf @@ -0,0 +1,10 @@ + + + mybususer + unix:path=/foo/bar + tcp:port=1234 + basic.d + /usr/share/foo + blah + diff --git a/test/data/invalid-config-files/badselinux-2.conf b/test/data/invalid-config-files/badselinux-2.conf new file mode 100644 index 00000000..ac3b95c4 --- /dev/null +++ b/test/data/invalid-config-files/badselinux-2.conf @@ -0,0 +1,10 @@ + + + mybususer + unix:path=/foo/bar + tcp:port=1234 + basic.d + /usr/share/foo + blah + diff --git a/test/data/invalid-config-files/circular-1.conf b/test/data/invalid-config-files/circular-1.conf new file mode 100644 index 00000000..faa895a3 --- /dev/null +++ b/test/data/invalid-config-files/circular-1.conf @@ -0,0 +1,4 @@ + + +circular-1.conf + \ No newline at end of file diff --git a/test/data/invalid-config-files/circular-2.conf b/test/data/invalid-config-files/circular-2.conf new file mode 100644 index 00000000..46a7e78e --- /dev/null +++ b/test/data/invalid-config-files/circular-2.conf @@ -0,0 +1,4 @@ + + +circular-3.conf + \ No newline at end of file diff --git a/test/data/invalid-config-files/circular-3.conf b/test/data/invalid-config-files/circular-3.conf new file mode 100644 index 00000000..87e354d9 --- /dev/null +++ b/test/data/invalid-config-files/circular-3.conf @@ -0,0 +1,4 @@ + + +circular-2.conf + \ No newline at end of file diff --git a/test/data/invalid-config-files/not-well-formed.conf b/test/data/invalid-config-files/not-well-formed.conf new file mode 100644 index 00000000..9e59cbc0 --- /dev/null +++ b/test/data/invalid-config-files/not-well-formed.conf @@ -0,0 +1,5 @@ + + + mybususer + diff --git a/test/data/invalid-config-files/truncated-file.conf b/test/data/invalid-config-files/truncated-file.conf new file mode 100644 index 00000000..e8d60883 --- /dev/null +++ b/test/data/invalid-config-files/truncated-file.conf @@ -0,0 +1,9 @@ + + + mybususer + unix:path=/foo/bar + tcp:port=1234 + basic.d + /usr/share/foo + =0 that represents the number of n, b is either 0 or 1, and each n(i) is a decimal integer +representing a positive number. The length of the compact string is given by the summation of the n(i). + +The compact string is interpreted as the representation of the bit string consisting of b repeated n(1) times, +followed by 1-b repeated n(2) times, followed by b repeated n(3) times, and so on. + +Example: + M = 5 1 7 13 5 1 2 + where z = 5 and b = 1. Then the compact string M represents the bit string + 1111111000000000000011111011 + where 1 is repeated 7 times, 0 is repeated 13 times, 1 is repeated 5 times, + 0 is repeated 1 time, and 1 is repeated 2 times. + diff --git a/test/data/sha-1/bit-hashes.sha1 b/test/data/sha-1/bit-hashes.sha1 new file mode 100644 index 00000000..e30e90ba --- /dev/null +++ b/test/data/sha-1/bit-hashes.sha1 @@ -0,0 +1,1239 @@ +# Configuration information for "SHA-1 Test" +# SHA tests are configured for BIT oriented implementations +H>SHS Type 1 Hashes +DA39A3EE5E6B4B0D3255BFEF95601890AFD80709 ^ +59C4526AA2CC59F9A5F56B5579BA7108E7CCB61A ^ +6E42FB84067CFF056C43A49E484997AF23190879 ^ +C63FBB9A87171A176E6E054890E29A8C5F125F6C ^ +3109E33C1C4B9A0169D1599169D0E5A520A1E71C ^ +9195E1E73CC68D7170F44BD1D83CB624BC87FA0B ^ +64F7C374527278C0436DBC8DE5AABEC2BBF634BC ^ +154B622EA426FB151B1FF1BE1CE871752B9EDEB4 ^ +12BDD00FD4038756CBCF8ECDAD1B0CD862603CD8 ^ +6700F93E1691E83735279E167F67AF61FEE9813B ^ +84AF20A06799F366435BA20F99B9A10955B6D276 ^ +C622FE003FD16220357F88FC6B9DE4789E77C321 ^ +C8DEA5A98DADA1F9662D5C150618140A150ECA46 ^ +FBB7127E77A39D856EC849D755C868CA7B9F11E9 ^ +B7D8A7A39AB33ED8C3AFD8F76201BF0904149437 ^ +154535460A12B9E100E251BB3A4D4DBCD80A309A ^ +82FC6020C7A9B62F334F7156ADA608532DCA6A3B ^ +9DD980B8073B32D21E9B2324F982024375C2951F ^ +419F97A9899486DC53C58C761CEB564314FD47BD ^ +A212E43EBFB31388F64C0C0B0B1CC7019704B744 ^ +D8F1623C186A5615F58E846C9D164F35A8956E44 ^ +AA32848DE1499365730A3650A3A7703FD404259A ^ +79BDB01E55B61A8C1AFBF63D3CE2DCCAB8CF3DFB ^ +23BF3164A448A727BA71457EBA9FCFABFBAC4F70 ^ +BA26E846EBEF7434B63F5862FDA005A1CEB5656E ^ +98622869A474EA85FE575CD979354248141A14A7 ^ +5C9E7E6951D386205542DA0680E07E60EC61D64E ^ +8EF07A02A7023AA0E6EE4BE1518627A521D1F9D5 ^ +CDEA382A5DFDA1C633F8BBC77F291F40E8801CE3 ^ +3C0A709FEF85DDBCC1B362AA162010461F31AECD ^ +10ABD6B8D97E688AF5CDA7955CD3CC0850A4A75F ^ +0EC53133F7FF955CA37D25491B592DFC0256BF23 ^ +1A46A67FEED1604523C062AACC2455223B366D05 ^ +FA3DD749E8F3D9029D9261F25157B3C0E2DF6834 ^ +43DCAC2CF20E7CCB1DED6E379CC302F302655F3B ^ +8BA25BDF331671CCB4B60961E4AF356224027862 ^ +AC3A3EA0FB8727334A4478ED165128581BBC5BEA ^ +CA4406A231EA2CA06CD1D8F3C77FEF9118B1501A ^ +5B83465B8EED14871FB51D9E6CE499FB2E4B4209 ^ +9445F521861946D4063E0CA3F41F580855A7454E ^ +C2410140818962F95506B407AE8514F11F892AEC ^ +F8F826FE0D93F415426ADB6956242116CBAB2426 ^ +C803F7539AA036CBB31B735238120FB85180D8C8 ^ +162EB5163692D9BC7B4529D214BBB932157361B6 ^ +D4B0D876A1952ADB5D27A1A6BF71BCF22731A4C5 ^ +CB5CD26AA39E45F248706604EDB9A2DB8EDC1BF6 ^ +F1AC987F30FF0375F6115C0CCD6E22DDFD0FAFE7 ^ +692E209D3A6A0228EB9823DCB738B16BDF97A4E9 ^ +FB9E1E71F7645EEEEB3DDE66716DC44444CD657C ^ +D51F071E360D96124DA49AD37E37DE17B564920D ^ +0667AFCDBB82B4213447D0B22006DC4A1320CD21 ^ +8FBFC65FEB2565F2FB8A9966B74702350C87CF40 ^ +8A8BBCD6AF76E71067EB0AF54F90EE5AC2B5882F ^ +8D831EF2344E336CC27281227185A34356B856A6 ^ +DE7AA7424F92CBC50966FC4E6A577F98905998FC ^ +1064EE6BEF704F3A618CB9C58F299B22A4D34293 ^ +95F8CF7E864FEBBF77E46067063D08D5175FC508 ^ +79381F230970F120D19B115BF864C794878E7797 ^ +D82A30F49538561D5A7D1324ECAD321DD05E1202 ^ +5926CEEAE43D29A7BE4C0EDCA626C43ABE00416A ^ +563458C9F2C16C5AF96915FCD9306F1D9BA579C9 ^ +C92B0BD604E45D7479AE19F641B2DB067E4CA774 ^ +D69D013EE5C871D3AE3E388090BC1AAF9852A83C ^ +7C341ECDEE7298605933465EA9ADBE7E044C8A79 ^ +83EC687D22A13EDDCD470C52C45276A6E1554982 ^ +6D27928F014269CEC4E8745EB73FA714BE2DC62E ^ +75C0BF312C05231DAF7E9CD4CA33ACA78BCAA59A ^ +015D799C602DD4E30D2C0104A57B1E214A423D66 ^ +D2F43ECAD20F0B4C57DD07D3CECE562B6B72C7FB ^ +27948CE5A56D57248D4DF683DC3FE023D2B9B43A ^ +2D5A984BF32DE28242744406469E18B7A5178A97 ^ +FFC5C4ECF0CC051320E071D14C7DCA4A4DDA305A ^ +CED8A5487AD13AF0003129659DE2556183836C54 ^ +599BB509863CC5D275416F6DB6C5D2BD827DC347 ^ +3981DAC895DDB9294D933C1CE78828E3A558B152 ^ +91EB715904123D326B23ACD684DFBD7203CABECB ^ +5A9AC8C3705AF14DDE50E6CF2FE5B0C15C4BD282 ^ +E2620DFB42B5ECAF85F590A71DF696906AC41C4D ^ +CBAADDA7B5DB389BF1775AE50040081A05A0EE48 ^ +AAF80D079F3F980BF9D5366C5B1991A3E3D9FDCE ^ +2A861F616604C526ACB157732DC431E81BC9A1F6 ^ +FBDB22AA0B87718F464C0D1AA39695A1BDCE053F ^ +4331BA331522D4F9CD6137858DB9AA16AC95316E ^ +33F6BFE23A4C0E04B8BF642CD96437EF0055AAF7 ^ +2046138F7899FDB2063CD84B84E821525172C03B ^ +E4FDC812C5F7A37FC7A81005F1E78BFF59666887 ^ +6477F931AC20B2FCE1C92171FA4DCF2D266B3DC5 ^ +ED0DD516FA7FE2DB7AFCC3DBEED0879A0C10F1C2 ^ +FCEDA0311C085368A5751BCAD8EAED2063C2D40A ^ +23EB08B5100C8FBAF7B3049887A11CC531B6CD78 ^ +A6C42B757DF078A69FFF6819A8ABC46E1B09F435 ^ +0615EE4840B1F1CD628636D1B4F4495639DEDEBC ^ +E2288110007AE6DBCCFC74B7735F4D94B0AA10A1 ^ +159E01DC348EB067E90A63BC6FEFBF4C45A01F9A ^ +A16286459CC989AE662C731F3D7D0CD487DCCB3B ^ +8FDAFE2DE37215E142E27A65A881F80E0430BF49 ^ +1BF978B58D98FC15731F4111E7C7A49F9CFD7C65 ^ +C1F61CD4B4DB14AA60C6448C0398EEC72107826C ^ +5CF0A7F6F46A730CD9103A54F1EC8A7549FA5788 ^ +FDC104217940BE5A7AD1C02D128B31747C972A5C ^ +DFF58BEF4FF418D26A35B55215CE419D3579A194 ^ +3A2EFD444F4AA7A3DB9765E027CE5D82B51F6737 ^ +EB616B6F97C5BFD02C1B9E4AFBA8A5151DD4167F ^ +62F31F9A28D0587BD8253601A7EFB698B03205FA ^ +E87645B2CB7DF66DA2771ABE0CEDA0F625FC8AFA ^ +E801C3071CA6AEE278B222747BFA819C118A2DDD ^ +EC70223BD963C122E4FCE2928934DDD2D7661CBC ^ +82261D26377A5A5DC69E0F39D0BBF59A1B2B2248 ^ +2E4DE781E4407AE536F70DC5A5DBEB178DBA2FC3 ^ +AD3D958B884CAA28D5858DA103463C300862DEE6 ^ +2A6A563C7FE33129637FABB4D40F5F0EE8B5C500 ^ +7EA6003A8BEF4D5BFA6BFEFBCB6A5B3B1A3B7991 ^ +6DDC620DB14882575D5BA1219284CF1C3068094F ^ +91AD7E588EC829739C3632656DE1915AC23C8CF5 ^ +311A491C1B5D8A26EA2A77A36B5D53FDABA1FB2A ^ +9D4B752AA8FDAF92897B03C4D65B65EABBDF062C ^ +C569FF6F0592664F690B008EE7A12EDA5740F0C7 ^ +1AE35E9CD3D0A8A165B2758E1DC4F9D1CD30FBF9 ^ +819A83318700EA861CB69F6CD8ED4ECD78CC3CB7 ^ +98099B550A82CE22EFAE48B5935F636D5814FDB4 ^ +CFADB998167DB289A7C17BA94DF7EDA00B29085E ^ +3F5A90A8F757936987938DFB95F10239F91AC264 ^ +7402265908EEA5DA183490FEF2EA2E55C9FC2862 ^ +EA6EF0F7050EDA6B78F35597E85B7A85AE0097E4 ^ +73F2780548F7C79E15945D7EE2A3E03B30DF35CA ^ +8EC3C93C7307E14E9C65F26DD847CEB195DE277A ^ +CFBC571A35B82FB0B7CB59753C4E8DE36A751195 ^ +3C4802A956CF93A148B9034FB8F041ECD8DD4532 ^ +5DA269C1D5CCEE3C7A66E31BD9F5E0B83BA06CE1 ^ +706D90C00800DB9790AF66788D1B3DC81E3FF7A1 ^ +59AC856447FDD27421C52EA66E465C64C5033722 ^ +EACA9E82D043F2B6E12E64CF03D82ED92FD6A64D ^ +8160755BA09C74F79DE8F9496BF0C9248DB7D45E ^ +8CE4390C185BDFC8BC9C4D3BEB1AB757C44F6434 ^ +1A1ADB628EB7B9CAA821AE9DE417E09A42A97113 ^ +97C4F92A46EF3F9169A977E1643C10745ECDAA4E ^ +408E53C03D10E2B32222F2B54D118AC4D65A9386 ^ +710628E811C207784E3255DA8432CE6E14B61FE7 ^ +4F6DB622778F4B1B6203BD239312D86589F1B261 ^ +888AD8FC1CA5B893294FDB8FC94AB7762018C1F8 ^ +AE36C2F54223BC082DDA0D528B70B2AEA190779C ^ +4BD2BF914223DCD0CBBCC444323FBF0E487F27B6 ^ +7526D5DF7B2ECFAC7BFF62DD7A4B5F38463305F8 ^ +0ED7C87B68F50813AAD5E50159CBE0BBF9BF05D2 ^ +4D5CD4E40A6668893EEA15F025ECB8187475DF4F ^ +D38446E842C0A94F175B772BDC707CD2EE79D098 ^ +DDA868BC2903C55CF273F48E9B92C09D90CD0179 ^ +0841268B95ECFAAB9FE3787BA7261227A1F23294 ^ +D3DDF20B4C0DB668421DE1F242B65A8C83FA867B ^ +112F3CF7DACA7527819D16704EB41302A4EE52AA ^ +96072A3EA4463A156B3BD9EAEC16ADB0905160C9 ^ +715F195F09E3EAD3D70AE51DEF1C9709500C0A6A ^ +8A112CA82CFEB5F3001B7A00591462F4120DDC02 ^ +50FC91E915270D1202F6FC8792BE16ECB73CE405 ^ +907736EC45BE7BEDA1B154EA282C51B5795991F8 ^ +05D49462991278720EB44BEA656AB4442C8845C3 ^ +6FD56D08A2D4630F72AC97E3C94A9575F3046729 ^ +DD1883376CF713C8D7AEBFEC60D51FF8E2A806E8 ^ +E0457FE00F9DEEE958DD6AD948EDF9CD9412F73A ^ +BA6538E91B276504C84E213B325B4A7703E924B4 ^ +C20A9B848503650DE9463B9992EB977422BB53DF ^ +BA4A565E5C0F9FAC89D55A2B784F291C7BAD4255 ^ +6510E09AAD8288AB81CA54DD5656DF57D0EABBE6 ^ +33996C9C5AD04883BCEB9771A5C4A272F88550B1 ^ +7B96F3C1272AD765DBDC35A59243F6A8F75FA351 ^ +5AA76B16EA4DFB267D88FF7DBE4F055184A56E56 ^ +33B9CCEB1A6EDC8C91F6034245B2E3AAC898C678 ^ +701A32FC0B1163BC55DB76FA46F69B574B3803A0 ^ +5D6F44A4B5175BA873BFA3369DC8BFB0AD1AC26C ^ +0727F12D8E554EDCB435AE3BD6425B197DF6EE2E ^ +6E1F46DC4FAD671759AC969998694BD79326246E ^ +85233F9CFD0780BD60240A22E037C14EB8286C33 ^ +B66CC7332341FA9261D96362F0BBD7B676F95E02 ^ +782A78F2FC32E0B627702C541341ED28B009BB6F ^ +6B7935265C529880DA5B166EDD660BAE14A770A9 ^ +49C298B1C10D380BACE26E907C213C90052D7523 ^ +49CE4D4FF9FFF6724DA032FF33F8C5A7792D24E2 ^ +CD2C4F19C12B086C071BB6B20E8E8210AFDD2D50 ^ +39710F77BE564C417C80CB6E4B87BE72FA805A40 ^ +F74A6A45F5B2979B5E773007B90804F322F13AD8 ^ +6FD6A34339047CF13F777C4B7D9E287F499FB19C ^ +FDB04F04D3B364A6953C341E343E310F2383A655 ^ +981E8717538CE98998E950EAD28596B527736841 ^ +E099987DB0CC61CF607C9852336CDAF478DEE33F ^ +E9C42F25A3E3542D1510DD09BF516AD809D42702 ^ +F7E580FB21C725CBEA563B193896862B9BEF7F24 ^ +D778A3287F68F47B0AA421410292D47805997A94 ^ +534DFE759735723649EDC89BCB063C0CCFEEC34F ^ +9381FB5BD26677A7760FC0288532755062986DF1 ^ +27E97EE829820399595DA0A0047B74D3C4E0DBF1 ^ +D38450071D1B079A9FD518D2F317C83C33094F43 ^ +0221B8E4D2FA66D2EBE1B04E679662CE41405E48 ^ +B9BC4FDC4A5CE00EFB911C3062D6F33304701C28 ^ +461B4206618B766C89E6D9AB2F8DB07903860234 ^ +122A9306B102F2C50B7364E1D24FECB0662E2958 ^ +61E91F5D167066EC904134AB1C4F9D116C9D3E80 ^ +6B7558BD8F4D3C5914A9AB5D7418F7DB77583B55 ^ +CE48EA94843854555DC48D24D32405DAB9DBA612 ^ +5A722AAC576F4078C001D06DA91C28131A4F92C5 ^ +9B8FE0F1E6573CC6832BA69DEC9F6E646228A374 ^ +F98429CA2799E5CAAEDDFB168B782A54384EF0A8 ^ +142877754AB95F57AA541CB978BA400E812AECC9 ^ +6D84D053CCD9E68CAC5780892409F61B39DDFD48 ^ +B58CC9CE0AE3DAAA02E3C040100D4B568D29E0FA ^ +17FB18FA32A8237D32CF83A9664B1B2E40DC5B11 ^ +C7F65E54E608CEF1C7A120BE8A29FA6C94B680D2 ^ +9C46329BA34077394B439C5476B91D9DF019BA76 ^ +3612B381B80A1DF6DA75AB2656BD5BA8DE6996B5 ^ +EDD9BCA1C431200D3234C099791C81D8605091AB ^ +C1951DDECB9796C0D39ED9AFCCBB65200AEAB0CB ^ +55E4F7846D9B90D8B31EAA5B9371D395590B6528 ^ +5D40B432ADBDF3A01355FFFDDBA47586B3DC7C52 ^ +AF5C675D2249F4CD20E70DC9E18B88D3ACFBD6BF ^ +B0EB6796A21876FAAF50FCDBA2EB121C4B742166 ^ +3C577C70B76810DDF9AD579910347312B881C30F ^ +0C16897D20C5F352FA6110C70F9A8C33CA35CA21 ^ +DBE0B4341526060C5B37576F6B972A1EB8954059 ^ +1567B10E33FBBE20033F5A52EB810348ED154F19 ^ +C1E47289412D3ACC208620A1EA676CE2815DD4FB ^ +ABC227EFFDCE3758061C77971860247E850382AD ^ +B29EACEC903BB8AF7CC1A63516163640FFE62822 ^ +5C8976A1A4FCC6B6FAB5EE631E3CDC561ED5FB10 ^ +1A1EA5107CC46BE909DF8165C3EFEE8676161991 ^ +268E86BA3A81FADDB20F74DD44C5BC71A98C3D08 ^ +05057E5E7934AC9A9141D39B8D4F5EA6AA14F74F ^ +C03EA72C4D68945726DF63803564E434426302BA ^ +54AF20BFBFEAD6BB2DD68E65D39D427DF7E17FD9 ^ +FDE938DB0843A844DC0F6601497A39ACF167D6DD ^ +ED0292D0BD869B66E80014824A3D7886CD6D3590 ^ +749B69964F5C0D9D02BF5CF903B2E56D09CF1B9C ^ +6B143D30366C45F159B83A8D1AE8AAEC88E44136 ^ +01169D65E71014946D0BF64BF439068978AA5B3A ^ +4C36E0A8C19C0AA6C80DF0611BA3404C1025E9CC ^ +A4DA9EEC2F682AF5B2EE7CC8525EB07DF66E5945 ^ +F1349AD0124D11613CFA46D498671484E5F37790 ^ +6A8E82D2D27D3EDD6E8B119F746761B8FE83182A ^ +52E7C7C4AE02659953079DAE20F442353EE2BB29 ^ +49C8D822724274B85DE62D9DF586FE880AF396E6 ^ +57866C0BB976B4F8AAA7ACF3C9A0F700E73216DA ^ +541A675DD37C5D6F2CF242163A5CF6B728DF9995 ^ +55B26D9344D4D644CBB69C4789473543262E8B91 ^ +3A8F3F0A96297020EEA583E9A280D53E0248DE26 ^ +D1FF7A0CD0B69A76B5B80D2BB5736B8440DA7F7B ^ +53E715FA39D3732F38FB4748D46409D998D67973 ^ +377781ABB4AB4E974B9C1670867E74F87AB4950A ^ +8E7DA96971265ACC0FF7C381127C966DF9F9F13A ^ +28038713A33ACAAC730FB4DDC3A707886E598DD5 ^ +5F6BD44D07A1C811D5B75661A61BB69A81444EE2 ^ +D465E6C767BD02D457D601765DD0FE5521BA2AC7 ^ +487D9E02912004E961968F387C21A65A0E653AE7 ^ +1F54DF00052B3740301C43420CC2CB85B2770095 ^ +7C5BB678083868EB817E616BD09421B910021649 ^ +4D31526E4E2FE3BD6DD4B3F59DC2EE2A52A9FB42 ^ +669F9FA9D71FB92D51ADE15C70742FB31B013901 ^ +38D1E74FE26AA43D45DABC160DEFF113B7740211 ^ +3724EF50CDEAEB856123BEBB190F38834461664D ^ +E2634112D2977A179D4C9AF35F220D3A626AA04C ^ +F14CF8133FF66A3E20D25E5DCFF70605F6B8A0BC ^ +809E04A38340D010B78B5287C8FDD20C391FB61B ^ +E5349D4D6EC31E2CF41001DFC440ADFF6D25B4F7 ^ +139F25FDC344EC2456F6E4DD9938F65693F0CB2D ^ +7C628B0954D4340B0851C89F1106589C5C6465C6 ^ +E65E65D7050258B6B6B5B35866840B5ACE0DBF0D ^ +77D33B87E0C13529D3AAC4D6606213EFE81FF398 ^ +5BA456BA49ABE50BBCB772FAACB71D4F3AECBD45 ^ +801A21F7AB73585AE3531058DB9512BD69BA5CB1 ^ +192AC4D5210EC863604FC1BA388AEA8455D4175D ^ +FD9F103EDFC4CC9F9C424266EE54A79C1C987F9E ^ +361AC46D96A69DD6E416D4563D7C69D3B487EFC1 ^ +3A7629045C0193FE08928F7D41B801827593116B ^ +545B2F5FD015F81BDE1DAFAFCA184D25590560C9 ^ +FEF2C50DA33621206450E21D92951B25385991A3 ^ +913A417AC1ECE08952A60E0035F70993F161EF05 ^ +4FFC95481F6F625B1B8E67B133F11619CE5C1460 ^ +5D6D0765B156FE028780331B6A53F84DFB130F0A ^ +2C5EC89F1018D34AB11E0CB6FDC812F82470B168 ^ +34D62CDFF955233FE7A5308925C24CBCDC0579B8 ^ +1148994D30F80C5689D7BB19CFBE33546872B4FC ^ +074FCA22A8A63F446C8D196612F7C812C22CCD8B ^ +228FE29FD13928D8FF0B850E50DB41DB406EFCBB ^ +EFF7BBF8F2F7DF36AD51EF3D748AAB8D8DAB7B7D ^ +C3AEA6AA17971C0A143ACE54A8CF515F9EEB0BD6 ^ +4C3A980E40602D4621C2AF1BEB1CAE27DF19AD32 ^ +E5CE2A41C72229D584E40FBA67C697EFA08F451D ^ +64A5368264959C73FB0A12F85D4FA16F8E25FF08 ^ +8FB770AEC165A93A6D99A0DC52F38444E0313073 ^ +BCFF3C5E5C56876A3DD8C4C90D4E819B67D71394 ^ +0EF20523757E25611C49C1F259D94381B08FB90A ^ +5D9F05DAB91C46ADDCE4B163C6FCDFB5230BDFFA ^ +11B3BDC5F3BE09148DA07CD42EC9C28C718D6A5B ^ +1EAD76EF18840B3176296FA57791D832B7E4035C ^ +AF8EBCBBDF5B8CFC203FBD8644B154445690B02E ^ +0A156DAD35A10AA7E41C5CB3B3043A051B7180B6 ^ +9B3E5F797BA246E5DE660B9A36E52C204BACE822 ^ +78780359CD24A2B7157FD6D55CDFA6F9DE149FF5 ^ +F2DADAB4275633F7ECDFA971D824A31B1C8D6643 ^ +EA68BA8F16D8368E6673A5C5AEE86BA5C36F2D97 ^ +788AA9451196E2BDD031E747B098D73BE113C093 ^ +18FE259B3573F52F23DAD33F05D9C91942B516DD ^ +0E4787F46AE8D5D7CC9589B76D00D60983079D75 ^ +148E4FDF031CAFB726099DCD1EB591BC2F24D179 ^ +3981DF8658AC2FA5C3151A424262324D41940DBA ^ +3C50A3800636EF877D89059F66CD697A9DF44BD1 ^ +D9BAB0471E2DB97FD5F3A42884DFC708768F62F9 ^ +52DD1063326E2550B6EF40D5EE4E1AD67C7BB6BA ^ +13CA27827127C698810AECA158DCAA7894F0C912 ^ +086BDB17EC1B8CAC68030A56FBD4C741D4F95DBA ^ +F7F389BC5ED225BD6399CC43EF22AFD77E895D06 ^ +67F173AD3A24C26E95E2EA8B37FC0259B1DE955C ^ +A7F348A3B6F67CCF7C7C69ED065B3FBFA832A8A2 ^ +ECECBB25354468FB62AC87D5CEB688E4A671DC42 ^ +62330BC400108DFAFF298EFB76BDC28CDC153AC1 ^ +BB0ECF9CB3CE448B4EA9C57CF5F1F997F81082B4 ^ +12C9741672CE8DBA14CC66AF3338B61E234F9E68 ^ +DB4CB5961A2FF6964CEDECAED3DA03D140112EA4 ^ +45E4D2BE3D9729BE9F69ADB245A5A9CC75064534 ^ +E35253550C84BEFC26C2E97F0C236CFF1D85C36F ^ +7D6D950A168107702CE3B6BCEF9298F9C8FC8F3C ^ +812F459AB5887364D1F2A9A00CBEE5FC352C39A2 ^ +7EE27F33C59B68C34604416D38606BD3F5CB6B06 ^ +D57E2A4F15DF5C50F2485909EE3149735C6DFB84 ^ +3D12D88B61EF0972808D8CAD41D8A16AA7ECCC87 ^ +CF9A7CEA9B105ADAB6BBA3CFB6D090B76603F7CE ^ +1D43CA164CAD0B616BE5763D7F5EA88355953F4B ^ +3600F085A53FB0115C26DA90D1180FD34EEB6301 ^ +E9F9C088C30A37E6CDF067F724BE6C4786F27C9E ^ +2BB86B47EA34400D434F8F4F94830CBDA9D4E573 ^ +3255A7D9A7A0B56D0D9C665EC13F7A8C8F05DA7B ^ +453597500A7D5BEC8CFB950926A2BFC0F92E149B ^ +A15EC452476870AC459B942F6A6B73822A07899C ^ +5B1821BFAF917BAB3DB1284A1D1FD40EA011BCBC ^ +8DDC25C7CA330A18CF39827B7CBEC00B874AF193 ^ +283832F45BB5E69649FC10DD607BAF8BAD61783E ^ +F39426F9C0474596B0251F0CBB5F92385D862D24 ^ +714E32DD5BB8FCC75B1013E6F1F56F96D97B36F2 ^ +988AC4592D50113B13F6EDB5C113A22E4D0F518E ^ +93BF1463788B7F4A4A06AD4C17482DC260797A3F ^ +5532535ACC8AC5668977B2A2F322B23AEB443DB2 ^ +85CC7AF0929F206FA44FCAACDC24C4E78345BD80 ^ +392196E3F2F4074D1D485A52119012D8C05740B6 ^ +3BA88B91F1EA18E712292301FBBC375E9B48BFC6 ^ +3DAAD1DAB1795F2C1C8C5CF5305B549ABFB85398 ^ +6EC93AFA3AB617708276E99066FDC331C84F028D ^ +CDA219303B91AF3C3FBD0B926758914984AD7C8D ^ +599CE24745EB5408554077354BD10A65F6BC3037 ^ +0798C1B53F949D643F7BD66C194715E7CAFC6E19 ^ +A17230F164E98AB83AC1141730B23389F0EB473D ^ +2C2B95173F1B06165E17EAE36A53C7AB641267C3 ^ +A7F408EF449DC92961617D4C51B55AE4E4536E97 ^ +2266C5133B6D6B08A09897AEFA355C768F718C6C ^ +343F10EE6EB34DF005E749D1C4A98F64537272B1 ^ +90EEB76B126E632308F8655FD49C52000027AA48 ^ +C7EA3C7D4AA8DCBE9580C4434075017934268419 ^ +455D4E7C988356A56588C40313D28E425AE219F9 ^ +5C0F3090992138D34B4E33029CF83A64ED8AB03D ^ +CB3C5288839D6FE79EB2E50D3AC34BBC4A942E46 ^ +E605842205079D83BDD489DCF6F8A2D1EE074C60 ^ +ABCBEC56EA20B6B369C85A931B2201FECB826F4A ^ +480C1CB97C3419DA610D9783E6047E6C9A6101A4 ^ +874818464DA1753D3AEDDB7D3B46E2D04614D7E6 ^ +C95B65E3A37ED4A2FE2B27A2D52BF1BFD307ED20 ^ +5E188A4F625C05482BF161C45F5094844CE70461 ^ +6B2EBCFE74E0BF32480D4BCF9A5698A527AEBEAD ^ +ABD3E28A2A528B7963EA8D8896651A17337304D9 ^ +B873FDE2C312C2279EC8950EC2C2E9DF990F006F ^ +4F1A18714689BDB766AF686623BEF08DAFDFE1F5 ^ +BA886793A89E7EC62692A8690164BF072EAF7AA4 ^ +A15C8DDAA0448DE7B361552FC51AF0D72C0737FA ^ +6FB516CBB4CCE9681C44EFABABC7A26C79C79CB5 ^ +C6DA89D3F7EC4D2FCDB36432042A78EAC9F04DC6 ^ +2A94A9023F7D54DB26C8C2A6A4C951126712C2E5 ^ +B0F115B8BF0A1464A378420A1F1F574AA1869FC8 ^ +A3C1794F58FFDC361BCAD4779B5DEF48E02ABD1A ^ +2DBA5D80C4B17167E715A8012876095577030D5C ^ +062C3CB7A059766125B368AD6C19BE8FAA981950 ^ +ECEA96EB623919DF4E22FB106616EF1FB2ACF5AF ^ +C0CD5E555861FFBCB2FF4045A46CE30AE6CA1758 ^ +A0150D931980E1D82A21928837F7E9E198E5D1B9 ^ +BF877B202812184CA74DE61FE34DB95BA2AC5D0B ^ +C863A0D2232E901920752F2AF92C201FC73609B5 ^ +C54E676209D81CFED2E7ECEA6F7E35A5459A58AE ^ +CBF376E8571F81792AAC49BA7E1D7F41713ACDCE ^ +9CD248C07EEF6303C71901AC484F30788D9269F9 ^ +AEA41C5B2260E0DC57094C5E1F80A70B85E79E77 ^ +B1016F26E32624C5328566B243329A2F75A36D06 ^ +3EDE118F7E2764CC49FBC3873508D38A2C6A4592 ^ +03DF0C882FEED72F81B303414178976ABD089EEF ^ +2A8E36B6A545D1ABE7B02D6DDD782AE032F7ED41 ^ +D90588E606FBDF3CC6030756DF92FB3729441E6F ^ +BCC413133B6D84621B482A7D2163EA955AC733BF ^ +BE1F36D34DEC54306EF20D8326FF603A716F4331 ^ +A2BAE41EA01E8AE9D59F5E8E663D22C9F414B0F6 ^ +D2295FE26206DE9ED169FEA487B198E7CA0DE78B ^ +06B13130DD10C94A24CB50DE6A612867F85E17FA ^ +2CF4C4F2F270AF63D7035903231CF7E7180E66E5 ^ +0A9EE3293A2C9B2ACC2F9B99BF17AAC618347857 ^ +C338F14C156D8777ECFC36ADF1850B64EE9E6179 ^ +E9BC6DA35AEB1CC399733CD0AD3B22E4E2C83E92 ^ +7A42F820210158AD33935CB77D78C28F9FE7A940 ^ +ECDEFA7817A436E43C3DFA35069F87948181A58A ^ +761EBF336F1229BF80702C9C7798DAC37ACF3086 ^ +1975B716880B49BA0863136736942E688C9EEC7C ^ +A4232C3227DBB91581B86FABB1C5AB0A29801DFC ^ +49947AF1D9488F146BE4C77782CB2FCF6EB13FC9 ^ +A3402AE17DB9E6EC899B0E15973073CF9404A2DF ^ +DCAFC2DC5BAB38629DFA0DE1454C300E5B9A2D66 ^ +A7F915F745E30E4CF6AFFABF214AB6D950C66FAE ^ +764515277D4AF73A14FAE2D9CFA4F9BAF306CCB5 ^ +B021EB08A436B02658EAA7BA3C88D49F1219C035 ^ +B97FE9E1C5918FEFBEDD986B757CCF4EC4AFA75D ^ +6917353596BFAF1A5A06119ECDABB37CB017D71E ^ +FCB4BCEBEBBAB66142AD2A5B35AB5DBF78C6A463 ^ +BCA454B69F4486960C633D2C4453FD01D6758BCE ^ +5CD25E62AD97AA5DB3A9CEE99C58439DFBF6073B ^ +E8405E583D31B3B8E8B365087F2AB391753324A4 ^ +39E32AE405420DEB07275224817B57187079886F ^ +63AC20AFAEDAFBFC018755F4CEB13A042BDEFDFE ^ +27245C74B61D19EA28FED81E59AA48EFC22946C9 ^ +7254C8F5A2DF0E747760E2EB353C4AB24E253602 ^ +32DD49B796ABCA76356AA9AB07D669CB7BC7F899 ^ +B83F3FBE6DB38223253344E69C399C474E4C64A5 ^ +B3E0EB484AE5B10B017F509730F350481A60F634 ^ +A99FC247C177D66CBC6C21C10C21E10FB2F33EF9 ^ +A7D033A946AA0315CD2E4B7025164B77E5979CBE ^ +F2DE5CD912D5CFE727B353ADECB6B7FD11E80189 ^ +111BA90582E17CB5E1BB70AB72C99FCF647876A0 ^ +9AF7F1A742235C0E396F6D1319BD1104518F8475 ^ +923B3E5246FB50FB5448742B8EA8CF4920E70702 ^ +CBFC4563334D104E4DF24443A295F4E9A7D7D4AA ^ +48F4BEDE76C6DDE9B72A9FED50D0BDBD0DF7E7AE ^ +2A21E7828C064DB0D684561622802C86A504DD37 ^ +2D599572D6E57A437A2A845546FBEF9F2FA11AD8 ^ +CB4CFD92FFEFFDDFD87A4786D60E28C7622C71DF ^ +FA6DB9D1EB92461454E7DADC36C9CE7A1F30C63E ^ +98C264B7CDF774C7D82F4DA5E1160AE4370665CB ^ +D503D3C5CAF7A2D124A7F9F0E7D8D0F5E29B6F19 ^ +AEFF5AF0023868EF6E3AD49F2C30D65E963B6308 ^ +73B1464B9D05509BE72E83C819F9D618B3121336 ^ +791774666D2629D4304BC81138B4D8A7599E77D6 ^ +362A2D419BAF263F1E77C5689F611AE301C044F2 ^ +B4D4796D1BC1851DDB75F5D3BA3089D1D0E0A15D ^ +B7C4FD404A73C0AE43FABAEB471FDB6F9B24A27C ^ +B9DC118349DDAB37DD82B65E092277C1E2F20C5F ^ +144782913DF2FA8F76D210A7A321F362FA5DA779 ^ +29D64351A178E52EDDA9A4B2F5279B70F3FEF39C ^ +31098A70FB95128BECC2C729CE5A2A4BCA121845 ^ +9C05D6B171C60C37822CDBD7E8C1C57286E27461 ^ +6FF7C4960E35463A8FDB77844A29DDAD1FF04F53 ^ +2E08B9088646737620F1B448E81EA5E42C40C595 ^ +AF2342D8F4BF12F9E524E44BCD42066F84620727 ^ +543A1A99B497DBB7776403F3252A9B2E11A0610A ^ +A2A46BEF09D21A9BA32AAE4FCF7A846D128F0358 ^ +81960A20A755F84B3623D1E2A395EDB12DFDE73F ^ +B016C90B350A5A9AD4C1F3AFE49E3EB21AAE8B7A ^ +41D03A8D79E8BAAE116C2F5573D869D97D7F6E0B ^ +831237F5BDAC37C58BA31F6131982AFE680BAC1F ^ +2E8ACF5FDE18542BDC2D0B95D3AED7FC48B5993B ^ +171763D880D45885EA61F5ED04BB51B79C6A2724 ^ +405AD282A2141C38D3D731F9DF630667064B9ED0 ^ +07F2ECB944D01DDF9C68AA68762BF07F385E7E6D ^ +EB5FEBB813E4DD7BF852FB32466025F7D4E79DD9 ^ +52DE090DB027385F17C9FD41F61272525FE108B1 ^ +103E352A261134E1154ED3C312D890646FED38AE ^ +65C73969E35E8F307B518ABBDE85654CAD13D0C7 ^ +FB380C0099EADED9ED8DD48D70E15C7A26E2F417 ^ +EF9E122E0B8F968EF262E1A98BBFED7B461846B9 ^ +771A162BDE3CC4C07BE7A1DD25470286F133020E ^ +5F892353DC5C65A1D8C9510ACEC43DD96F432742 ^ +4E658B8743D510221B968F2C78C72A588A5DF6D6 ^ +5D5295ACEC24F8A52ECC5B174E4884732BD216E2 ^ +7791BD0E1C4136D97C46CCD66D36E98443C4182A ^ +515419AE59BE4E824E575E497F361C3382C21783 ^ +7669D0D083B3A0A7B631EE4871AD2A2AF8C512F9 ^ +90A1A9BD93501D9AFE5040DDEE395F94E5594EE4 ^ +B8E48F79618CDE951296F1D28B87653C3CDA6FDB ^ +FE94D5373EF009ED2C06F632C739717791EB6BB6 ^ +B5C3871DA2466E4635DD3BCD085A2B8E222CE8F4 ^ +43032D022D24B65394F7A707C8441C2A7F3CD980 ^ +87C13448017DB3B6C553250C59DF4D3D57676788 ^ +F38FCA4589543051935D4F1525710AB366161F22 ^ +921E3C3DE773F987452CAE28D3C10DF9804632DB ^ +32308D5BCA33E694071B8C17470C6469EDC1DCCE ^ +AC5258297BA22FE60B464DEE22349C70FDFAB219 ^ +599322BC214D7248216F0C6ECF00CC34C792C5FB ^ +99EBA91FAFC27288B3FF32DE55BF17BC6D76B16C ^ +899DF7C21779CC0F54EDCD441051CACBD2B06941 ^ +E5E0BA18BF3C99062BA444847876C5CA2DB8F9C4 ^ +94B8B90566B2E3BDDA8FF8D37BDD9F95CF9BE0B2 ^ +86422BAD65C5E0B22F02B9D1510B9D24F4227AC9 ^ +427694B772A08400381D472854FA5FD4D4CC1D62 ^ +3732DA8EBA84CB4591DD4A87BAE958635C85DD71 ^ +D41C28C028E42AD1DF5057C97BB953B03AE8F6AE ^ +4C44286F5979D44AB4CA5E3776F30CA04CE539EC ^ +E695D9B049A1497A86765195BA7884E8869142DE ^ +2A5DE9C5489375B8EFDB09CA29D32FDADAA07402 ^ +012356EB46A587763ECD1EC9F3114B8B8B7987B7 ^ +6B803DF07E5A47FBBE412149D8258B526D2BE96B ^ +14A1090C3B382482AAD5EF49B30D842317792745 ^ +C2A576DE385017FA84855388EE6CB1F51F43A6C4 ^ +5746B8C88CE540313A0429E64841ECD0AD569299 ^ +298EFB87E9C09299DEC17171902682D919899C9D ^ +55AEB7930CD6202CD52E6513ED4C35824B574198 ^ +ECDAA8404F88334E9C2C6FCC9209795581654C25 ^ +061FFFCE8F69BE0D0C9B63E30BB065C6CC73DF33 ^ +229F3A8BD2F6FFB5CE2DB330ACFBC4C4D7796D7F ^ +0BABE60803248059F3B05E06E273B5F41A619C9A ^ +5F496A5AAA1FC38B76069BF9F08C63777EE7530C ^ +91FC8994FAA03E9A2D9D565F04478C6DF035AFE3 ^ +A68552B9049E192BBF98E82E2A69E405FFC2D93F ^ +7910393D1D9D8B876EC89FE9100320D371789C23 ^ +9B923F97F2D2B057950DC3C0E89981F22F96EC2F ^ +1EAD9C237CF3B1CB95E7ED79EF2E5842E9263447 ^ +F51E5C202D698C75F8F0C2926081D4C28F641812 ^ +8842D9CD97868196B31F34C02BA63CE34493DCA2 ^ +26C8977BC36C3298582CE6703F62DFE4488E0DDE ^ +955BEF358ACA4D44E33F31051A3B92D96BA669E3 ^ +68D841B29DA285DA53A31E823462E794B3126914 ^ +BB52C1806605DD37113035390D97036EFB3FE2BF ^ +BC55772BC9B6066112512E1A8B633411B9508FA2 ^ +BDD2CA4B43157C04CE7043F57B7E2610D3E175D9 ^ +8E493F25E110F6244FBD7585CF18F285933950EC ^ +650242DF99E985DE23A5CFC25C8CA72C80D7F23E ^ +56A061FE49B428798C329336D4B184BFE69C4102 ^ +59FF817CEE946CB948056227607A119F4C7DDA89 ^ +BD4F03F1878CEA86E2AD981C6A80701E0AD30B4A ^ +A635F528CC4028877184E8918CF73E1AEE6F777F ^ +15DCAE87F7E40CA577C61C2AA5B6D90F0CBE6DCE ^ +D67BD85A353CEBB99ADE4CD86B54673DD6D64360 ^ +1619DE7229032800CDF071830CBCC3208B1EDB09 ^ +09DC18BEE0C2DD9A2C7189AA6D3DEB8B7CC41CE5 ^ +4165ED470D85FEDD9593577A9101306C31825E00 ^ +C52942DABF4F9D72B31B2B3291705EF5201B3343 ^ +88296035BE79F5281B91C0F1006E57C28671CBF3 ^ +82593804880F168B9FF50D89CD149E9F263EB557 ^ +52E4F42FC2EC2EB7C0A728D2251A14A6C5EA5A00 ^ +C91B243CBA2031B29F365BA4451FEFD6A902298A ^ +90F6F5A65E6BC9430A34C06631208AAE8B7555F5 ^ +7535D77C8809B4EA21678BF9686791418FC71931 ^ +027070AC6B5D77BFA0398B8AD556A23AB8E99EBF ^ +B48335F6FB6EA27CE2156A1D3E00E42D3E3A8489 ^ +B67303D71BF125F2441BFC599106177A32E43BAA ^ +46E98D49BDC5A4604F62AAF76E964838291BFAF4 ^ +F1ACC562D96999493EEBD2531A289264C3E1BEF6 ^ +0B261712C3F4D0D74EBDDD052E1A058BCFF412D0 ^ +50446AA7A1A81A97B1DD524AD0DB4D09971D383C ^ +E3A51B6AA5AA586803EF2183DECA0CB5CA869B11 ^ +C81B52FD60ABEA8CD5E3184E206F693211F008E4 ^ +197270C0DF693622DFE871857A7C87B7BE2E439F ^ +43453DF7620D71CAD56DEF9CEE616AD9E7C73EBA ^ +3E3C6EE1141AB3D7EA5215ACEF4E876EFA89D03B ^ +5773C28260C2B2D325883AE73B04D28BFD2E8884 ^ +EB6F26A0E774022773CD86E1C8DFEA461CE6F8F8 ^ +6C26410B11A0CFC97849F6E43E77B8E48D5C5363 ^ +F0236CEF2298ED3D86A95E9F5247C17499A772DD ^ +704B5496CE0AFF4289F3D915230F69ADC7A1ED7B ^ +B0D4FF6B50F09FBBA19F76693AC9CA87768E2758 ^ +10DE4F687577CCAD9E16AEDC9958021D90DE8726 ^ +785741949059E8508DB8D132A9B053EB4277119A ^ +CB041BAF13AD22778A1C73A8AAAB7458B664B1C5 ^ +B4B0ADDBEFA078AA497045629840FD965BEEC33D ^ +68F0E43B7DF89F484F3CBD6984C95168142E4A82 ^ +D042BE14A23D0CA1A0466179C119F2A959E1E118 ^ +DD23CC2824A881FDB6566AE6A57B1A2D1624E895 ^ +15B75E7E13B374039B8C9FB4A1122BB8A22FAD6F ^ +849F0D379A2775CCB5EBB0A88839516F30A665FB ^ +8B4125FF2EBFA9459075459C1EE149D68C4F98F6 ^ +1D632D3EEC63D18243FF48702AB894EA05A1AED3 ^ +F2C2E1082004EDCBE3DF96C25D8860C0F5B432BD ^ +4B96C3C284E9E12C3D2F18AB8C8FC6776F30C6DB ^ +F40DC8B94D9FE9910117BCD66F3FFB22F6977447 ^ +D65D126DF604DE306AEB41A641DE0B214449D69C ^ +90FBEFF058E825EB940122B6D8B7492FC574B32A ^ +AE4414AD47216DA0AFD9AD1E22C882F665429C54 ^ +5F9D97E91B7E4810AE765A09803ABFA50B6F64E4 ^ +A2D4E6AF7AFD87E303E867D0E03E1945A0F0B72C ^ +14ABF713982D4DC7C1CCFCE7A48680576082DCAC ^ +BEB8F77A7D211D9451B698D65FBC0B5E38D26086 ^ +B35F660629962D5F1F8529203999FCA0169F2675 ^ +07AC5B04166E739A9FB87FCCA74112AD93A08128 ^ +2D8272C9D620A730561EDFDAF2A129666CEBB5C9 ^ +C25C1971EAB264F44CEE1F44614579EE6D8C7858 ^ +76F8234E2F0A533E810545F79AE28A7C46056AF3 ^ +35025EA09EA111E299814FBC958977DDBC3A2387 ^ +0A2EF548A38D84F6A1CBB2AE01D48D296D6CD8FD ^ +6F546DD1623E92DDA185BDA01618DF7E7E7B82F6 ^ +A0C1C2AED8C3F436DE200E2A3F4C2A9D2DA8DD7D ^ +8DC10195B967FC7FE57B338494C2C42FB43599D5 ^ +0D9192B27851CAA766D90A5376CE255B2FDE906A ^ +7799450D003824356EDFEE1B408AA59E830175A8 ^ +2EA6F3188D3010EDF4EBB55E009CC4D99296F578 ^ +2A73ACB83FB8E25D65FBC1B8085BE67342F5858E ^ +67F9928A27118ECC38EE231E05977A694AD0F7AA ^ +27E2078CC9FDDF5C5DD6CE629F3EF071B2107936 ^ +F50540B4DEE071C64D861872F1E0BC4C7DE75B52 ^ +87DC9AF771F2EE543F96DB0C924AE650A063F854 ^ +76DB885DD797249A4E2F794171DD559FF056A9FB ^ +9AC2E9CD3881BF14D758A7FEBDA81BC9DDD31652 ^ +D3D8595D75AF4D1EEEBEA8166CAFB156E827DE90 ^ +5F7D9D9BD0DDC5A2AD4772610FE2A4923A826486 ^ +F437BB6CFAA9139A1201FEB58841B18C3809F00E ^ +8C3EB402D92E6543D885A9FDE2FC80B9D4340E8E ^ +134307C50C24BBD7822DBA30F644B874EBB54F0A ^ +24774DA4669C2037F7B2A43BCD1C8D574715F071 ^ +69FEF8FBC9034D05F3C9BD9C663D2198AB48FA30 ^ +0390F1C49421806B19DF1F886902F37088DF77DF ^ +DD535B129F482256503AD2744B712BFEB8BF216B ^ +ABEC552E41020144EFE06854149BE03F1BD7F6F6 ^ +3FC8C8A14D1452713E76EDD5EF95C239F3F8A4E4 ^ +8861A84429E238D94E75D3CC191FB4D128215F7D ^ +DBA6377C376AED4D1E79C198EA864B6E6D90C494 ^ +4E5DBF823DC5BFF56C999A1FD0ABBC51155017D3 ^ +6699420C6FF512BE5CABFE1EBAEFB0AE40CDD902 ^ +77CAE0D7EDFD2D13506D096D66A32B9907AB9B23 ^ +F6022F2A1545842915029B344B19F4C69757925D ^ +6ECD085FF34032636E7BE7269D29DA62BC4BFB5B ^ +60CC512BE506BE1A580CEEAD2A009DB8D7A1BBC6 ^ +0F34DFD7EDFA6A5DD132B2EE77B52EEAD98DC701 ^ +1BD542585AB33A0A3694BE45D6C7EEBC266D4806 ^ +1524F20389EBC2D7DE777F96156DF9B2A8652373 ^ +451282E6DA707668886AF7E77DB4C58F73CA6EC2 ^ +BB7D59890BC39F7F87D4DD7E2583C737B2B40B86 ^ +255D67E3AF65376A1D71FFCCF505812481AF182B ^ +4D559BC171516F79E22938DE999685F9FF05383D ^ +2F7EB16081B2338D631153D5B70DE67F050E348F ^ +5902CE6CF7700D2E23CEDEE742E273F4A6A39F6D ^ +7D37A7515D1E04D44CA0F314306919C0307FF4AD ^ +18C215A5B8AA9CA5C55DF8BCFC79683E9982B159 ^ +63520C9DD2CF321388DC89CC69D0D9F6772A3553 ^ +5FA13E6697196EBD0E40FEAED4B945CC93375DAD ^ +BF8CA60D07D1B69767056B2F80A9AC4B1F9FA99D ^ +6CDD13431EB70D9E346102B708E9F8AB233CF959 ^ +4CB448B4131DEB8F1AC3085765303CF214436A26 ^ +1FDC9CC58A748A9478A9E55C66C6446775382ECD ^ +0EDC5CC7CF8C6CB318616D62CC08CD1449960315 ^ +D5D0D540287D21AA519CE90B6E3D81958A2E307D ^ +BA5CCD323B987F54E06AE04A09957BC417ADA611 ^ +26846FD68BA956CEB2899DDC18324843DC211485 ^ +12BD70565F701BB35B87364B47F73C93287E7672 ^ +C57A0F96959C7DEDD353462099EFE380CB273E90 ^ +9900D5268B99165BE1AA2A6B41B9FB66455B865C ^ +D5AC2C2BF36B04EAEF95E8B93958BE28B5A4C836 ^ +82788DAA7F95292B266CA17E86631D866D68FD47 ^ +37B9E638610418C4CE4CF9AAC0D3E64F033D3D74 ^ +9845A156240CE847508A1D3762362FA90216E59D ^ +9E59DC76EA01567183A4B4AD65CD31F169706CA9 ^ +B2B4A1500A176C883268447A09DE920F0CF77F76 ^ +E14FA11B60B9389D3B9B2C1E7C45931992F666AE ^ +922D169C624E79DABDB79B76E777F6994C339EF9 ^ +AE99C2F46A3939CC5EE3F8CF68D6EA486392C23D ^ +154F915F90340CBB03B9514810FD399EED06CE3B ^ +C440E1E74C75266822919080966AB74D96FF43E2 ^ +405155FA99EF5E4A0F4E93D107CAEC89A80B94A2 ^ +0AA9625455A0CCDF37D486B4538E790BE407A59C ^ +46D633F7F2EC56496D53138A56D11D9ABDB701E1 ^ +75C1BD5738EB5380E25EC4FCFCC7BB3FD8164460 ^ +B618C9E52303919BF762D452F5681D23ABFF23B6 ^ +D08BE1F5485939677D294C4198FA15B118938B3F ^ +F931441259B793DABAF082D1B0024ACAD3CB48A6 ^ +096E206E3753BBEEC8F0F0D3F97EBF2EB3063B1D ^ +13AA397D03C60AA4414271D33CAC2361C138422B ^ +777E2979834E8C6E89D219E9109F0A2852961EFA ^ +13960A648DB8B7CF541A56B9009A5F7FBCC1ABAB ^ +B3447A3C462B53945F8295032FC9A057BC301FB7 ^ +8C42386A2436DE83E1959E92B44EBF61E6C8D093 ^ +D9EF91B04DD4371968E1978CBFEDB50C2BABBE67 ^ +E84042479D1D669AB5871B71D1342AD6D15105C2 ^ +4ACD112CD8CAC72DF2D4DA76910C2CD3BE1EC25D ^ +AA20982E2B138FB2407EF99509075CE8366F10BC ^ +5E3BC535BBFF471686885331CD9831C80FEB18CD ^ +53C55C80D64411221C7311654921523D2BD0E227 ^ +3FB8C850B9BC7A923767D036992AD79ED7F0E1AD ^ +AF0BCA4D440D6599BB91396A0823DE64764C2112 ^ +30B13703A702572257D54DC09463768F5AAEF759 ^ +59C44B99EDC297B476402310044554B3F29F9CCF ^ +FED078596C584810E5336545F6F6B93027D9CBD6 ^ +6499E70E5455F9C8FFD2D5F600009A43FAE710ED ^ +D26C0718A9C8222F30D021E8FA6508935E80BC85 ^ +1F4152447ECB8D7CD725B57B65E30F79B466BBDE ^ +6C4958665DDDFC828C1427E57D23359E9C5D1190 ^ +B88EAD843C4897B2A691612B837E5A5D9F58172C ^ +A51097DC1883B160AB799D2D103C443336EAC2CA ^ +5DA1B85BBF4F3912C5E964242A61EBE83A3DA5B8 ^ +4E9A45C0410F0211DD4D9123BFB8C29C53A5E03A ^ +C2B7C89F7DEA6E5A6CF909388471DEC4CA362255 ^ +4EF3B7E7846115212B3E77C29AACA6198422BEF2 ^ +78C74563BB2CF819F83E73CC00072378C114639F ^ +FAF96E836C381EC80FE1EA8AF76E9D8D8AD95FBD ^ +3B30A2BBF84AB70E8220349CBA249DB87FFDCBFF ^ +6CE0CC298D12597F801E0F1BDE66CA9DDF6AE66A ^ +8274B1DB8C0C7390C383C837FDABDEBBEDD1A8C1 ^ +D0F90D63ACD0126C84D714AD7C9EB673DFB459B2 ^ +D1E63EB5C373C78EDF968E0651DC1171907258F7 ^ +1530DC99565BE2B5AE91D1D70B027EDFD4EC6E93 ^ +FEC0946FB9CC04713C67BA36FA36EA9211131281 ^ +BD2BA680D2200AFC5CAFB362A5517BE9DAB7E593 ^ +5FB57E1AAD5BD9C1D176E1CA03C1A5A8E33DDE2D ^ +F6D5E7B1B28C9070115DB6665309B8DDF5F81281 ^ +BFE88F7A0FD5F6A1B26A5E15D0A109A1DA7C1FC1 ^ +E5668AA40375C8CA35FB3046EDD8AD9EDBA82FE3 ^ +C854D5C5A0A100411FCC9189D6307C47B57228CF ^ +1EE384076308AC6B80FB66856D5FA19952B3D6D5 ^ +CAA4DCFEE058D22D726292B2C722D3147F1DCD63 ^ +1887C76092C9275B2DE333014C99FD13E5E533BA ^ +AEAC6ACB4561985DCFF6C9696BE836FBF75E24E9 ^ +CA46F23773B30BF0ABF5C38EB9D0EE021D713F8C ^ +2EF007988B2161FED07E5181C342E724D3F640A3 ^ +F0F1422DFD34EDE00A8B0741F4F395234480FDB8 ^ +2C471BF867F5A02CC241E35D95C97B43D6536E7D ^ +D4906C8804B241E28F3F2E6380019FB739EC8503 ^ +632183EEF8C6EC8EAA3016A43E568DC38E29379C ^ +1808120D461A867C90222469985769AF1756EE5B ^ +08C2F97B6FA6E1433DAF56403CDFE8CEECF6BCFE ^ +2767E111977A20D318EAE19D59E1E551A4AA7F1E ^ +B1A7158CE56666BCD1FDE7DC87B40C92705BFDE5 ^ +7CE90514AD734390F6FE58BAE8FFCD66391E9595 ^ +C57F4C2D8B78DB8464EF1F719B8B1DA270867480 ^ +C97938F34C6DF26BFD509658838F7C35FDB0C58B ^ +A5CAA6946300B1C4B5F53A69AAAD67961C4C6821 ^ +DDF684947B1667A77A22C7DFE8B6A0A8484E2509 ^ +8FB1310F1F215E4EF62C41566C523275BC929670 ^ +1573CC447B398532BFB9A2E5AB3880F23CA7C27D ^ +D6E0B674B9E4D283C0AAC355989CC0E8BBF09678 ^ +7D083BB9C3E005B41FE32629F84B9E292D80FC67 ^ +D3E2591B7D7CD29E9ACE61DF6019D8787AC93BE6 ^ +7159B10AACA9E7610C7404DE961ABFDB17B89156 ^ +B4A0248088E850FFC5CCA99EA2F28ECACBFF1960 ^ +CA63F54FDB6C46E877760EF4E50E56F3164A417F ^ +C41DF52EB252961619BD4861C4AACCF1AB392B69 ^ +FE3EFE453C8705E1CEDD06F15DF5B35A7311DB32 ^ +5E2E8BB04B327E91572992A8A61063F7A76A93FF ^ +8EA0191E8491400038CC5B1416E5A56622EF1E8F ^ +47727D4D7E8D9738608AEEDEB0E12C9F2427EBCB ^ +7340F405BC428DA514E7B2F39728CD77FA2177F9 ^ +5E451C7A51AEBABCEF9FDFBF3538AFECB968872B ^ +528038274803D6DB419F6923993A45C999433336 ^ +281D30FD3C725A4646A6287329140BEA4AC7A5B8 ^ +922A57DBF62C01DA19B89F90F36C433817F089B0 ^ +C79AB225BBD03145A981DBE7BF6FDD16A5E95D8A ^ +301B4D0E270F2AEC6E1372560385D37875EB682C ^ +1EF2EC6A3642C7FD61C4F1C3DFC55302535254B7 ^ +1D94ECF29D2310B1A5A2042CFA616BA0D19E7C41 ^ +52DDA9BEEFAAAE667A6D12BE414FAD8619750040 ^ +B14486D16D1521D1283698E651A10FC14AFF8996 ^ +4BBFBD0244BFEE440DBEDC8361806CADFF673253 ^ +662E0E466C9D700C50C5F98CD77CFECF8278D708 ^ +1AC5B8197B0689681B0F474832F316CD25147AF3 ^ +8720E012F16588A3C368689113902119C9791FF2 ^ +D892C1E257A997A8DF95B229C9D24C99F60EF205 ^ +57F5C45286EC3D29CEC19939C04045D9C38E761E ^ +07151D2EC889D24730AAA5282FA4DFC49A66E439 ^ +6AC94690EA6DB4A8DC982271490EE18282A3B33D ^ +32DD19F12AC0854998C7B14D1D96C15FA8995DBD ^ +7817A25C6CF1EBFAA8DED7A80063D1A299AF8B18 ^ +01C5EAC1830D1F5A7F186E039663CE925FCBACDF ^ +B9F32F67FF4937F44094CB4A62BE12474AC3E1AA ^ +05BE2CD6882447472AD2E02B08590EDED62C7638 ^ +CEF149F6D6FC8987C3693D5F5CCAC0CDDD3D0787 ^ +6A7CC99DAD86DA9797B1F8336356C9864F279D35 ^ +3A72F8EFE64CF60D49589AB92D48301620CEC0ED ^ +F1F5939419E375182A2AA928DAE3CF6C378E4589 ^ +3EC1C1B74B8881F86C1D3EDE42F6689C61132710 ^ +7164A5B4A69A004FD76EA4C6CDFE0273D35CFF71 ^ +224325A309FDF2378C5776B1751BB0694ED30C28 ^ +64E0FECBF5F94517EA9E0F4E1E16FC700EE275B8 ^ +69CDF3321850BB640D5231D3B3458F83738CCE6C ^ +0684349A2ABEC06CE05100EB69D01CD4FB7AB193 ^ +1DFA49225C0FD725046AFCAFED17B1ABA6871FB7 ^ +ECF4B1B9C78A802F748D58BF6E27FAF1B274EEC3 ^ +A44B67EF91F2AAA9EB2DA8B166A1A316886E8909 ^ +CF38B0F7DDD2F72A891B41AD026FCC3282218747 ^ +F917033D4494A1CCC8580C1DBED6F28FEB3E2E57 ^ +3C326F550039F815ECF5E236F6DDE5DB0E2E9F65 ^ +7332001002A11FDAF501914A867398625398D5CD ^ +DEA189DC41AF695109ADCD93906EB5372B512A57 ^ +E0F14BCA9240B27E44647ECEB4A40408E2880DB9 ^ +77545EF84146F952212D9E1FDBAF62243CDA630A ^ +D162F654DEB5BB0D54179319D8DF9F1BB6D8A13B ^ +3BF79007252537CC2EB11E148842E7AC443CA91A ^ +6CB2F291C7198C9E4112B991FD4D829DBAD7EFB1 ^ +C850258036781C0AE8A083D6A791D3FAEC946C99 ^ +DC64C5037BDC93A3D38613D203FB3D7C82A18A24 ^ +620B7714289FD82ABB9FC776B644571F72A9557F ^ +4BEBC1EF44C30B0B033153F883D5C58E4AE6876D ^ +E3815A4E6BF3B50EE312E5A795B3E9AA2D7832AD ^ +9CB13D19C64752209D5D4D7033FAF9DE8960C147 ^ +3182B9F03D0ABA3BD91A1EB8CDD0F465FD9CCB51 ^ +73D8E8B9E6A04E88E29797CC5E2F489350D978A7 ^ +732734CCEC18944BCA784B953DCC0E582225AB89 ^ +A2152DB03048AE27B47C25DDF99D249504A8ADF1 ^ +AB70B32A28D9BFAAE1CA868C4A161B6D4B3A92E5 ^ +AB8B90085B47050B87F4BDAFDF971790B7950900 ^ +B315A8C87011BACA969A1B79EBAC80A7343742E6 ^ +B78A044908CDA9640633DC8BE828E22F90E6D7F3 ^ +AC2BC5246C1BD99231CDCCF3CECDEF5688E58D71 ^ +0679F888F8C353B807F544C2379BB5A4AE8EB9A4 ^ +464B5754E3D42864CC0A98B4E696C827E3254317 ^ +7E5385C8A1BFF0FF476905BB6B7515B6D438CC0D ^ +0F5C968CA2FCB4A17E0AF0B94682B3AC347C2D12 ^ +4F5E353500D63C99F58A28F5870064FA278FC7BA ^ +E7A104651C4D6DFD0778EC8AC8E4F001BC7B9DD3 ^ +23DCF9A854D1D5B5599B14A0E9A19AB4F2E3BB77 ^ +588E429FA1C3055C4DCC99EE5407A64115B54345 ^ +39215ACE01669CADFB81E9FB085710EB5B97461B ^ +23566449DD29A315D413604A2DBCFAE0D40579A2 ^ +1EA87C13DA38FE4C59691D96AF590EAF3908C0F1 ^ +5A6170FC6BD7E8C01140E16F248C56890B51323A ^ +FF328DFB506B72FDB8DF5716E291A1830BC539D4 ^ +7B4DA846F9074254C676F00948BD4C9698148C4D ^ +2AC310393EE1ECC5844A4BEC15A9CFC1B5022294 ^ +3AE36316FA94B369D7320A8B71304CE6490FECCD ^ +7078C7041275BCBE8403DE24D16A646B4462882B ^ +8325A8716A2C879888BA9F674C869B1FF31BF363 ^ +586200B55B5D537B59B5E0BC6FD9BACE1E72C6EE ^ +0B675E7F434756F5E310B80B58F861E789495F5D ^ +749C4C0856CC4629DC397678C0E8BDCBD649A6E2 ^ +25327C66FF46C4466F81EE635E8EC02C5CA60F2A ^ +BD9DFB59EB5E53BA6988734FBE0894194A119D33 ^ +3084040E5ECA5E77406B4DF3CB7F324ACC96B506 ^ +1E14A09FEDB61CEBE255B94F533C4018E5AF4BAE ^ +C8840C051A204F8A13420CF17FE77EEE2FD7945D ^ +4790265B5231F9A1738CB9F8423BEEF219DF110D ^ +354947C0F2F25EB491D21BD0BD1D809FDD140A66 ^ +23762BF3CDF3F484C70D2003B55E6F447BAF46FA ^ +E5BFC99555CED5C1743B152A64AE08C9ED1365D6 ^ +4CB44DC507F716BED4B4CAC742E79E1A2DFA308F ^ +62790EC14E8CFD1A0D6FAF93D7984A1E9416FD5C ^ +5C2D3ED988F5BD9579D2F710D5DD68B11584295C ^ +CF8414ED85FA0135E44B37A8F8B40756BAED23DF ^ +03432064C1C05D28393C9AC5878C9A9BAA6E5C7E ^ +C37A6D64CF81CDF7DBB1B81509A67A0A1BB5F278 ^ +F341D89B75E599048A911D0AE756E0065669B4FB ^ +269E1529285414A74B76586EA4FCECA895C7D1EC ^ +FF9BB39F9FEA1EA63D944BF12ADC98D1D4255096 ^ +DD114F2DF3D92977F9DB98AEC04F367CFF9FBA2D ^ +69B53BB13375F9E123FC30098CD9EDB3C1A1FDF8 ^ +2A60984DC79682E96C29CC7050E1ACF988D9E4D6 ^ +09AC4CA1A40A7D83A463AF0804C4EDA208E09D36 ^ +A2EE2473C270A0637FAAF17DA54237D37E0C6960 ^ +B3A7817ADE962DCEEA7FB6F960EBE2BC1F9BCBA7 ^ +85A46CCE01A7968104496225483ECE2C198F2A27 ^ +BC028F5ECD8773AE47563F1216E0BC36A9E37E4E ^ +C65C40CCC3DD80045D6A4EFF3E9C7D6E4E0E5583 ^ +BD9C189A639FD3D70167367DF61F14868CE7E313 ^ +C6899A84B8E66548BFB50781632CC3D2D1BE8B9E ^ +92F3C8E436227976F32F005469DE91B2363150DC ^ +7D2A80A5C5CC88988F38334AFFE31C04AA1AFC9C ^ +D60FACFA57F663C4A399B1FDDD75973910F27294 ^ +CEEB9661BED2E89DDB07A21EEBF590BB1AD644A0 ^ +0465C9DF2E0886AC79F46BBBEB0A243DF7D6BAAA ^ +98073013597B7AE84CB884BD932E20E6CB47709C ^ +3CB4F76B602BF6B58B316A2D8D169D432F02CE23 ^ +5CD4EB05E8612974BD9C3B19E48D192BE8B96A09 ^ +BB188D5FDE806BD30648B6058143F1802F15FA10 ^ +84EF1D3DE5C1144C2C928CD4D9070A6E79543417 ^ +73BE2AA66F5FD6BF63273EA136350D29491A3305 ^ +53CF3BB07761910BBB486C3C0C643943D5BF17C3 ^ +9A774BDBD27C3704871B52CD5F7F924C8EE4A67D ^ +B106B6582F0F6C9E2EFBC4860CFC7028F2C47F74 ^ +FEAFF44298CBB7517B14B81A6AAD501828C773A0 ^ +B5BB48BED969F15D162301966C537A81C40CF4B3 ^ +3495D7E36747B824D33465B5DB72D6C623EDA72F ^ +D7F49178B43847D9984B923DEAA6DE9571690B92 ^ +3AB7E26BDB0409E55063AFFF456B7A29CF098AF0 ^ +7984E1565BADCD2249EDCA0A3AADB4346104A556 ^ +42DD99B41801B0C347580DF1FDFB2397D55D2A85 ^ +8D59C00401EFB314A0DFA4D82E1D85711C77E246 ^ +50CF74894F7CF5A9F37C37B47327047E910D88A1 ^ +1FC40E2840C4B68F40C205B6BB06C3E106B6B8D8 ^ +A49F56DFC293411736F27C19FA2A362A545C761E ^ +221E48845FE8B3D2C79AFED37414C0D732A69F4F ^ +AFC12E7BDF9F48FAB1B595FD656776A39F0F6CA8 ^ +5EAA114491E88938276FC3ACCDE659623C024BD7 ^ +5081444C3F81E18114B289020D9AEC75FB205597 ^ +D4F69156DE85C61E9B4150AC9F6F6A54F8E193A6 ^ +3D7C7EF4D362DE137AF0625925B36837C1FC7572 ^ +575D772F9C1CBCA8FF38243348E0DFE02643C28C ^ +0C821F27FD82C55CB4D76D386F41DDC92F79493E ^ +C3D0101DDF552A11C8E1EE6BFADB72A983F38571 ^ +F4D650440127390F3A3C2EE991C185CE7650FAEB ^ +54460FDAFEF3022BC2C7D1D497CBE5CED73624C2 ^ +9B3F7B9D594AAF6A26F5C21BD6E4717F46267418 ^ +14E2B34F0B2C89DAE1732400C02E2CA19A767F8E ^ +1072ABC4DFD2FDC6C114314D3C08457772421713 ^ +C9EA4B020C11DEB794D1D05957473A46A906B472 ^ +90BA4272464A020612F0085B7DB9367B7BA8E15E ^ +8713A3997A3CD5DA87E97AB94851B68E748268CF ^ +370358D54C819703E20EF63A2498C8586B48D44E ^ +0DE40249A8B215E98E849008FB7CAE80EC23F4A6 ^ +BBDB96306594D13598BB0109258E488D486D98E4 ^ +DF7DB9CB2FD8A86854C5DEFCE59C4E2F0245F582 ^ +84DE32ED88B3D2BD5F4E33BA3398CD2EC1E9BDF3 ^ +D20967844FED11CA71D28D72B28ACFDB14A7DBB2 ^ +B13A0A6A7723BCD9098E2B04FA04320C4A0E605D ^ +BE66BE38F97E7DDB02EDC8E0ACE97CDF83F034FE ^ +28ECC25FFB394AA8DE18F8ADE8B3577955346FBB ^ +45068B6A0F61D0AEF708AF7D848683DABE817C2C ^ +EAAD829C32C3AD4EAEA8B7E6090A5CF6B2FCAA82 ^ +F445FEB22DF5A9E49E2CF7AAD7CC1F5F72F18B77 ^ +73C424FA0B7863F1F170A850F6A0F85C87820841 ^ +71F0155D40CC55F3D64BEA645608FD184E2543F2 ^ +4542FFCF50267B77502D1A0ED0C2A5050CAD5200 ^ +FB48F26F320D7A4B803ED459BDF92BC1F8703631 ^ +C9F9A37E34BEA6220BEBC167E34B0BAC6B55A6B6 ^ +B0C836CC2831FB8BFE5988360CC39FAA6A904A89 ^ +B0CF783D84BF5383EF30EF2071E0FBA9ABB553EA ^ +8411C8D1A4FC3F130143DEC5232B59BBDDF11B7C ^ +ACB6D9EB22D474CFD5836C8CE22F387E12DC20B7 ^ +D582FA3DE1DC425AE6A394FE5AC321DFE96B9305 ^ +15CA32D0E246F395DE22FAF8F0FD90036C4016C8 ^ +F1832FEECBFFF1330C7A6AC47D6FC1880E79550D ^ +C4846BEA159D1D43427CB5802C46E479F9157392 ^ +C84FF09BA6A2EE9BD1972B8C0BF25240F5A7EE72 ^ +4E6B4F363D7FDB4083AA6F5E7979966FB8FF6C5A ^ +7A543B81CB4DC93081D8CB6AED436A31C4018A84 ^ +85990A1C35B86BA244F60BA0EBD6F6E801552FD4 ^ +D3E07F5D14AE219D3CB59B034764C40056BA95F4 ^ +F4C4DCCC63E8FC5402E93CF50533E51D1BECED43 ^ +3806AFF9AD3859B150F1E2A40FBC047FB624CB14 ^ +B51A4E4FA213D22548CFF28323C6679D2693110A ^ +A7C70C19BAC1040698C7AE6A23B0688B58405153 ^ +E74FD8C457581CD09F75EE3D43485130609FA9B7 ^ +86ED1E49D4CA868934D7C254D3AE0D5BF7323CD7 ^ +A16507DABC3A0CF7137150C4E6F88D5AC9A0AA3C ^ +DDC76D7BA54354112C2D7D31E1A80F0048551E5E ^ +D943F6028146EEB0386BB3084FD354CE86ABCF00 ^ +4ABCAB65C7DAA52BDBD13BCC9098643F5A165329 ^ +D75FE22162C538BA1E2687D66E2923CEC7375E01 ^ +1A11A2B12D93FB030B0C3441D7AAC06DAD6FB527 ^ +F8F3D414C26D09C6CA1B88BE44BE69AC879D3C5C ^ +D2D0BC98795740002B2EB6EA6AECA5559340B54B ^ +A8A3838BA45AB6B05D1D464E8681AD61B136B6A5 ^ +5B162923200439D870F57AEC584A67CA2E8939B9 ^ +A8FE0B55CFB15D977E871152905D8FDB18AA6B59 ^ +02D5D4928969C7A852B5A8AC772A3D1EB424C9A3 ^ +4ECE08DFF1FDE1258B1BF0423E1E31D83C57557F ^ +F701430EF6CB54BF0D138B54FB13A1B586A1CDCC ^ +E3242A71106CB77D25A60D164BD17FE07EAC4951 ^ +D8B18DE86132672EDB330190BE895E3106F92D2C ^ +8CF05FF1387C61A8CC3724BB1283AAD3E2F85EEF ^ +797B311DC2B5D14B5277E49A38A787D3D6A58C2D ^ +6472BC5881A62BA95651DBB3DFF9B3885949C9B6 ^ +86AED4B53D8617FC135D0E1FCB762271B2545A45 ^ +E3C888A1C00301AA7CE203A5590D82C1CE77C6D4 ^ +8A081A7A672F91493AC09D95B29FABD043DA83DD ^ +D47F87022DB4FAE551FF3FA09FFF02D92D112527 ^ +B2271E377E9B158ACBCA1EDAE0ED6BA4C59CB722 ^ +71EDE0C9488A21E62456D06EE393F390478C3F31 ^ +437A1B709176598020EBA1E92386C3979A18915D ^ +E3F4AC4384848071C8A9F9868376D941DEC2A9FB ^ +00444CAF6A3F4210FD97DCB8F10F43B28D890600 ^ +9B6BB350E30CEE209C77A3E20BB6ACE867546313 ^ +935D2688AE2B16B79B517BFB79D48CE7E4F0F4E9 ^ +16B21F19ADE7B6DEE665D45A847491B7F055C46D ^ +853397C3565C807AE72EDFA37F4198E801103FD4 ^ +10992C2FFE5127006BAFB2172359701AB10FA4BE ^ +C82D6BA4BA621E36872ACEE4AE3BDF33C2381B07 ^ +D7852DBC8FF592E08A1F1EE57A70BEFF327D8EBD ^ +CF67308422F072415EFB75B43D5B67C7F5362B0D ^ +30DDF35E1E99243F85311A0994D91B8AA543F729 ^ +DB2FE340F62A89400AE4A16B61435204405350D3 ^ +744980FA26DE503743EED298B966ED5FA8471DF6 ^ +D2C8B803D3DDB54CDE6464D126CE3009A9F0FB73 ^ +885700ECC04EB97943A9C100EB6EC4ACFE59DF81 ^ +770F9CAC5D4E9C878A6636EB0306EE8DDF0CF915 ^ +03C3F0553D7CF16CFE3D3F01C0A4CE26A914512C ^ +93B304BDB138DB6790DFF8A84FFF3D3506770CDC ^ +D5C5FA0488C5A6E14770F216B575997950A94184 ^ +2F695B8EB18C28250D7C8B35BA000042EABDB245 ^ +0353FFA7F7085D3B7888F96B8498486EE7DE16CD ^ +239FE3AAC0D3739F5EEEC82B2BF6F5F47D058548 ^ +16DE8684395CCA8A5DBAC72ECFAFA4BC3DBFC5D6 ^ +AEB2BA742708DBC048B01FD77B1560CD3A23E707 ^ +FAAE178B97175A7A68E51BD7EEC06234723B670A ^ +B3F1311247D920110972772C3DC30F789D3FDBAB ^ +466F682842C07D2C770B41B66A66BE9F6651C046 ^ +39724BD29138F776ED20633B66A3A241FACD817E ^ +5931F19A1985CD5F7171A5D2B81CE1CB3BA8EBBB ^ +27DE5C33A18DF1A731051D6644DE8900E30E242E ^ +A4E1C4F20A34C033589ED0985E80168A28C2377A ^ +9BE820B134475CA31513EE1C79D06E299D70E017 ^ +98F396D147EDF3D3079A6B2DCDDE92D48C9CC52B ^ +D6108901909418CF7E7AECD9E4D1CA121E992E90 ^ +F2E8F0FF1C652356E6056644B81FF8270A07F56A ^ +EA1669ED509120F2B42CFA547A3FD6002FFB862D ^ +219BAB55653B03A3CA7886212DF27B23C082B2E0 ^ +BBE95F8BBEEB6F9A0062D151A7155630F2010B88 ^ +FF6BFC90FE3EAB299892A5D9CA4D17DF2C6C604E ^ +8D0E1DBFCC419AEB1C7827C7649333E34AC7E30C ^ +EF3847F7FEA054F0E080836D0F2BFB676E3573EE ^ +F60A15E6A28A5CCC9C4EFB1B3107A54C9AAEC26C ^ +76328CDE5EFE6961B2CED4E3457D219229E161F7 ^ +FFAF03FB632A042B837F8660412B72B1099394B1 ^ +211BA6675C52CBD9E7F5F5B366A64A2466532AA7 ^ +51E05B7481381358782FDF73CB958E1434CF3330 ^ +BB5CEAD1F3B68227CB032B2B8E5B627461071637 ^ +3EBCF1D78998D4D11C094BF28FD522EA9F5A1E37 ^ +3E7186CB1D39C64CEFD28BDA2CCAA073E71A5327 ^ +415B6A0083386054D3B77026A38654D45D3BA106 ^ +2297372256479E31E139AA16E63C27C207519C0C ^ +65A79FC4B322F655ADCF63432D295349FDCA9E7B ^ +2D1130EE6E4156151C637B46527FAC54D9E79DF7 ^ +80E18DE7C798F040C008B3BFE3054261740E1444 ^ +0710A3A300290CC1C3BAB56CF00A682C1B711BB7 ^ +C6BE5E337A1A976C253CBF356687F359548B6A3E ^ +3D6E4E514277223BADE6A317C478F17EA6EBC9DC ^ +25C66C904C35EBAD2613A30B73283E0FC23CCC10 ^ +125709FDFD511180B08DB77366DC7E5A2B46F0CB ^ +AFB5C53BB272826DB7A1C030B89C7F3AE956F65A ^ +D166E71D8142E26E58E0F7A69C50CF19CFE225FC ^ +426007235D8F06FDCFF20CE7FD00E994F2FC422C ^ +8CA2730163EA816BF9B63CC653B443A8E8BD7656 ^ +BB2DA623B5FD10032BAFA1A2F9FB1E13F74AC4EB ^ +82238EC3C90BAF3227885BE78534A1B08213660C ^ +64BA275EE9422356EAC19A46A4C5C9BDB4D63C05 ^ +4995323B85FD3879631B439BF4F8D7D39639A7FA ^ +41F95B512991A4E05B219479842285900DF8425E ^ +3CEBE929AC763F2FD85F21354C9158E5169A844E ^ +BAD5D53D67CBCD7767B6009546A91D59188DE99D ^ +E9C2909F6F0A3079890193C8772E745A317C48B0 ^ +BB97E31E9B8EAA8CE758DD775D8326F94720E198 ^ +109471A1C3A427C65C4BBAF8C785DB99C748E5FA ^ +751D9CC64F00176E424A1F331C63EAF2910A75CB ^ +27EC395B07FC740569612741E5CF13A9A6048010 ^ +F674BD87556FD0F71D9BF23A0ECCE9F39AC82099 ^ +93B2F9109A25C511865D15E1683C0683555FFC01 ^ +SHS Type 2 Hashes +EFA3EC89797EE3F1A5BE4B8D34747136CA7DFB99 ^ +D146D467E321E4EA4C73E8424029BEA461F3D90B ^ +25ACD32DED334AD20DDCCF01059B6B8B864E8D7A ^ +25416D69665007C3EDD24161F3DF0F6ACBD0E859 ^ +542A29E5C04A5B79AD0986FAD49BE741F09942B9 ^ +5B197E1011286E5C130F9379843DE89776C37C59 ^ +467277EB8887EDE0F2369C6E7D12281EE3B51857 ^ +BC1610204E15A37D533B74412683767898B35DFF ^ +3DC7C4726B3EF75AB89193701C990F86AA6DE80F ^ +4AD4348E5022685C70A2B9806698664C281E7123 ^ +A33E4996BD9980ED505F8AAAF0F6D64E97D7E619 ^ +06280ACC2D0DA15EAD7C963253349C86A6C3C6C4 ^ +33BE29779F42EE504A3CDAE0422F7B9C5CC994DE ^ +412941272C5CE344AC144B69D4BA5F61F1474F4E ^ +C33ECAC1FA74D54685669F8B9F85918471A88D60 ^ +C48272E42F921A2749D60418965D8A7CB1C7BF0D ^ +44ABEEAD2C278098062D934460E565ED3C646880 ^ +08DF185007816E3EF01D6226C72B03256478F23F ^ +289E89F8F15DD709701AA22B12C69E8F90C93F1D ^ +5B93CAB369C99B85EEE3130F833B7BB06D4FC041 ^ +7B2872C58FB340C9A1D068B618E4980B04FDFF2D ^ +62783421CF58EA66366ADDCBFA96968FB1369918 ^ +C8BD732D0181051698160B2FBC2025476297C96B ^ +038D587CC069C9B89DBC2FE9D86A98C031D340B9 ^ +3059031A68585DA8F09B87B0BE3413987EB390BF ^ +1B74A4A95713083609B27E67140708EDA15F80B1 ^ +6EACEA69922C7ACE38E0560A91DA459C0CC89B55 ^ +60E21F5299EC719D2832A82268B24AF6B2815DEB ^ +3D7D51782A532F4F410AA2AB3DC9178C21A55F0A ^ +B2423D96008FB800E5E35E19DA6BEA27487585E0 ^ +5038FE9AEAC82966A4EE5CC69ACC8ACCF55E63DC ^ +90BF0A90F88F5F1DA51E4494E2D5D4C6250D2D4B ^ +F858434E0A5FD61A220CC792380801D19E0D9F77 ^ +C31E0BB45FF1DC0DE44C77C53C59B15C3BDE9EB4 ^ +DF5628CF6445C409B51F46A86488A95DD34A3DA5 ^ +744CDCC9A51B1AD14FAFD673D4104433B7A24739 ^ +CEA5E7B91773DFE13649ACA78907769B5BEBCA1F ^ +DC23EC1A04F7417D9704B844E9F39F39EAABE6D8 ^ +D39DDE97297B7D1C9FFD6B6733349D0B8E802688 ^ +65219E79F5A3C61FC075660258A9C5F13A159271 ^ +D2A86164D1366B60F146651464761B01353F9028 ^ +8E3D1E4E0438EABC58AB967B1CDDDAE3CDD9B078 ^ +EE9BEEC73D0E760CFD05CF62382A461C7DE3CE2A ^ +5C4FDD604751596BE5419D4AC256C3D982012149 ^ +43ECD0DE83F087815CF257982914611E4BFF698C ^ +1A1BCA41BA127DF4264D3795E2EBCEDCD1BD8EC7 ^ +FF82BC6904520E186803FFE861DCE7E566D75F03 ^ +764546FFA014DF8278974BE66D01485251B8B0CF ^ +A06BC97DACB07EF207808684978841C425AE1238 ^ +6C7E6E0E89F2A070EDF3C4333353869942F3D883 ^ +572437B2B35C5BA00EBC74521B12D20E6F14ACBC ^ +08703186E74A9397CEBB1B2034A6770995AF3D0F ^ +E4F9055356AABA933EEF0C0B07B6FCE90361D208 ^ +2020203EFD4C5FFA02E593B7A658024B33FB368E ^ +2BB2F32D64ADA56A3E53A6D750A05F8D2B5D7A7D ^ +C719AEE4708E7A242440C9429B7236DFDEC02B4B ^ +924A26B46649287197E142CB42506C96E309EB26 ^ +0463F94B5452A2D8BA3A0DBFE9C490A371C19975 ^ +9FB2FE5393238EAAF58034BC934B190784A10DD3 ^ +AD4A6962A6A59CA32789AC3BBA368583B9122AF4 ^ +2A89459657F9E2685D794E7AEAF30A05B06AA573 ^ +9B65CB91D0A24773AC8675FE9862E28A7B84954F ^ +9CB7CADEDD391A3689B04427B461C4113717B6C8 ^ +F1B922D7EC240FC99692EC28C1A6CC7D907B1018 ^ +DE301A1413C36A5CB891FBCD9CF9258DF4EF14A4 ^ +B330738D2AD53448C287BEEFE5C5583F2B817A03 ^ +B80EBE0104A25840CAEF6AD74C4676D524571A29 ^ +3B5CD01661A279BA72DFC1272E683573B4F16DCD ^ +1412D6A2DBBC9D00641A71164A690C640852B56E ^ +0EF514429CAC95CDCBE8A2E60C2AA8B892AC5B33 ^ +5F32CFF3B07D47EC13EB54E7C39E4F5216FDBDC5 ^ +B931966169D171DE8F9488E8B5E0960124BC7451 ^ +E5034D3A5A573442781EF0C6EEA7BD39FAD0B94A ^ +F97CAC5013135944FDF8BDCF02B4CC61241BEA6A ^ +FF74C93CF32506B4E17A0B596AB564989F20F1D4 ^ +5CA42E33BCE4301B8FBCE56BFBDB43EF79E956D8 ^ +87F5D981EDFA01A2E9885BD52CC4E649A2330621 ^ +63F43844ECDDF338203DFB116FA79CBAF4E5C92B ^ +92C5E2A5D380D2BB5E19E9E65DC9A77F4B8B25F4 ^ +E3D78501969ACDD78A71042E7B0BD0C14882E402 ^ +4E1FD6F5CFE29A0E33248F2E2EFB74E7E0A99765 ^ +5FF5DADC93B2E452A60677C8CD0CBAF7BD4895E4 ^ +CA490FAA2D6723F9F682D5C96586460D0C8B2010 ^ +94F099C2FF7DB694FD2DCF5A9A6B06855B2A9948 ^ +CF3B1E0DA7BE87180BF1847DEBEC706788C53B8B ^ +F85305C4BF149B92068D363EF19B914DB90618DA ^ +B4BAFCA3176B80E9800E319FB3BB74E5D65BEB64 ^ +38CCF51915A38559A96E6F3258148D5E63230984 ^ +6FF43B0D25C7171FF178DEAB13D7F488D21C4216 ^ +3E4A034152D86E4568A2197A5328E8E97363287E ^ +F231D4C3ABBE0FDF77C71EB2C28E50ACD9584537 ^ +23E1A4F73F288233847E647CF8623289F1F89E55 ^ +726DAEAE724E79232611CBB216B7722594E814FB ^ +0E5FE512B0AF52B4183119508CB01AF5338C63E3 ^ +4A5D3E12EB29B224202C0B319B086535E99F5E32 ^ +363574A910830EDCFDAED1055975F0613D1B5C95 ^ +4820BE6C74AD34D8A43A5DD0130CBDE3F890C53B ^ +FEB6E5BF7A66ED9B838A10305F850052DDF9207E ^ +D50B331AD6925545264B6614C3B4C39375AB1F65 ^ +36B1BF39BF4AEF05FB054BD02FAD9062D2337239 ^ +SHS Type 3 Hashes +9B30CAFDD7F5E525221EC036D55A9C8D78294DBD ^ +9BCA33B3DAD2201D0F1981CCD0AF4874E162A6DB ^ +8B06697E4A75DA5F020CEB860A29040B3DF6EF21 ^ +F0D48401AE22498E281CDAAF045FFEBAA87A9776 ^ +6247DF62DF5D4857A795996039B5A6271F7A2031 ^ +D98433C3372F1405FCC2475959B9F35DF27D32E9 ^ +C4D14B2873B0BDF01CA7C1628EE01D61682CF1C8 ^ +C027A9C010F8EBE89FC88C1C9FB68DAB09A0CFCD ^ +4D8D19F35FAECDEB015E116130A0A4C836A42A6A ^ +928E2E95D3F09D8EE63CB8F10296EE6EF7455FFF ^ +55F3E770DCA28CFB711D059174CC7A9EC2B2DD7B ^ +4500987086FD8C275330E0F27E8A3ED8596D01AA ^ +60BC57D16F50E2ADD1724E0C7DDD5E47DDF8E300 ^ +59D174272AE602AC092EE7EF393AC19B87B8E865 ^ +8C25614E6E4D825D6AEDD93A62D1A0458583EE84 ^ +695390D1E57BCC4CDD442879F0978BD823322E5C ^ +6F353EE6B5F4B8272E4A0D3D4BBCC83B1B942516 ^ +4B3F671874220DCCF49B580189E6B13FFF0F531D ^ +BC6C473B4824D8E2FA04DDA86A5865D4A36E8E91 ^ +1BFEC269FD18D25DC5C56ACD83810022775F3EC8 ^ +3E9921E2F685413C0AEA64801945B48CB76E195E ^ +EEC7221FBAC5F27B56CF68C396B7EBBCAA3C0B05 ^ +F86DDD2A8229532C3F183EA9903AD228A2521593 ^ +FA17B5DF33E4326BCDCB27F1CE8B83BE8B8EF890 ^ +A4AFC0B41D30CE796C2B4B06E368A5D390735889 ^ +745AF12B4EF985E4D2F848D7C7ADB6B32404B6E6 ^ +5CE4B657409033BF67DB7B0CA480EC2ACCA801EC ^ +0B5AABC9D3A8E861103D6B5B9B994F9C743BF058 ^ +86A1198983A73298BF4EB41A61EAAC3E4B06B408 ^ +460A107A6AF329B330DE9425B3077755553AD370 ^ +62C81D06AFE8C8F3E642AD42374FFE486DE86F2F ^ +FC1EECA32F7E434BBC74F4360808EDB141087BDC ^ +BF494B4E8D3311F167B1EAAE58A3343683F337EE ^ +961247D01E1C4CC0D71307637CD559D530521FD5 ^ +B34F846411BE61E15361922E0E2AF83F3F03B291 ^ +CD845B240FC2551DCB2CE487646648CF249AE8F0 ^ +5C124B615FAC548DAA35AD0287E032EC77D220BD ^ +3C74771D838CCF7FAE2DAB100CEA7B46BE2FFF3F ^ +62860DB8C0C897C7369A1AB61747B04C0AE9F8A6 ^ +C98400CDD7FE71C7B35488C16D3395C04300EDFA ^ +95167E2BBFC0349C0DB7CB7BD2030BC30F9F286A ^ +9F835DBB27076B5F0D8880603F417CE83A0D2242 ^ +08442B715C84B7A8B2C7FFB46010AE56A0C8C05D ^ +B7132DBA522C54F42903CAEB705167485AAD30B0 ^ +9E99F03ED08374EFA4F9A26551A909F40BEE503C ^ +999977E6AFFAE0451E93E7F77C7D177DE121402C ^ +30E0BB7F21433A348E3B446F08D80CEAAE06DB71 ^ +B3A41EEDF017DA7B20FBD9111BA6E2E59842CED2 ^ +5B9CA331BD03D97E8D057DFD35C9E600F90C57DC ^ +5338A25B31CC9C64552B6F6742F9FEBDC13D9733 ^ +1B3A55BF6FD748B3B650EA5BE839B61530C871C0 ^ +1503F21523CE8BC5A19E6A7F5CB0EC34A7E9F75C ^ +7F6A16B30377D3D0014B0B0B4C8639160C721DDB ^ +8F621F8CFB6AF216746D8B99C913267DB14ADB08 ^ +42E9177C487B4B711A4451C360BD7E2C6DA73446 ^ +5B2497CA6EC2426B12653D711E6BFDBEEFD4A389 ^ +30F4690FD4F09AC8E29B926F64C673539D7FB65D ^ +CE12D1AA4961245E606097B672EC3E16103D0D16 ^ +9BE5D693BC0CC56B34B8DDB92FACEC2F8F4B638A ^ +D2040005AE230EFDAE95942372607577EFA5DBC2 ^ +8A920F9407C74FA37D9C93C3606B996DB945841D ^ +F26915C08DC1D3D31D9CA73F18F04DBB57E8A672 ^ +E449381C8148837B9E44251B17825530D8754C94 ^ +BD8402B21520E40E31D1EAFD9C99A9E409C3A77D ^ +624CCE538A78CF0FF788B9BE433A008FA7779280 ^ +B796B521B90D55396E8EC02AD9B69B7E91093E4C ^ +5C4D584F97C1D8FAF810CEF3A4CA0915FB0B630A ^ +A179FEAF341BA97B1D0278822ACCAE5FCF8F4ADE ^ +693DCF85919E06A5423F92780E79C2C0C4528D67 ^ +DB94BEADFEA3682051D622519AF9F87BAB28C5F9 ^ +2E20D1925FBD460E7A5E6B48A92964A7DDCB874F ^ +86651FD71862CF72F01F099F68CC164DEF0E9625 ^ +D5948BDCA91D6707015C79BBC2BC74C1B60573F5 ^ +8870B8A6884FF54E0E400441FB2EC74F2452F39C ^ +7DF1C3C052E8396D251E9D522C4227344DF92C11 ^ +59A290A0BD41B973DEE35947CB240006DBCEC582 ^ +DD0EDB3AA60CDEBB85DC01258B9F49F3A5E83589 ^ +FC6794E4B4F2735773A195F9BB2022C70AA4C754 ^ +8BBC40A02D87A8CF14D6CBA0A2C9857D93EFDEFA ^ +D28FF6E2366097135EE565F10263E8798140C5DC ^ +2E4289EBE02E75E53B52D6724CDC16B89ECF3DC6 ^ +F2E716831CC0CB5CB2A623197D14C2C9FC25A914 ^ +47B926A13D65377A8E2AF27A84E175BE93739E38 ^ +D368B8ACC50353EC8070936C73242A2BF6CEC3AA ^ +8556025BED695B975CB924DDFB372F6899A7B09D ^ +9B4ED89E63D17B7210A3FC1BBF0FDA607694F5D9 ^ +0D2221F5CDA184EC7F6CCA29A75F502FCA25673A ^ +3C152CCB811DD9BC16529B23DFA1757D744FE676 ^ +48D1808CD62F868FB6F45560137CFB1DFD856266 ^ +8A3FA42A984C95CA75D6AE51391AAAC0688C2ABD ^ +AB570D91E9B6F3F1188DC8639A3B144837EF1ED8 ^ +673F62A7D205D5C90B7454E81A5EDA9A60650D91 ^ +D00575E45FA324FA05142359BC3A07C803836EE4 ^ +B908BE44A2A66F7370DCC022378A9C2F9BA70B38 ^ +1EF79029F88E7A091D6F2FA2F44A96829C120C62 ^ +491CB2EE0994EE6A4FAC59C4B9FBC9CF8183DE8C ^ +CEAAC4E211E7DDDCE3931C47ACA3D626B62E5054 ^ +BE2041CB55A4882A8335A46B744ECB8611336F5D ^ +E4C0BC6857AFFE0C2B77B38FC01829B44247B6CC ^ +122A6AF11DEB6C3B97E6ADF5E077B5D6363887E3 ^ +SHS Type 1 Strings +0 1 ^ +1 1 1 ^ +2 1 1 1 ^ +3 0 1 1 1 ^ +2 0 2 2 ^ +4 1 1 1 2 1 ^ +3 0 2 2 2 ^ +4 1 1 2 2 2 ^ +5 1 2 2 1 1 2 ^ +5 0 2 2 1 1 3 ^ +4 0 3 3 3 1 ^ +5 0 2 2 3 2 2 ^ +5 1 2 3 3 1 3 ^ +5 0 3 3 3 2 2 ^ +6 0 2 3 1 2 3 3 ^ +7 1 3 3 3 1 1 1 3 ^ +7 0 2 3 1 2 3 2 3 ^ +6 1 2 4 3 3 3 2 ^ +7 0 2 4 3 3 1 1 4 ^ +8 0 2 3 1 1 2 2 4 4 ^ +7 0 2 4 2 3 1 4 4 ^ +9 0 4 1 2 1 1 2 4 4 2 ^ +8 1 4 4 1 1 4 2 2 4 ^ +7 0 3 3 4 3 4 4 2 ^ +11 0 1 3 1 1 2 1 2 4 4 4 1 ^ +6 0 4 3 4 5 5 4 ^ +7 1 2 5 2 4 5 4 4 ^ +12 1 1 2 3 3 1 1 1 4 2 1 5 3 ^ +11 0 2 3 3 3 1 2 2 4 1 5 2 ^ +8 1 3 3 5 5 2 5 2 4 ^ +9 1 5 4 5 1 2 1 5 3 4 ^ +9 1 5 1 5 2 3 4 4 4 3 ^ +12 1 1 2 5 1 1 5 5 1 4 1 5 1 ^ +12 1 5 3 2 1 3 2 2 2 1 4 5 3 ^ +10 0 5 1 4 5 5 4 1 1 3 5 ^ +12 1 1 5 2 3 1 5 1 3 3 5 1 5 ^ +12 0 1 1 2 3 2 5 1 3 3 6 4 5 ^ +11 1 3 1 5 1 3 4 3 1 5 5 6 ^ +8 1 4 6 4 5 4 4 5 6 ^ +10 1 6 5 4 3 3 3 2 6 2 5 ^ +10 1 2 3 4 4 5 5 2 5 6 4 ^ +13 1 3 1 3 1 4 1 6 6 5 1 2 6 2 ^ +10 1 4 3 3 6 6 6 3 2 6 3 ^ +13 0 3 5 3 1 4 1 4 3 5 3 4 1 6 ^ +10 0 2 5 5 2 6 6 5 2 6 5 ^ +12 1 2 2 5 3 6 6 4 3 2 4 3 5 ^ +13 1 2 6 3 6 5 2 3 2 1 2 3 5 6 ^ +13 1 3 5 6 2 1 1 6 2 4 5 4 5 3 ^ +16 1 2 1 4 3 2 3 2 5 3 4 1 4 1 5 3 5 ^ +11 1 3 1 3 6 7 7 4 1 6 5 6 ^ +12 0 2 5 2 7 5 5 4 2 2 6 7 3 ^ +13 1 6 4 4 1 4 2 5 2 4 2 7 4 6 ^ +12 1 3 4 7 6 7 1 4 4 3 2 5 6 ^ +16 0 3 2 4 5 6 1 1 1 5 3 4 1 4 4 5 4 ^ +14 1 5 1 3 7 6 3 1 3 7 3 1 5 7 2 ^ +14 0 1 5 3 2 7 1 5 5 4 6 5 3 6 2 ^ +14 0 4 7 6 6 2 3 5 1 1 3 6 2 3 7 ^ +13 1 6 4 6 3 7 5 1 4 5 1 7 4 4 ^ +13 0 7 5 3 1 4 7 4 2 2 7 5 4 7 ^ +15 1 7 3 6 1 1 2 7 5 1 5 4 6 1 6 4 ^ +16 0 2 5 3 2 7 2 3 5 2 1 3 3 3 7 5 7 ^ +18 1 3 7 2 4 1 7 3 4 1 5 1 5 1 1 6 1 2 7 ^ +17 0 2 1 7 3 7 1 2 1 4 3 6 6 6 2 2 5 4 ^ +22 1 2 2 1 1 2 6 2 4 1 1 3 5 2 3 4 5 6 1 1 2 6 3 ^ +12 1 7 8 7 2 1 3 5 7 8 7 4 5 ^ +15 1 3 5 5 2 2 2 7 4 2 8 7 4 5 5 4 ^ +16 0 1 4 4 6 1 2 7 1 6 4 1 8 4 7 4 6 ^ +16 0 8 7 7 2 5 2 1 5 6 1 1 5 1 5 6 5 ^ +14 0 7 3 2 3 8 3 3 8 2 8 3 7 7 4 ^ +14 0 4 2 6 5 4 5 3 8 8 4 8 2 6 4 ^ +14 0 8 7 1 3 5 8 2 8 1 4 5 2 8 8 ^ +16 0 5 5 2 2 4 2 4 7 6 1 5 8 3 8 7 2 ^ +16 0 1 6 6 6 6 4 2 2 6 4 2 4 4 6 7 6 ^ +16 1 2 3 7 4 1 7 7 5 7 2 4 7 2 6 6 3 ^ +13 0 7 4 8 6 5 7 6 3 5 7 5 8 3 ^ +16 1 4 1 1 5 4 3 6 5 5 8 5 4 8 5 3 8 ^ +13 0 7 4 4 5 8 3 8 3 8 6 6 6 8 ^ +14 1 5 4 7 5 8 4 6 1 6 2 7 8 6 8 ^ +18 1 3 4 4 5 3 4 1 6 3 7 6 7 3 3 2 8 4 5 ^ +19 0 5 8 1 2 1 3 5 3 1 6 6 3 7 4 5 7 1 4 7 ^ +17 0 5 7 7 2 2 6 4 7 1 7 8 1 5 3 2 7 6 ^ +14 0 9 3 6 9 3 4 7 6 9 1 7 2 9 6 ^ +21 1 8 6 5 2 2 4 3 1 1 6 2 8 4 2 5 4 5 1 2 5 6 ^ +16 1 2 6 5 4 9 8 1 8 1 7 6 7 7 1 2 9 ^ +15 0 6 9 5 4 7 1 7 3 9 4 7 7 5 2 8 ^ +16 0 1 7 8 2 7 2 9 8 8 3 4 5 2 4 8 7 ^ +16 1 1 6 8 2 8 1 6 7 7 5 9 2 9 2 8 5 ^ +16 0 4 2 9 6 2 6 6 7 9 9 1 9 4 1 5 7 ^ +18 1 6 9 2 7 2 8 5 8 4 3 4 4 6 6 3 1 6 4 ^ +19 0 1 7 4 4 4 6 1 6 3 9 5 6 4 7 2 2 5 5 8 ^ +17 1 8 5 3 7 3 5 6 4 1 9 2 6 5 7 9 1 9 ^ +18 0 8 8 6 3 5 3 3 5 5 3 8 3 2 5 5 4 7 8 ^ +16 1 4 7 7 2 7 3 8 5 7 5 6 8 5 2 8 8 ^ +19 0 3 7 2 3 9 5 9 7 7 6 5 3 1 1 5 2 3 9 6 ^ +18 0 2 4 6 7 8 1 2 9 7 2 3 5 8 9 1 7 9 4 ^ +21 1 4 1 8 3 3 1 7 3 5 7 4 1 8 3 6 3 5 7 6 8 2 ^ +17 0 4 8 3 7 9 8 6 8 4 2 8 7 2 4 4 5 7 ^ +18 1 3 9 7 1 4 5 6 9 2 9 1 3 8 4 7 8 7 4 ^ +25 1 2 4 8 1 7 2 7 5 5 3 2 3 2 1 2 1 1 2 4 2 8 7 8 7 4 ^ +25 0 9 4 6 5 8 1 1 1 3 2 1 3 1 1 1 5 3 3 6 5 7 4 5 6 8 ^ +19 1 7 5 6 6 8 2 4 1 8 7 1 6 3 4 8 5 8 5 6 ^ +19 0 6 1 2 1 7 1 10 7 4 5 1 6 4 6 8 7 10 9 6 ^ +16 0 10 10 5 5 9 7 2 5 4 3 6 3 10 10 5 8 ^ +18 1 2 3 5 9 8 5 10 6 8 4 2 2 4 7 9 6 9 4 ^ +18 0 5 10 3 1 4 5 4 6 8 3 7 7 7 5 9 2 9 9 ^ +18 1 4 9 7 5 4 4 10 6 9 3 6 6 8 6 2 4 6 6 ^ +17 0 5 7 4 8 5 9 10 4 9 1 4 8 6 6 5 9 6 ^ +17 1 3 4 8 9 1 5 8 10 5 10 3 8 1 6 8 9 9 ^ +18 0 8 3 6 1 3 10 3 7 6 5 9 3 10 9 4 6 10 5 ^ +16 1 9 1 9 6 5 7 7 10 9 6 1 5 7 10 8 9 ^ +20 0 6 4 10 10 4 3 9 8 10 3 3 5 2 1 8 1 3 2 9 9 ^ +17 1 10 6 10 6 8 3 6 7 3 10 8 6 6 4 4 9 5 ^ +19 1 9 4 3 4 7 3 8 10 2 4 10 7 6 10 1 3 5 7 9 ^ +21 1 2 2 2 3 9 2 8 3 9 3 7 7 4 9 9 5 4 2 6 10 7 ^ +17 1 5 9 8 8 9 10 9 1 8 3 10 2 7 2 10 4 9 ^ +23 0 5 4 10 4 10 7 8 3 1 1 3 4 2 1 1 10 2 1 4 10 10 10 4 ^ +19 0 9 2 5 7 9 6 7 1 8 9 1 2 1 10 8 10 4 7 10 ^ +22 1 2 6 8 8 9 7 2 1 3 3 10 6 2 6 2 6 5 2 5 10 5 9 ^ +22 1 8 7 8 10 1 6 3 7 4 5 5 5 1 9 2 2 5 5 2 10 9 4 ^ +21 0 1 10 2 6 10 9 4 3 3 7 10 2 9 6 10 2 1 5 6 3 10 ^ +21 1 8 5 7 10 5 6 7 3 3 1 2 9 4 8 6 3 9 1 7 7 9 ^ +22 0 5 5 6 5 2 3 5 3 11 4 5 1 10 6 4 11 8 3 6 5 6 7 ^ +20 0 2 1 9 9 3 6 1 8 11 6 7 11 6 1 10 6 7 5 5 8 ^ +19 0 4 1 7 10 4 8 10 8 10 4 11 9 6 1 4 5 6 11 4 ^ +19 1 9 2 4 11 11 11 7 1 1 6 8 1 9 8 5 11 5 4 10 ^ +20 0 8 3 10 1 7 6 10 8 2 9 3 8 6 8 9 3 7 5 1 11 ^ +22 0 4 5 8 4 10 6 5 4 5 3 3 4 1 5 9 4 10 9 6 7 3 11 ^ +21 0 6 5 8 7 8 11 2 1 11 10 3 3 2 9 1 3 6 9 10 10 2 ^ +24 1 3 1 1 9 4 2 5 7 3 10 11 5 6 7 1 7 7 8 7 2 2 7 4 9 ^ +23 1 9 4 6 3 7 5 10 9 8 9 3 2 1 7 2 2 7 6 2 8 3 6 10 ^ +22 1 7 10 2 10 5 1 8 7 7 3 8 6 6 8 3 2 11 6 3 4 7 6 ^ +20 1 11 3 7 2 10 10 7 5 2 4 3 5 11 3 11 8 9 5 5 10 ^ +19 0 6 2 6 8 5 9 4 9 10 9 8 3 2 10 11 2 6 11 11 ^ +20 1 8 2 4 2 7 3 9 9 11 8 2 11 4 8 4 8 10 6 9 8 ^ +21 0 6 10 10 7 9 2 5 11 9 10 7 3 1 4 5 4 10 1 2 8 10 ^ +18 1 8 11 6 10 8 9 11 6 7 7 2 6 2 6 10 6 9 11 ^ +21 0 5 11 1 6 8 11 8 10 5 10 3 7 8 9 9 1 1 1 10 2 10 ^ +25 1 5 10 2 9 9 9 7 2 2 4 6 1 11 7 3 3 5 5 2 11 2 5 5 10 2 ^ +21 1 1 8 1 11 6 9 3 6 11 7 11 8 6 9 4 4 10 7 1 8 7 ^ +23 1 7 7 5 11 1 4 7 11 11 11 9 2 1 3 8 2 8 7 4 5 2 5 8 ^ +24 1 4 11 5 10 7 7 9 5 1 5 6 2 9 1 5 7 9 9 11 1 1 3 1 11 ^ +27 1 10 4 6 8 5 7 11 4 10 8 6 4 3 4 4 2 1 1 3 3 1 11 2 3 4 10 6 ^ +21 1 7 11 2 7 10 10 9 10 1 3 10 4 3 11 10 2 5 3 9 11 4 ^ +22 0 7 9 10 9 5 2 6 6 9 2 7 4 9 8 4 9 2 5 9 8 10 3 ^ +21 0 12 2 6 12 7 9 3 5 11 6 11 3 5 4 4 11 10 2 1 10 10 ^ +27 1 1 4 12 2 10 1 6 5 5 4 1 10 3 1 12 3 2 11 5 1 4 6 4 6 11 11 4 ^ +22 1 8 9 4 8 12 5 5 9 3 5 2 3 4 12 12 8 5 3 1 9 10 9 ^ +24 0 5 12 8 6 2 4 11 11 2 7 11 9 4 5 2 1 8 3 10 2 5 2 8 9 ^ +21 0 3 7 7 7 5 9 11 5 9 11 2 9 7 5 6 11 2 12 4 9 7 ^ +26 0 4 4 6 4 7 2 4 2 5 7 2 6 11 5 9 8 2 5 10 2 10 8 8 5 2 11 ^ +23 1 3 3 2 6 9 10 5 6 8 5 8 11 3 6 10 4 6 9 2 11 10 3 10 ^ +25 1 1 3 12 3 7 4 5 5 3 8 9 2 4 8 7 7 9 1 9 11 4 5 7 7 10 ^ +20 1 11 9 8 10 11 1 7 12 6 7 4 2 12 12 2 3 9 10 8 8 ^ +20 0 12 11 1 4 10 6 10 3 9 7 12 4 11 8 4 6 12 4 7 12 ^ +24 0 8 6 4 8 2 2 9 2 9 6 3 6 3 3 10 12 2 7 8 7 8 12 10 7 ^ +26 0 5 11 11 7 3 3 9 10 3 9 3 3 7 2 9 9 1 2 4 12 2 5 5 6 10 4 ^ +22 1 12 9 10 10 12 12 7 8 2 7 1 6 8 2 8 7 6 3 1 1 12 12 ^ +22 1 11 10 2 11 10 8 1 2 8 12 8 3 9 5 7 9 8 7 11 1 10 4 ^ +22 0 10 1 8 6 12 2 11 7 10 4 10 6 5 7 10 11 3 3 8 8 4 12 ^ +26 0 8 5 5 12 1 8 6 7 6 11 8 10 4 3 7 6 1 5 1 1 9 1 5 8 9 12 ^ +21 0 1 12 4 11 12 9 2 12 12 3 12 5 4 12 4 1 5 8 12 9 10 ^ +26 1 5 3 8 1 11 4 7 3 3 10 4 9 6 6 4 3 9 11 1 3 7 10 7 9 6 11 ^ +23 0 7 12 3 5 8 9 7 10 8 11 10 11 6 1 8 1 1 6 3 9 8 12 6 ^ +25 0 1 5 5 6 5 12 1 1 1 11 9 9 3 11 9 6 1 11 3 1 12 8 11 11 10 ^ +22 1 10 9 7 3 10 2 6 4 11 3 11 6 4 5 5 11 12 9 7 8 12 9 ^ +22 0 8 5 10 7 12 8 3 4 4 5 8 9 12 6 8 10 6 7 11 4 8 10 ^ +26 0 3 5 3 11 11 2 1 9 1 10 4 4 6 9 4 7 6 5 10 10 1 8 9 9 6 12 ^ +24 0 12 11 4 10 1 3 7 5 11 9 11 7 2 11 5 4 7 8 1 6 12 7 4 9 ^ +28 0 1 12 10 2 2 2 4 9 11 4 11 7 2 4 3 11 7 10 5 10 5 5 3 5 2 7 5 9 ^ +26 1 4 1 4 2 13 6 11 5 6 8 5 1 5 6 3 8 1 5 8 9 9 10 12 13 12 2 ^ +26 0 12 3 1 11 2 12 6 8 6 8 11 4 11 10 9 6 3 3 2 2 2 13 2 1 13 9 ^ +22 0 3 3 12 13 13 7 12 2 8 11 9 10 10 1 1 13 11 13 4 1 11 3 ^ +26 1 2 6 2 8 12 3 7 12 8 9 8 3 12 7 4 9 2 6 4 9 9 4 8 2 4 12 ^ +24 1 8 11 11 3 13 2 10 3 10 8 6 6 4 4 13 4 2 4 8 1 11 12 9 10 ^ +29 1 1 2 5 1 1 10 3 2 4 9 11 8 2 5 2 8 10 2 10 11 7 8 12 6 1 9 8 4 12 ^ +23 0 6 12 7 10 7 7 13 2 2 7 10 2 8 13 10 7 11 2 5 9 11 13 1 ^ +25 1 3 11 2 10 5 11 5 7 10 8 10 1 10 3 11 7 9 5 3 3 4 5 13 12 8 ^ +26 1 5 13 9 4 3 3 4 3 13 1 6 11 10 8 13 3 4 11 9 1 9 1 7 8 7 11 ^ +22 1 1 3 13 8 11 3 4 10 10 12 7 2 11 4 7 7 6 13 13 9 13 11 ^ +26 1 7 9 7 8 9 9 5 1 13 3 3 4 9 2 1 8 9 3 9 12 8 10 10 6 11 3 ^ +23 1 3 8 12 8 10 4 3 8 5 5 7 11 13 11 12 11 4 12 3 6 5 11 8 ^ +27 0 3 10 9 6 9 7 2 10 4 4 5 5 2 12 13 5 3 1 10 1 4 7 8 13 13 12 3 ^ +30 0 2 6 5 4 7 3 10 6 13 6 3 9 6 2 10 5 3 8 4 1 11 3 5 3 7 11 1 12 9 7 ^ +29 0 5 2 13 6 5 2 6 3 2 9 5 3 6 6 4 10 2 4 7 7 10 13 9 6 10 6 5 9 8 ^ +31 1 9 8 2 7 3 5 11 3 7 7 5 6 2 1 1 6 2 11 5 4 5 7 9 1 11 10 2 3 9 12 10 ^ +28 0 11 1 4 1 12 10 5 5 1 7 2 3 10 7 12 9 2 8 2 6 10 5 12 12 4 9 2 13 ^ +26 1 11 9 8 12 4 12 7 3 4 4 6 1 2 7 12 4 6 8 10 11 11 1 10 2 9 12 ^ +28 0 10 9 7 10 1 10 9 12 7 10 7 6 6 5 3 2 3 1 3 12 1 4 13 3 9 7 9 8 ^ +27 1 4 11 1 5 6 9 12 12 13 13 13 1 2 13 1 2 1 12 12 3 2 2 8 3 13 7 7 ^ +29 0 6 5 5 2 4 2 11 4 4 13 9 13 7 3 12 8 3 7 6 4 12 3 1 8 11 1 6 13 6 ^ +23 1 11 6 6 11 7 13 11 6 7 4 4 12 2 13 5 12 5 7 9 6 11 11 11 ^ +23 0 11 13 11 7 4 3 6 12 13 10 11 5 12 13 11 6 1 1 4 7 13 10 7 ^ +27 1 7 5 13 5 4 8 7 3 9 6 7 11 7 1 9 3 8 5 8 8 2 13 13 8 5 13 4 ^ +30 1 2 5 8 4 13 10 6 4 2 6 1 1 12 4 13 5 10 4 10 8 5 7 1 5 5 12 4 8 6 12 ^ +28 1 12 1 12 11 10 2 3 10 1 2 6 11 12 9 11 12 2 1 9 4 1 5 7 2 12 11 4 11 ^ +29 0 6 8 7 8 8 12 2 7 4 12 11 5 5 3 5 13 4 11 8 8 9 2 2 1 6 2 8 6 12 ^ +28 1 7 13 5 7 11 3 1 9 2 5 12 8 6 2 5 9 10 10 11 4 5 12 5 4 6 5 6 13 ^ +25 1 14 4 8 2 9 11 7 4 3 2 8 14 6 14 7 13 5 5 14 6 5 11 6 6 13 ^ +26 1 3 5 12 1 11 13 1 3 3 10 11 5 6 12 11 12 7 14 4 3 6 6 10 11 14 4 ^ +27 0 4 2 3 10 7 12 13 8 8 12 10 13 1 7 10 2 7 2 13 10 2 3 3 6 4 13 14 ^ +24 1 11 1 9 14 4 14 14 8 10 13 4 3 2 7 6 6 8 14 5 11 7 14 14 1 ^ +22 1 13 13 10 9 13 8 14 9 3 14 3 11 9 9 12 13 2 10 1 5 8 12 ^ +25 0 9 10 9 8 4 14 6 9 3 13 10 11 3 1 4 6 10 3 4 3 12 12 14 11 13 ^ +26 1 11 8 11 7 8 10 9 12 11 6 10 6 3 9 9 1 7 5 6 7 7 12 4 5 8 11 ^ +26 1 12 10 8 14 7 4 13 13 8 4 5 3 2 4 7 14 3 10 6 9 13 9 2 1 9 14 ^ +28 0 6 12 2 4 7 8 11 10 12 2 14 3 1 1 1 12 5 13 9 12 5 9 10 5 1 12 10 8 ^ +29 1 2 6 5 14 14 3 6 13 1 2 6 2 12 1 2 10 1 4 5 14 10 12 11 2 3 14 14 12 5 ^ +30 1 5 2 3 5 11 12 3 7 12 7 9 8 3 3 14 10 5 2 9 3 8 6 11 8 7 8 1 6 12 7 ^ +28 1 14 5 2 14 7 8 1 5 4 12 9 6 12 1 1 7 9 5 14 11 9 4 1 10 1 14 10 12 ^ +27 0 7 2 8 5 3 14 8 9 4 6 11 3 11 6 12 1 7 14 9 14 6 10 6 1 8 14 10 ^ +26 1 6 14 2 2 12 10 5 10 10 8 3 7 13 10 1 14 1 14 7 11 12 9 1 8 8 12 ^ +30 0 6 13 5 13 3 5 8 8 8 2 5 5 4 2 13 14 7 2 12 12 3 3 5 7 5 11 3 7 13 7 ^ +26 0 13 7 2 8 4 10 14 2 7 1 10 8 11 11 2 13 9 11 2 9 11 7 13 11 2 14 ^ +31 1 7 7 8 5 13 4 1 12 14 1 9 11 3 5 3 13 11 7 3 2 9 1 3 13 6 3 10 12 1 13 3 ^ +23 0 9 8 8 7 14 13 6 13 14 12 13 12 7 4 14 10 1 3 9 7 11 14 5 ^ +27 1 1 10 4 12 4 11 5 13 13 4 12 13 7 12 12 4 13 6 2 7 5 2 8 7 13 12 3 ^ +26 1 7 6 11 12 14 12 3 12 8 7 4 9 14 1 8 11 6 5 10 10 6 8 5 2 11 14 ^ +33 1 1 11 1 5 3 8 1 12 14 5 1 3 7 2 3 9 3 4 14 4 4 10 8 5 14 1 11 12 12 10 4 13 +2 ^ +32 0 11 4 4 9 5 5 8 9 5 10 4 2 4 7 9 9 6 3 5 1 8 3 2 13 3 14 9 8 9 10 14 5 ^ +28 0 12 9 5 8 7 2 14 12 3 8 14 6 6 4 7 5 7 10 7 11 10 1 9 6 7 12 8 9 ^ +25 0 9 9 2 11 13 12 11 11 6 14 13 10 5 6 8 10 4 3 11 11 14 5 5 10 7 ^ +30 0 13 9 14 11 4 8 12 9 5 9 1 2 9 13 12 6 1 14 11 10 7 8 6 1 4 3 2 2 2 13 ^ +33 1 13 5 9 6 13 9 1 13 2 6 8 9 1 3 12 13 3 4 4 12 5 2 1 12 1 6 2 1 8 2 14 13 9 +^ +32 1 8 6 7 1 4 4 6 1 13 3 3 1 13 7 6 11 6 4 9 10 4 8 13 1 9 10 12 7 10 11 10 5 ^ +30 0 12 6 6 3 4 13 1 4 11 10 2 6 14 6 9 12 6 2 2 11 9 13 4 7 9 14 2 11 8 7 ^ +26 1 2 11 13 2 9 11 8 11 11 15 13 13 3 15 2 12 1 15 3 8 4 9 13 1 13 7 ^ +32 1 9 6 1 2 2 1 15 3 15 1 10 1 4 11 14 14 6 10 2 5 9 10 10 9 1 2 14 10 12 1 1 +15 ^ +29 1 13 2 3 8 12 5 14 9 8 9 2 14 1 4 6 15 10 9 2 7 9 4 8 7 9 10 11 11 5 ^ +34 1 12 2 7 2 12 8 2 8 6 3 12 4 4 10 1 14 12 11 5 15 3 3 3 14 13 2 2 3 8 2 1 8 +8 8 ^ +31 0 6 2 7 10 1 13 10 6 6 6 2 8 7 6 7 14 3 12 6 8 9 3 11 1 3 10 12 11 11 9 9 ^ +24 1 13 15 4 7 11 13 10 14 14 13 4 11 5 6 11 8 12 13 9 1 10 9 10 7 ^ +33 0 3 1 3 3 4 13 1 6 14 8 3 4 3 2 1 14 14 14 5 13 13 11 10 13 4 3 10 11 3 6 1 +10 7 ^ +28 0 7 9 13 9 15 2 4 12 10 10 4 12 3 8 5 6 13 1 6 15 1 8 9 6 12 11 7 14 ^ +32 1 3 1 13 6 4 1 9 4 5 7 1 8 8 11 10 5 15 14 2 8 14 9 7 12 2 4 13 7 4 3 9 14 ^ +31 1 14 12 13 8 4 12 2 6 5 12 9 3 11 8 5 13 5 10 5 2 3 7 12 14 4 1 7 3 6 9 9 ^ +32 1 10 15 7 2 13 5 7 2 5 2 10 7 11 5 5 9 8 2 9 3 3 6 3 13 10 3 5 7 15 11 10 12 +^ +38 0 2 3 7 1 6 3 3 12 5 2 9 4 5 11 2 1 7 6 14 7 14 10 4 11 6 3 11 2 10 6 4 8 1 +4 9 4 15 4 ^ +27 0 7 7 4 14 2 3 14 15 10 7 12 7 5 8 7 15 15 14 10 2 3 1 10 12 15 9 9 ^ +31 1 15 3 9 9 5 4 2 6 14 4 9 5 12 8 1 6 1 4 8 7 10 14 3 10 14 8 11 9 8 10 9 ^ +28 0 14 11 8 3 5 5 7 2 11 4 4 4 6 14 13 10 14 10 3 9 6 9 7 5 10 15 15 15 ^ +30 1 8 13 4 2 13 6 4 7 4 4 15 2 2 12 13 3 14 12 7 11 6 2 14 2 6 6 9 14 13 12 ^ +27 1 13 14 15 12 14 5 14 15 11 4 1 1 9 5 13 10 6 5 5 6 14 13 1 5 3 14 13 ^ +29 0 4 2 13 12 15 7 3 15 5 1 6 7 6 13 1 14 11 9 5 15 6 13 3 6 11 7 15 8 9 ^ +31 0 5 4 4 14 3 13 8 13 3 7 13 7 9 12 3 11 15 11 5 14 1 3 4 10 12 7 12 1 2 13 4 +^ +28 1 12 7 13 14 7 7 1 9 13 8 5 14 2 5 9 9 15 9 13 7 8 9 8 1 12 3 9 15 ^ +34 1 6 12 4 14 12 5 3 15 4 4 6 8 2 11 8 4 2 5 1 15 15 1 15 2 11 4 10 9 4 7 3 2 +15 6 ^ +26 0 14 5 6 5 11 12 14 12 12 11 15 2 14 9 15 1 7 12 11 12 13 14 1 1 12 5 ^ +32 0 2 2 4 5 2 11 12 5 4 12 9 14 5 5 8 6 2 15 15 6 13 11 3 5 15 5 11 3 12 7 10 +8 ^ +26 1 2 15 14 9 14 7 6 15 9 3 4 8 8 12 14 2 9 11 14 6 11 15 10 8 14 8 ^ +34 1 15 7 4 5 10 1 13 7 1 1 8 3 13 11 2 8 15 11 12 6 6 1 3 2 2 11 3 13 9 10 3 6 +12 15 ^ +25 0 15 7 10 2 10 15 5 10 13 12 8 15 3 1 11 14 15 8 15 12 9 6 8 13 13 ^ +27 0 10 8 13 10 15 13 5 8 4 10 10 6 7 13 6 12 12 9 12 2 5 10 12 10 8 15 6 ^ +28 0 5 3 8 12 15 8 14 15 9 12 12 3 10 13 6 11 10 4 13 14 8 9 1 8 1 5 11 12 ^ +29 0 9 12 4 13 15 5 9 11 7 14 11 1 11 7 8 8 11 1 13 15 12 1 5 8 3 8 10 7 14 ^ +30 0 1 5 13 12 14 5 3 6 4 12 15 6 6 10 11 13 9 1 11 6 10 3 7 14 4 14 11 7 8 13 ^ +34 1 1 12 5 1 7 4 6 7 5 11 1 4 7 12 10 10 8 15 13 4 11 15 11 6 9 1 2 15 5 1 5 +12 6 13 ^ +35 1 12 15 4 11 13 3 6 5 10 8 1 3 9 3 11 1 2 16 12 10 6 1 9 1 16 5 6 15 1 12 4 +4 2 15 4 ^ +27 0 15 11 15 5 11 9 7 15 16 6 16 12 3 2 10 16 5 5 7 1 7 11 13 7 9 11 12 ^ +31 1 5 5 5 4 13 13 14 4 7 12 6 4 8 2 9 9 13 13 3 3 6 7 16 7 6 15 5 8 15 6 15 ^ +30 1 6 16 15 11 14 14 4 7 10 3 4 10 3 6 7 14 4 6 6 5 2 7 8 16 2 12 16 10 14 7 ^ +36 1 2 3 7 14 6 9 4 4 5 9 7 12 3 9 2 5 1 3 10 11 11 6 12 7 1 7 12 2 1 2 8 12 15 +16 9 13 ^ +34 1 6 3 12 11 16 15 8 8 8 14 13 7 7 8 2 7 6 2 2 14 7 1 4 2 4 11 11 5 7 2 12 1 +14 11 ^ +29 0 12 11 2 9 8 5 6 14 10 12 5 11 5 3 1 13 15 9 12 11 13 4 14 5 16 3 5 13 15 ^ +30 1 5 16 11 2 6 13 16 3 6 4 9 10 9 8 6 14 8 9 5 13 6 5 14 2 8 15 8 7 14 11 ^ +28 1 14 10 13 13 11 10 13 9 8 4 11 14 11 6 10 10 1 9 13 16 5 3 4 7 9 12 10 8 ^ +36 1 10 15 12 8 8 10 13 5 6 11 4 6 2 3 5 6 11 1 1 8 6 13 15 6 3 15 5 10 1 6 2 5 +2 11 10 10 ^ +31 1 4 14 7 2 14 3 1 12 7 15 13 1 5 9 8 3 3 14 12 13 2 15 12 7 16 12 3 8 11 5 +15 ^ +34 0 10 2 10 16 4 16 7 8 1 16 6 14 9 5 12 16 8 9 4 4 4 1 7 13 10 1 7 10 5 7 4 1 +5 15 ^ +30 0 16 3 8 7 3 8 8 11 8 13 4 16 8 16 1 4 16 11 4 12 1 14 5 1 16 11 8 14 12 9 ^ +33 0 7 9 9 16 11 7 6 1 11 14 12 14 10 9 11 8 11 7 5 10 15 2 6 9 3 9 4 2 1 1 9 +14 6 ^ +32 0 5 8 14 15 4 1 6 1 10 8 1 15 15 3 10 7 8 10 12 4 3 11 15 8 5 3 3 16 15 7 14 +13 ^ +36 0 3 10 12 2 11 9 2 1 4 3 8 10 14 2 11 3 2 4 15 14 5 2 8 16 16 1 5 7 5 9 5 15 +9 11 3 14 ^ +31 1 5 4 14 4 8 3 3 1 10 4 15 15 13 2 13 9 7 13 11 9 1 15 15 15 16 7 7 6 5 13 9 +^ +30 0 14 16 12 1 11 11 7 3 7 3 3 13 4 13 14 5 15 12 5 14 16 14 4 5 9 6 6 3 16 11 +^ +28 1 10 16 10 14 13 6 16 14 3 14 15 7 13 12 4 1 8 4 10 6 1 13 6 14 11 3 16 14 ^ +33 0 15 11 13 8 11 1 15 2 10 9 9 14 8 13 2 13 8 1 2 1 3 12 8 5 4 11 10 14 8 9 4 +5 16 ^ +34 1 12 12 6 7 13 13 12 1 13 14 1 1 6 3 13 2 16 3 1 16 9 9 15 3 13 1 8 3 2 6 12 +8 9 13 ^ +27 0 11 12 15 14 12 10 8 15 9 15 2 7 5 11 8 9 7 16 6 15 4 15 7 11 15 4 14 ^ +29 1 9 1 14 7 4 14 16 11 10 11 12 14 6 12 11 15 7 14 3 15 6 1 12 5 12 13 3 6 14 +^ +28 0 6 10 7 7 9 10 7 11 12 16 9 6 9 14 10 10 2 7 4 15 16 13 11 8 10 15 10 15 ^ +32 1 8 12 1 10 3 7 15 14 9 16 14 1 15 3 14 9 2 2 12 14 7 3 5 14 5 15 10 2 14 1 +15 8 ^ +33 0 9 16 10 16 6 13 1 6 2 8 13 5 7 2 15 11 12 6 8 7 1 5 8 13 9 4 8 12 9 15 1 +10 13 ^ +30 0 10 4 16 4 13 12 2 4 14 6 11 3 15 8 4 12 3 11 16 16 16 2 13 7 10 2 13 10 15 +10 ^ +33 1 16 2 15 10 4 1 13 12 12 9 12 7 16 4 12 4 2 16 4 9 16 8 2 6 15 2 3 4 9 12 6 +8 12 ^ +34 1 13 11 11 4 9 13 14 2 9 6 8 6 10 11 9 3 12 9 13 4 10 3 5 1 14 11 11 16 1 2 +2 11 6 14 ^ +33 1 15 12 6 5 16 2 14 2 10 12 2 5 5 6 10 13 12 3 10 8 16 9 5 12 15 4 11 13 3 6 +5 10 8 ^ +35 1 1 3 9 3 11 1 2 16 12 10 6 1 9 1 16 5 6 15 1 12 4 4 2 15 13 15 11 15 5 11 9 +7 15 16 4 ^ +36 0 16 12 3 2 10 16 5 5 7 1 7 11 13 7 9 11 2 5 5 5 4 13 13 14 4 7 12 6 4 8 2 9 +9 13 13 4 ^ +35 0 3 6 7 16 7 6 15 5 8 15 6 4 6 16 15 11 14 14 4 7 10 3 4 10 3 6 7 14 4 6 6 5 +2 7 16 ^ +31 0 7 4 8 17 16 16 11 14 2 10 14 15 10 9 1 14 10 14 6 6 16 3 2 3 8 3 12 8 11 +17 2 ^ +30 1 9 7 16 14 4 11 15 5 13 9 5 12 17 17 13 8 2 6 8 16 1 12 5 17 2 9 8 10 13 6 ^ +27 0 11 17 12 5 14 9 11 9 11 4 11 13 16 6 10 5 8 3 17 16 14 1 15 15 15 6 17 ^ +29 1 2 11 6 13 11 13 4 6 7 11 11 12 16 13 1 16 16 14 16 2 4 16 11 6 15 7 4 17 +11 ^ +32 0 5 7 6 3 14 16 5 17 11 13 1 1 14 13 3 6 14 5 17 5 4 8 14 3 16 7 13 4 14 8 9 +17 ^ +31 1 8 12 8 15 9 6 6 1 5 13 16 5 8 4 6 10 6 11 16 17 15 15 12 4 13 5 3 4 10 15 +16 ^ +33 0 7 15 16 12 12 11 8 13 14 5 8 1 11 10 9 3 14 3 1 9 6 15 12 16 4 5 9 7 1 9 4 +8 17 ^ +36 1 7 9 16 11 11 6 13 7 1 7 8 1 14 12 2 7 4 5 15 16 12 3 1 6 11 4 15 8 9 9 2 1 +13 2 14 14 ^ +29 1 6 8 8 15 13 13 10 2 16 12 17 6 7 14 13 12 13 3 14 12 12 2 15 2 5 15 10 7 +15 ^ +38 1 5 15 7 8 10 10 1 11 2 4 3 11 11 3 5 2 3 11 5 12 12 8 6 2 17 15 6 16 15 4 3 +14 6 3 2 10 5 15 ^ +30 0 12 11 15 14 2 16 14 7 6 15 9 3 11 8 8 5 16 2 16 2 16 6 9 6 12 10 16 7 15 +10 ^ +36 0 11 5 3 16 1 15 7 10 17 10 10 13 2 2 17 6 2 5 6 6 10 12 2 9 11 12 6 1 1 8 +12 2 6 16 12 16 ^ +30 1 10 17 5 1 6 14 17 8 12 10 11 16 15 1 8 3 9 13 7 7 16 8 13 11 10 8 15 3 15 +12 ^ +31 1 14 8 4 12 1 6 5 13 15 3 5 11 14 11 14 17 5 10 17 7 8 13 5 12 15 3 6 17 7 +17 7 ^ +31 0 12 3 10 10 4 13 13 8 11 13 7 17 11 1 10 1 5 11 11 9 14 13 15 8 14 2 7 16 +11 8 15 ^ +32 1 7 16 17 17 4 1 13 15 5 1 5 6 14 15 1 5 1 9 9 17 12 13 12 7 12 3 7 15 4 16 +12 13 ^ +36 0 8 17 1 11 4 10 2 6 10 3 16 16 2 7 13 9 15 7 17 14 3 10 16 13 6 7 5 2 1 4 +16 3 10 1 15 5 ^ +32 0 4 6 4 15 11 4 2 17 9 15 5 10 7 12 15 16 15 17 12 14 9 2 13 4 9 2 4 15 2 11 +9 16 ^ +29 0 4 4 3 17 2 14 17 17 1 17 13 11 15 17 4 9 15 8 11 16 9 10 8 9 12 15 1 17 11 +^ +35 0 16 4 2 14 14 15 1 2 12 9 1 10 16 10 11 7 1 12 17 8 2 15 11 1 7 17 12 7 3 7 +6 9 9 14 6 ^ +36 0 2 15 17 10 11 9 5 9 4 17 16 3 11 2 10 12 11 5 3 8 17 15 3 3 4 7 2 1 10 7 +14 4 16 6 12 8 ^ +36 1 12 14 6 9 3 17 11 10 6 8 14 6 11 7 10 8 6 17 4 4 9 8 2 8 14 8 7 14 1 3 6 8 +11 10 17 1 ^ +39 1 12 14 9 4 11 7 6 6 13 14 2 13 1 14 9 7 7 15 2 2 5 15 13 17 3 15 16 9 1 1 2 +3 2 12 1 3 3 13 9 ^ +34 0 13 10 15 5 8 10 15 10 8 7 5 5 14 4 13 11 12 4 4 12 10 13 12 4 10 3 3 7 9 +13 16 9 17 1 ^ +36 0 4 12 1 9 12 13 5 10 1 3 15 4 1 13 17 1 8 9 6 12 4 7 7 10 17 13 17 6 17 9 6 +9 3 5 17 10 ^ +34 0 1 4 10 12 17 14 11 8 5 16 5 5 2 13 13 16 9 13 10 9 9 5 3 13 6 4 3 9 15 14 +14 7 3 16 ^ +38 1 9 17 3 6 5 16 10 14 9 1 16 7 3 5 4 17 14 7 12 6 2 8 8 17 7 2 4 5 7 12 2 1 +7 11 3 14 9 15 ^ +41 0 2 12 3 4 1 4 1 16 10 5 16 8 7 2 10 3 5 9 16 8 16 13 3 12 5 5 11 2 2 7 4 2 +8 16 4 14 5 14 10 4 17 ^ +36 0 6 1 2 7 1 15 13 1 17 4 7 4 8 17 16 16 11 14 2 10 14 15 10 9 1 14 10 14 6 6 +16 3 2 3 8 14 ^ +32 1 12 8 11 17 3 9 7 16 14 4 11 15 5 13 9 5 12 17 17 13 8 2 6 8 16 1 12 5 17 2 +9 14 ^ +29 0 10 13 14 11 17 12 5 14 9 11 9 11 4 11 13 16 6 10 5 8 3 17 16 14 1 15 15 15 +14 ^ +32 0 13 2 11 6 13 11 13 4 6 7 11 11 12 16 13 1 16 16 14 16 2 4 16 11 6 15 7 4 +17 6 5 15 ^ +35 1 6 3 14 16 5 17 11 13 1 1 14 13 3 6 14 5 17 5 4 8 14 3 16 7 13 4 14 8 9 3 8 +12 8 15 11 ^ +33 1 6 6 1 5 13 16 5 8 4 6 10 6 11 16 17 15 15 12 4 13 5 3 4 10 15 12 7 15 16 +12 12 11 11 ^ +40 0 13 14 5 8 1 11 10 9 3 14 3 1 9 6 15 12 16 4 5 9 7 1 9 4 8 5 7 9 16 11 11 6 +13 7 1 7 8 1 14 10 ^ +34 0 2 10 15 10 14 8 18 9 9 12 12 3 13 12 6 4 9 17 13 13 5 7 3 2 1 17 14 4 16 6 +13 1 13 13 ^ +35 1 6 10 1 3 18 3 11 7 9 5 7 11 17 1 9 16 5 15 10 17 3 8 15 17 8 15 11 3 15 17 +11 1 1 4 15 ^ +36 1 14 18 4 2 18 8 15 6 4 6 3 15 11 16 10 17 17 9 6 3 2 6 16 4 9 12 6 8 1 11 3 +2 12 2 14 16 ^ +37 0 4 1 5 11 16 18 16 8 11 15 2 18 7 5 14 5 15 13 3 3 5 4 3 11 4 4 5 10 3 12 +17 1 4 17 10 10 17 ^ +35 0 1 3 4 2 1 12 5 14 11 10 4 6 14 9 1 5 8 2 9 15 12 13 7 16 2 13 17 15 9 18 +15 9 13 16 17 ^ +34 1 18 10 4 11 13 9 6 1 17 6 8 6 5 11 5 14 16 9 13 11 10 9 15 4 14 7 14 3 1 15 +5 5 18 16 ^ +34 0 13 8 13 16 5 17 5 10 1 8 8 12 6 13 18 9 6 17 3 16 2 8 9 8 7 2 14 14 8 10 +13 9 11 11 ^ +40 0 7 11 4 6 9 10 11 12 2 14 1 13 1 7 1 15 7 9 8 2 1 4 9 14 17 8 17 15 3 4 15 +15 2 2 3 16 13 2 9 12 ^ +33 0 14 6 6 5 2 13 4 16 11 3 10 18 2 15 5 9 4 8 4 18 18 17 18 3 14 12 9 11 15 +16 1 9 16 ^ +32 1 18 5 10 6 7 17 7 12 3 13 8 12 3 8 9 3 17 12 8 18 6 14 3 6 14 14 10 14 13 +17 18 8 ^ +36 1 18 12 17 9 17 2 12 5 9 12 1 18 10 5 5 2 18 3 6 16 18 3 1 2 10 15 2 5 8 16 +10 14 3 9 8 13 ^ +33 1 16 14 1 16 15 16 17 4 12 12 16 5 3 9 14 5 7 17 12 11 12 18 14 2 7 7 15 8 3 +5 1 8 13 ^ +34 1 7 6 7 14 9 15 15 18 16 3 10 5 16 6 8 11 4 1 10 1 16 4 12 17 15 14 8 5 4 6 +4 17 16 16 ^ +38 0 4 5 18 18 12 9 3 9 6 9 7 6 10 15 4 9 17 5 17 5 6 1 6 2 8 17 7 7 4 4 13 16 +3 4 10 16 12 13 ^ +33 0 16 7 18 3 3 11 9 13 14 15 18 2 12 10 3 15 3 1 10 6 15 13 17 13 5 9 7 11 9 +5 18 15 12 ^ +33 1 16 11 1 6 18 13 8 1 18 8 1 5 13 1 18 5 15 15 16 12 13 2 17 12 14 17 8 1 10 +12 10 4 18 ^ +34 0 5 6 18 18 7 10 13 14 10 12 7 4 10 8 16 16 15 5 13 14 4 14 2 4 12 6 11 5 17 +8 5 1 14 16 ^ +31 1 17 9 11 2 11 11 3 13 13 11 12 13 5 12 12 11 6 13 4 18 15 12 18 6 6 7 15 13 +12 14 16 ^ +38 1 4 11 2 5 6 12 10 2 7 15 11 8 14 7 16 16 1 4 3 9 14 16 3 18 1 7 17 1 7 3 16 +17 6 16 12 5 3 17 ^ +40 1 10 15 18 10 8 10 2 5 11 2 7 3 5 6 7 1 12 2 9 2 4 15 1 11 11 17 3 3 16 8 3 +11 18 16 11 6 15 8 8 13 ^ +40 1 10 3 17 7 10 18 13 14 8 7 8 14 2 2 8 6 3 7 5 6 9 5 12 10 7 6 5 16 4 14 2 +15 3 15 9 15 1 9 7 12 ^ +35 0 14 15 12 7 2 16 18 8 18 1 13 12 1 1 14 14 13 3 14 7 2 10 10 11 14 3 12 5 +13 6 17 14 1 11 13 ^ +34 0 7 12 8 12 17 17 18 17 13 2 4 7 5 1 15 7 14 17 11 6 10 9 18 9 14 13 3 8 4 +13 8 7 13 7 ^ +35 0 4 16 8 17 10 2 13 10 2 2 6 2 3 18 17 2 17 4 18 7 16 18 14 4 11 7 4 15 17 6 +11 11 14 17 4 ^ +37 0 10 17 16 13 15 14 6 1 14 11 8 16 6 2 16 13 7 8 6 2 15 1 9 12 4 4 11 13 7 2 +11 9 18 4 5 4 18 ^ +39 0 2 14 9 9 1 8 13 11 15 8 5 9 10 16 9 2 7 1 1 17 13 6 11 10 8 5 12 15 6 15 +10 12 4 18 1 2 8 11 15 ^ +32 1 16 10 12 18 11 16 12 11 17 17 4 7 13 7 10 7 10 6 1 12 7 18 11 18 2 10 15 +10 14 8 18 2 ^ +40 1 9 12 12 3 13 12 6 4 9 17 13 13 5 7 3 2 1 17 14 4 16 6 13 1 13 6 6 10 1 3 +18 3 11 7 9 5 7 11 17 12 ^ +36 1 9 16 5 15 10 17 3 8 15 17 8 15 11 3 15 17 11 1 1 4 3 14 18 4 2 18 8 15 6 4 +6 3 15 11 16 8 ^ +39 1 17 17 9 6 3 2 6 16 4 9 12 6 8 1 11 3 2 12 2 14 12 4 1 5 11 16 18 16 8 11 +15 2 18 7 5 14 5 15 10 ^ +47 1 3 3 5 4 3 11 4 4 5 10 3 12 17 1 4 17 10 10 9 1 3 4 2 1 12 5 14 11 10 4 6 +14 9 1 5 8 2 9 15 12 13 7 16 2 13 17 3 ^ +34 1 9 18 15 9 13 16 18 10 4 11 13 9 6 1 17 6 8 6 5 11 5 14 16 9 13 11 10 9 15 +4 14 7 14 9 ^ +37 1 1 15 5 5 18 13 13 8 13 16 5 17 5 10 1 8 8 12 6 13 18 9 6 17 3 16 2 8 9 8 7 +2 14 14 8 10 13 ^ +42 0 9 11 10 7 11 4 6 9 10 11 12 2 14 1 13 1 7 1 15 7 9 8 2 1 4 9 14 17 8 17 15 +3 4 15 15 2 2 3 16 13 2 17 ^ +36 0 16 14 6 6 5 2 13 4 16 11 3 10 18 2 15 5 9 4 8 4 18 18 17 18 3 14 12 9 11 +15 16 1 9 2 18 6 ^ +33 1 10 6 7 17 7 12 3 13 8 12 3 8 9 3 17 12 8 18 6 14 3 6 14 14 10 14 13 17 18 +14 18 12 13 ^ +39 1 9 17 2 12 5 9 12 1 18 10 5 5 2 18 3 6 16 18 3 1 2 10 15 2 5 8 16 10 14 3 9 +8 10 16 14 1 16 15 14 ^ +30 1 17 19 5 7 14 4 11 3 6 18 13 7 18 18 19 19 13 9 10 19 14 12 4 15 15 18 2 10 +7 15 ^ +34 1 2 13 8 19 15 1 11 14 7 7 17 6 16 4 16 17 2 18 12 5 14 19 17 1 8 12 6 6 6 +19 13 10 16 5 ^ +36 1 14 13 6 16 14 15 4 13 15 4 4 11 4 10 3 17 4 19 6 17 14 3 2 16 1 14 16 5 17 +8 1 1 19 13 12 12 ^ +34 0 17 11 13 5 19 11 18 19 1 3 12 11 8 4 11 13 17 3 8 9 4 5 12 15 12 6 7 16 16 +12 1 13 17 15 ^ +40 0 18 9 3 16 2 16 4 19 6 6 18 3 13 1 5 3 2 6 15 11 6 4 14 15 15 9 13 8 1 9 15 +2 7 5 11 5 12 7 16 15 ^ +37 0 18 4 3 1 4 11 15 7 6 9 1 14 7 1 17 17 16 14 13 14 12 14 9 12 11 18 7 14 3 +1 6 1 15 8 15 19 9 ^ +32 0 3 9 9 7 7 10 12 13 7 11 12 16 9 9 9 17 13 13 2 17 10 4 18 17 19 16 11 11 +13 18 13 12 ^ +35 0 8 15 18 10 6 10 18 17 9 2 14 1 17 18 6 14 12 5 5 15 17 10 3 8 8 1 10 5 1 +18 18 9 16 10 14 ^ +38 1 6 16 1 6 3 5 8 16 8 7 5 18 11 15 17 6 11 10 4 8 14 16 6 7 8 12 12 18 1 10 +4 7 1 19 7 19 15 12 ^ +34 0 1 14 6 11 18 5 4 12 6 14 2 19 2 5 13 10 10 2 16 10 18 16 19 2 15 10 7 18 +16 17 15 15 9 13 ^ +38 1 10 16 4 15 7 5 19 1 15 16 11 19 9 18 2 4 6 12 9 8 7 13 14 11 4 12 13 5 9 6 +5 6 16 11 9 3 15 6 ^ +40 0 16 1 13 6 8 18 11 11 2 1 2 2 14 9 13 1 15 6 5 16 19 14 19 7 18 5 2 2 3 13 +13 12 13 11 2 12 2 12 18 5 ^ +35 0 7 8 13 6 9 8 17 10 11 1 9 14 4 19 19 3 15 13 9 18 12 17 1 16 8 9 15 1 12 4 +4 19 18 13 11 ^ +36 1 14 18 8 14 9 3 4 18 16 9 19 12 3 17 5 10 16 5 8 4 4 10 14 13 4 9 11 19 8 8 +5 1 13 16 14 13 ^ +41 1 10 15 3 4 8 2 12 9 16 3 16 3 6 17 3 10 19 7 6 1 5 11 18 9 4 6 2 15 11 17 +17 17 4 10 13 3 7 10 3 9 14 ^ +42 0 7 9 3 3 8 19 10 8 2 19 12 19 13 6 19 3 4 17 6 9 1 7 2 9 7 18 6 15 2 2 4 3 +10 11 11 6 12 10 18 4 12 10 ^ +35 1 4 5 11 12 15 19 12 10 6 15 14 19 18 11 8 11 17 16 7 7 11 2 10 6 19 5 14 7 +1 7 3 19 4 17 15 ^ +36 1 5 10 2 18 1 17 8 12 17 2 9 8 8 3 14 10 15 2 14 8 3 1 16 18 12 18 11 16 7 +17 5 19 2 19 12 19 ^ +37 0 16 14 2 9 16 2 6 6 7 9 10 9 11 9 14 11 15 5 16 9 2 17 2 8 15 8 4 3 14 14 +16 16 13 11 10 16 14 ^ +40 0 11 7 14 14 14 6 10 10 1 6 13 19 5 6 4 7 12 12 10 5 10 15 15 8 5 13 17 13 5 +6 14 1 9 2 6 5 17 9 11 13 ^ +38 0 18 8 6 13 15 3 3 15 5 13 18 3 2 5 5 14 7 13 4 17 7 2 17 3 18 15 7 15 16 18 +5 12 8 6 3 17 12 13 ^ +38 1 19 15 9 7 17 16 15 3 11 11 5 2 13 19 16 2 4 16 7 8 1 2 9 17 12 3 5 18 19 +11 17 9 1 4 1 18 10 10 ^ +41 1 13 1 7 13 5 7 4 1 8 13 16 3 5 7 6 8 8 14 8 13 7 19 8 16 18 4 2 8 7 12 4 14 +5 1 3 19 17 11 14 15 19 ^ +39 0 10 9 12 19 11 10 3 18 14 17 18 17 7 12 14 8 11 7 2 10 17 15 5 3 12 3 12 1 +2 1 1 12 14 10 2 8 17 18 2 ^ +45 1 4 9 4 16 5 18 1 1 10 10 11 3 10 12 1 3 11 1 11 5 3 3 16 15 10 17 14 15 6 +13 12 2 3 14 3 9 19 4 4 8 10 14 5 11 9 ^ +35 0 2 7 15 14 8 2 11 19 19 4 5 10 8 9 5 15 9 17 19 5 7 14 4 11 3 6 18 13 7 18 +18 19 19 13 13 ^ +35 1 10 19 14 12 4 15 15 18 2 10 7 9 2 13 8 19 15 1 11 14 7 7 17 6 16 4 16 17 2 +18 12 5 14 19 9 ^ +38 1 1 8 12 6 6 6 19 13 10 16 13 14 13 6 16 14 15 4 13 15 4 4 11 4 10 3 17 4 19 +6 17 14 3 2 16 1 14 19 ^ +38 0 5 17 8 1 1 19 13 12 12 17 11 13 5 19 11 18 19 1 3 12 11 8 4 11 13 17 3 8 9 +4 5 12 15 12 6 7 16 11 ^ +43 0 12 1 13 17 4 18 9 3 16 2 16 4 19 6 6 18 3 13 1 5 3 2 6 15 11 6 4 14 15 15 +9 13 8 1 9 15 2 7 5 11 5 12 16 ^ +39 1 16 6 18 4 3 1 4 11 15 7 6 9 1 14 7 1 17 17 16 14 13 14 12 14 9 12 11 18 7 +14 3 1 6 1 15 8 15 19 12 ^ +35 0 3 9 9 7 7 10 12 13 7 11 12 16 9 9 9 17 13 13 2 17 10 4 18 17 19 16 11 11 +13 18 13 8 8 15 6 ^ +40 0 10 6 10 18 17 9 2 14 1 17 18 6 14 12 5 5 15 17 10 3 8 8 1 10 5 1 18 18 9 +16 10 19 6 16 1 6 3 5 8 16 ^ +40 0 8 7 5 18 11 15 17 6 11 10 4 8 14 16 6 7 8 12 12 18 1 10 4 7 1 19 7 19 15 2 +1 14 6 11 18 5 4 12 6 19 ^ +35 0 2 19 2 5 13 10 10 2 16 10 18 16 19 2 15 10 7 18 16 17 15 15 9 15 10 16 4 +15 7 5 19 1 15 16 6 ^ +43 1 19 9 18 2 4 6 12 9 8 7 13 14 11 4 12 13 5 9 6 5 6 16 11 9 3 15 12 16 1 13 +6 8 18 11 11 2 1 2 2 14 9 13 11 ^ +39 1 15 6 5 16 19 14 19 7 18 5 2 2 3 13 13 12 13 11 2 12 2 12 18 7 8 13 6 9 8 +17 10 11 1 9 14 4 19 19 3 ^ +34 1 15 13 9 18 12 17 1 16 8 9 15 1 12 4 4 19 18 13 15 14 18 8 14 9 3 4 18 16 9 +19 12 3 17 15 ^ +45 1 10 16 5 8 4 4 10 14 13 4 9 11 19 8 8 5 1 13 16 14 1 10 15 3 4 8 2 12 9 16 +3 16 3 6 17 3 10 19 7 6 1 5 11 18 2 ^ +43 1 15 4 13 14 3 4 1 3 1 5 11 4 9 7 20 8 15 4 16 7 19 11 1 11 2 13 13 11 12 13 +15 12 1 5 13 3 8 15 12 8 16 16 6 ^ +44 0 5 13 12 14 5 3 1 4 16 12 20 1 6 15 11 18 4 17 16 6 10 3 2 9 9 14 6 2 8 6 7 +10 17 12 20 6 7 5 16 1 4 2 17 9 ^ +38 0 15 8 20 18 20 11 15 11 11 9 6 2 15 5 17 12 1 9 1 3 5 11 7 2 2 6 18 2 9 11 +8 16 11 16 15 18 18 18 ^ +35 1 20 2 17 17 10 8 13 20 4 18 6 18 9 4 1 1 18 5 2 17 15 16 19 15 1 10 17 16 4 +16 14 14 11 15 10 ^ +38 0 5 9 15 10 9 17 18 14 15 12 6 1 16 8 18 8 13 12 10 14 14 13 9 2 14 17 9 1 +20 10 4 2 12 9 4 13 16 5 ^ +36 0 14 10 11 16 17 12 18 12 7 17 8 7 3 1 3 17 4 9 5 17 14 17 11 5 20 19 8 19 +14 13 2 18 3 3 18 13 ^ +41 1 13 8 14 6 18 7 10 1 13 10 11 11 16 1 2 8 7 1 7 14 8 17 6 8 4 3 11 17 3 5 7 +16 11 11 14 7 13 20 20 7 20 ^ +40 1 13 15 14 16 14 8 9 16 5 1 6 3 17 18 16 9 1 15 9 10 9 19 1 3 3 20 11 13 17 +1 19 8 3 4 3 7 1 14 19 17 ^ +37 1 18 13 11 5 18 4 19 10 6 19 11 17 10 10 7 9 13 16 9 10 18 4 12 5 16 5 20 12 +3 8 10 1 18 1 6 20 14 ^ +36 0 8 9 6 12 11 7 7 3 17 13 6 20 17 9 20 16 10 12 17 8 11 8 11 10 5 10 14 18 8 +19 9 12 12 2 20 12 ^ +38 0 12 16 20 3 9 9 19 17 13 13 4 17 2 11 7 14 3 6 16 13 10 13 5 16 10 2 8 2 17 +19 4 17 7 19 6 9 15 7 ^ +41 1 20 7 2 18 5 7 18 5 2 15 7 11 10 9 3 2 14 19 3 11 8 18 15 5 3 5 12 15 16 10 +17 7 19 16 2 1 16 6 3 19 10 ^ +46 0 5 18 9 9 11 2 1 12 11 14 12 14 10 4 11 6 8 16 7 5 11 20 8 17 4 14 4 15 3 2 +2 4 3 2 3 14 15 10 2 12 7 3 7 20 20 5 ^ +41 1 10 2 3 1 10 12 15 14 11 20 3 16 14 9 4 18 1 19 20 9 5 12 13 6 6 1 9 13 7 +15 9 8 5 19 3 16 9 8 10 20 8 ^ +39 1 11 13 19 5 7 16 18 16 4 4 4 6 9 13 10 19 15 3 14 6 4 12 10 15 15 4 8 13 13 +9 18 13 6 4 7 20 4 20 7 ^ +31 1 18 18 12 16 13 19 19 5 7 2 6 11 18 9 18 6 11 14 14 18 10 13 19 20 17 11 14 +5 19 20 13 ^ +46 1 20 1 1 4 13 10 6 5 6 19 18 1 3 9 14 20 7 18 7 15 2 3 15 5 1 1 2 6 13 1 19 +6 14 16 5 15 11 13 3 6 11 2 20 8 1 20 ^ +37 0 4 20 19 3 18 3 8 19 7 8 12 14 12 19 11 15 6 19 1 19 4 10 16 17 7 17 1 2 13 +18 12 2 18 19 2 7 15 ^ +42 1 9 18 8 5 14 2 5 4 4 20 14 13 7 8 14 8 1 7 19 9 7 11 12 4 19 12 10 19 20 4 +4 1 8 2 16 16 8 20 2 1 20 13 ^ +37 1 1 15 7 6 20 10 14 9 12 19 18 20 6 14 6 5 6 17 14 12 12 16 4 2 19 14 15 17 +7 12 11 12 8 14 1 17 7 ^ +39 0 15 18 2 4 10 18 11 17 5 9 17 4 19 5 5 8 6 2 20 15 6 5 18 11 3 10 20 10 16 +3 12 7 5 14 18 15 14 9 14 ^ +44 0 14 7 6 15 9 3 4 8 8 12 19 2 9 16 19 6 16 20 5 3 19 7 4 7 4 5 10 5 1 18 7 +17 6 3 3 13 16 2 3 20 16 12 6 16 ^ +38 0 17 19 2 2 11 19 13 4 15 8 1 12 9 20 2 5 2 10 20 5 15 13 7 13 15 19 17 11 9 +15 8 15 17 9 6 16 8 13 ^ +38 1 18 10 8 8 10 15 13 8 4 5 15 6 12 13 1 17 12 4 7 18 10 12 10 3 15 20 5 19 8 +17 20 13 14 10 9 12 17 5 ^ +46 1 10 18 6 6 15 4 13 14 3 4 1 3 1 5 11 4 9 7 20 8 15 4 16 7 19 11 1 11 2 13 +13 11 12 13 15 12 1 5 13 3 8 15 12 8 16 6 ^ +45 1 17 5 13 12 14 5 3 1 4 16 12 20 1 6 15 11 18 4 17 16 6 10 3 2 9 9 14 6 2 8 +6 7 10 17 12 20 6 7 5 16 1 4 2 17 16 ^ +40 0 15 8 20 18 20 11 15 11 11 9 6 2 15 5 17 12 1 9 1 3 5 11 7 2 2 6 18 2 9 11 +8 16 11 16 15 18 18 3 20 19 ^ +38 0 17 17 10 8 13 20 4 18 6 18 9 4 1 1 18 5 2 17 15 16 19 15 1 10 17 16 4 16 +14 14 11 15 2 5 9 15 10 15 ^ +38 0 17 18 14 15 12 6 1 16 8 18 8 13 12 10 14 14 13 9 2 14 17 9 1 20 10 4 2 12 +9 4 13 16 7 14 10 11 16 19 ^ +39 0 12 18 12 7 17 8 7 3 1 3 17 4 9 5 17 14 17 11 5 20 19 8 19 14 13 2 18 3 3 +18 17 13 8 14 6 18 7 10 12 ^ +41 0 13 10 11 11 16 1 2 8 7 1 7 14 8 17 6 8 4 3 11 17 3 5 7 16 11 11 14 7 13 20 +20 7 16 13 15 14 16 14 8 9 16 ^ +43 1 5 1 6 3 17 18 16 9 1 15 9 10 9 19 1 3 3 20 11 13 17 1 19 8 3 4 3 7 1 14 19 +19 18 13 11 5 18 4 19 10 6 19 4 ^ +41 1 17 10 10 7 9 13 16 9 10 18 4 12 5 16 5 20 12 3 8 10 1 18 1 6 20 12 8 9 6 +12 11 7 7 3 17 13 6 20 17 9 15 ^ +37 0 16 10 12 17 8 11 8 11 10 5 10 14 18 8 19 9 12 12 2 20 13 12 16 20 3 9 9 19 +17 13 13 4 17 2 11 7 16 ^ +43 0 3 6 16 13 10 13 5 16 10 2 8 2 17 19 4 17 7 19 6 9 15 15 20 7 2 18 5 7 18 5 +2 15 7 11 10 9 3 2 14 19 3 11 14 ^ +43 1 18 15 5 3 5 12 15 16 10 17 7 19 16 2 1 16 6 3 19 12 5 18 9 9 11 2 1 12 11 +14 12 14 10 4 11 6 8 16 7 5 11 20 2 ^ +45 0 17 4 14 4 15 3 2 2 4 3 2 3 14 15 10 2 12 7 3 7 20 20 19 10 2 3 1 10 12 15 +14 11 20 3 16 14 9 4 18 1 19 20 9 5 18 ^ +42 0 13 6 6 1 9 13 7 15 9 8 5 19 3 16 9 8 10 20 14 11 13 19 5 7 16 18 16 4 4 4 +6 9 13 10 19 15 3 14 6 4 12 18 ^ +36 1 15 15 4 8 13 13 9 18 13 6 4 7 20 4 20 18 18 12 16 13 19 19 5 7 2 6 11 18 9 +18 6 11 14 14 18 15 ^ +43 1 13 19 20 17 11 14 5 19 20 11 20 1 1 4 13 10 6 5 6 19 18 1 3 9 14 20 7 18 7 +15 2 3 15 5 1 1 2 6 13 1 19 6 19 ^ +40 1 16 5 15 11 13 3 6 11 2 20 8 1 5 4 20 19 3 18 3 8 19 7 8 12 14 12 19 11 15 +6 19 1 19 4 10 16 17 7 17 16 ^ +39 1 12 19 20 1 13 12 10 8 21 15 7 19 13 6 8 19 20 18 2 12 14 3 10 6 2 6 2 17 +16 2 5 21 5 17 19 7 8 11 15 ^ +33 0 12 17 14 18 15 16 16 16 12 20 13 2 5 5 2 10 20 16 12 10 2 17 21 20 15 14 +14 18 21 13 9 17 10 ^ +40 1 2 12 16 17 3 9 19 5 7 10 5 11 17 18 14 14 12 2 20 15 8 17 3 20 11 12 18 7 +12 7 9 8 3 18 14 3 5 17 9 14 ^ +43 0 8 21 11 8 8 16 21 12 5 8 7 20 10 14 7 1 9 5 4 5 2 21 12 1 1 9 20 14 11 9 +19 16 3 1 14 10 2 8 20 18 7 8 18 ^ +40 1 2 19 6 11 18 11 15 6 5 16 14 9 7 21 3 15 21 16 8 7 3 6 14 17 17 5 10 20 10 +15 10 1 15 18 6 10 9 7 16 6 ^ +39 0 11 15 12 2 9 1 1 6 6 13 8 20 6 18 8 5 8 1 1 17 20 20 19 17 13 14 17 12 5 3 +18 20 20 11 18 15 13 16 7 ^ +48 1 7 10 1 19 10 7 17 7 16 3 8 4 4 15 17 13 9 11 2 2 11 7 13 4 17 7 1 5 13 19 +16 5 14 16 2 11 18 5 11 6 4 7 3 17 2 1 18 12 ^ +41 1 21 18 3 5 16 6 11 2 8 8 7 14 13 21 6 14 12 6 12 19 14 3 16 3 2 7 11 14 8 +16 10 19 12 19 4 5 6 13 19 12 13 ^ +44 1 7 5 12 4 13 21 2 5 17 15 15 1 13 5 21 6 4 12 14 15 5 18 12 1 19 2 14 1 8 8 +11 6 20 10 3 21 8 20 2 4 1 16 11 21 ^ +42 1 5 3 8 16 15 8 12 14 20 16 18 7 2 18 2 18 19 7 4 19 3 1 20 7 15 1 4 5 12 10 +19 6 11 4 4 9 20 20 8 2 20 18 ^ +42 1 19 2 8 4 15 7 2 2 6 18 20 16 1 18 17 13 3 14 2 1 2 10 14 19 12 9 15 20 1 7 +15 17 7 12 18 1 15 14 8 21 21 5 ^ +43 1 7 20 10 11 10 1 9 21 7 5 1 12 15 2 9 17 4 13 5 4 11 21 14 13 3 20 21 1 3 +12 18 11 4 14 20 5 3 14 13 15 9 21 3 ^ +40 1 19 8 1 5 9 5 9 16 17 9 6 12 6 16 7 4 3 1 21 16 19 15 18 17 17 17 21 13 20 +9 6 6 9 1 13 17 21 1 9 14 ^ +36 0 11 12 13 18 19 19 15 12 20 2 16 12 9 21 17 16 8 2 14 6 4 1 6 16 15 19 19 +21 9 13 18 3 16 8 13 11 ^ +47 0 21 15 4 21 4 2 3 8 15 19 8 6 16 2 15 3 12 3 11 3 17 12 21 6 3 4 13 1 12 4 +10 2 6 7 6 9 12 21 10 10 11 2 13 19 2 14 17 ^ +44 1 11 8 10 19 1 11 11 9 3 13 15 4 3 18 9 14 5 15 18 5 6 17 11 19 2 4 12 8 18 +12 17 3 4 8 5 19 16 16 6 1 13 1 18 18 ^ +39 1 10 18 15 11 5 1 17 4 17 19 11 18 21 9 2 10 10 5 5 20 18 13 5 15 3 6 3 10 +10 16 13 13 14 16 20 19 11 16 8 ^ +42 1 6 8 15 13 11 13 15 18 11 20 17 20 4 16 10 14 1 4 16 4 17 8 3 7 7 18 16 20 +2 9 9 4 20 7 16 4 11 4 10 6 20 4 ^ +41 0 17 6 19 17 2 15 6 5 7 4 8 11 16 9 10 15 20 12 15 8 6 17 5 9 3 3 4 19 20 12 +5 19 21 5 21 11 14 19 1 17 6 ^ +39 0 9 4 19 3 17 1 14 21 14 7 6 5 20 14 21 20 4 6 21 7 11 20 12 9 11 6 16 18 18 +10 11 20 6 12 11 5 7 21 3 ^ +43 1 18 6 15 21 10 4 14 9 19 10 3 3 5 13 1 8 12 3 13 9 7 10 17 10 6 8 3 17 18 3 +21 19 6 17 15 4 9 15 9 15 14 4 18 ^ +45 1 14 8 10 13 4 11 10 7 6 21 1 14 5 11 7 7 2 13 13 3 9 13 8 14 9 3 7 18 4 9 9 +5 15 13 17 10 15 16 20 8 19 9 10 9 13 ^ +40 1 19 14 21 2 18 13 10 4 18 16 4 21 15 10 18 19 3 12 12 14 4 13 11 1 11 1 10 +2 12 4 21 10 21 18 9 2 16 7 20 7 ^ +41 0 7 12 19 20 1 13 12 10 8 21 15 7 19 13 6 8 19 20 18 2 12 14 3 10 6 2 6 2 17 +16 2 5 21 5 17 19 7 8 11 10 21 ^ +35 0 17 14 18 15 16 16 16 12 20 13 2 5 5 2 10 20 16 12 10 2 17 21 20 15 14 14 +18 21 13 9 17 21 2 12 10 ^ +40 0 17 3 9 19 5 7 10 5 11 17 18 14 14 12 2 20 15 8 17 3 20 11 12 18 7 12 7 9 8 +3 18 14 3 5 17 9 18 8 21 20 ^ +46 1 8 8 16 21 12 5 8 7 20 10 14 7 1 9 5 4 5 2 21 12 1 1 9 20 14 11 9 19 16 3 1 +14 10 2 8 20 18 7 8 15 2 19 6 11 18 10 ^ +44 1 15 6 5 16 14 9 7 21 3 15 21 16 8 7 3 6 14 17 17 5 10 20 10 15 10 1 15 18 6 +10 9 7 16 14 11 15 12 2 9 1 1 6 6 19 ^ +38 1 8 20 6 18 8 5 8 1 1 17 20 20 19 17 13 14 17 12 5 3 18 20 20 11 18 15 13 16 +13 7 10 1 19 10 7 17 7 15 ^ +50 0 3 8 4 4 15 17 13 9 11 2 2 11 7 13 4 17 7 1 5 13 19 16 5 14 16 2 11 18 5 11 +6 4 7 3 17 2 1 18 13 21 18 3 5 16 6 11 2 8 8 18 ^ +42 1 14 13 21 6 14 12 6 12 19 14 3 16 3 2 7 11 14 8 16 10 19 12 19 4 5 6 13 19 +12 13 7 5 12 4 13 21 2 5 17 15 15 12 ^ +45 1 13 5 21 6 4 12 14 15 5 18 12 1 19 2 14 1 8 8 11 6 20 10 3 21 8 20 2 4 1 16 +11 1 5 3 8 16 15 8 12 14 20 16 18 7 18 ^ +46 0 18 2 18 19 7 4 19 3 1 20 7 15 1 4 5 12 10 19 6 11 4 4 9 20 20 8 2 20 3 19 +2 8 4 15 7 2 2 6 18 20 16 1 18 17 13 14 ^ +43 1 14 2 1 2 10 14 19 12 9 15 20 1 7 15 17 7 12 18 1 15 14 8 21 21 19 7 20 10 +11 10 1 9 21 7 5 1 12 15 2 9 17 4 19 ^ +45 1 5 4 11 21 14 13 3 20 21 1 3 12 18 11 4 14 20 5 3 14 13 15 9 21 11 19 8 1 5 +9 5 9 16 17 9 6 12 6 16 7 4 3 1 21 15 ^ +35 0 19 15 18 17 17 17 21 13 20 9 6 6 9 1 13 17 21 1 9 16 11 12 13 18 19 19 15 +12 20 2 16 12 9 21 12 ^ +44 1 16 8 2 14 6 4 1 6 16 15 19 19 21 9 13 18 3 16 8 13 21 15 4 21 4 2 3 8 15 +19 8 6 16 2 15 3 12 3 11 3 17 12 21 9 ^ +48 0 3 4 13 1 12 4 10 2 6 7 6 9 12 21 10 10 11 2 13 19 2 14 17 11 8 10 19 1 11 +11 9 3 13 15 4 3 18 9 14 5 15 18 5 6 17 11 19 15 ^ +44 0 4 12 8 18 12 17 3 4 8 5 19 16 16 6 1 13 1 18 1 10 18 15 11 5 1 17 4 17 19 +11 18 21 9 2 10 10 5 5 20 18 13 5 15 18 ^ +39 1 6 3 10 10 16 13 13 14 16 20 19 11 16 21 6 8 15 13 11 13 15 18 11 20 17 20 +4 16 10 14 1 4 16 4 17 8 3 7 21 ^ +46 1 18 16 20 2 9 9 4 20 7 16 4 11 4 10 6 20 14 17 6 19 17 2 15 6 5 7 4 8 11 16 +9 10 15 20 12 15 8 6 17 5 9 3 3 4 19 3 ^ +40 0 12 5 19 21 5 21 11 14 19 1 17 8 9 4 19 3 17 1 14 21 14 7 6 5 20 14 21 20 4 +6 21 7 11 20 12 9 11 6 16 11 ^ +44 0 18 10 11 20 6 12 11 5 7 21 19 18 6 15 21 10 4 14 9 19 10 3 3 5 13 1 8 12 3 +13 9 7 10 17 10 6 8 3 17 18 3 21 19 8 ^ +47 0 4 12 22 5 11 20 16 15 4 17 22 1 8 16 11 6 13 18 3 14 8 13 2 19 16 1 19 1 5 +3 16 9 8 20 7 5 1 11 15 2 3 17 3 12 7 4 19 ^ +42 0 18 16 13 7 1 19 5 12 18 12 6 15 19 4 4 9 13 13 8 17 13 18 12 2 8 4 7 17 17 +14 11 13 1 16 11 2 21 3 22 17 16 11 ^ +39 0 18 22 12 20 17 13 1 7 10 7 20 11 1 7 8 14 14 12 15 13 15 18 15 11 18 1 17 +14 15 20 16 20 8 2 17 10 4 21 2 ^ +44 1 19 19 14 22 21 18 13 14 1 3 12 11 11 4 22 13 5 18 7 21 9 22 19 12 8 16 5 +17 5 9 1 2 9 6 12 6 1 7 4 3 15 1 14 16 ^ +42 1 12 3 10 2 10 14 21 13 17 6 6 17 1 21 2 14 16 17 9 11 20 21 11 12 12 8 20 +13 2 9 20 9 14 10 1 16 2 22 6 4 16 18 ^ +51 0 15 1 12 4 14 9 21 3 3 9 8 21 15 14 8 4 14 4 2 3 8 12 8 6 1 2 18 20 15 3 19 +3 10 20 14 6 3 4 21 1 12 4 18 2 6 7 6 9 20 14 13 ^ +40 1 10 19 17 21 12 15 17 7 10 11 8 10 12 1 19 19 9 18 21 4 18 11 9 22 5 15 8 +15 3 5 6 2 19 12 17 4 20 8 11 20 ^ +45 0 2 18 4 16 20 12 9 9 6 16 21 16 3 16 18 3 19 5 16 2 4 2 12 11 15 11 14 17 2 +10 18 5 5 13 3 21 5 3 6 18 18 10 1 21 15 ^ +45 1 7 1 13 12 19 1 14 6 8 21 19 21 11 19 13 2 13 4 1 10 22 16 4 9 4 10 16 3 7 +15 11 9 13 17 15 9 9 15 4 13 15 9 4 19 9 ^ +46 0 18 6 13 22 10 6 12 2 17 15 6 5 7 4 8 11 1 9 10 8 5 20 16 6 10 5 17 3 3 19 +12 13 20 5 12 14 5 14 11 22 12 16 10 8 9 16 ^ +39 0 15 12 3 2 16 22 14 22 7 6 5 13 22 14 13 4 6 14 7 11 13 20 9 19 6 9 11 11 +18 19 13 6 20 19 20 7 22 12 12 ^ +41 0 6 14 18 19 7 17 12 10 3 18 15 5 21 16 8 20 3 21 9 15 18 10 15 10 6 8 18 2 +11 3 14 4 6 10 19 9 8 17 8 22 20 ^ +36 1 7 22 16 18 21 4 11 10 15 6 22 16 22 5 19 15 7 7 2 21 21 3 17 21 16 22 9 3 +7 11 4 17 17 20 21 21 ^ +37 1 18 9 5 8 12 17 18 17 16 12 22 14 17 11 21 10 4 3 1 4 14 10 11 4 3 20 20 22 +19 21 19 16 19 16 10 17 17 ^ +40 1 19 14 18 14 3 9 17 1 7 13 6 7 15 20 12 13 16 21 20 10 8 22 7 12 21 6 16 4 +13 11 2 12 15 22 3 18 6 17 6 22 ^ +42 0 10 9 2 5 22 5 10 4 7 8 19 10 20 10 22 11 8 1 9 1 20 13 21 17 5 5 17 10 13 +9 20 18 17 2 14 13 22 22 3 14 21 10 ^ +46 0 2 14 2 20 1 10 18 9 12 5 7 18 20 19 10 11 22 7 12 2 13 8 8 2 3 13 19 20 3 +7 20 7 9 8 3 11 22 3 5 10 9 11 16 14 19 16 ^ +46 1 15 8 1 14 20 5 8 7 13 10 22 7 16 9 5 4 5 2 14 20 1 1 15 17 13 22 19 17 4 1 +3 1 22 10 15 15 2 16 13 11 7 16 17 12 6 20 ^ +40 1 3 19 8 6 5 9 15 22 17 7 14 18 14 9 16 7 18 14 22 2 2 5 18 13 18 8 18 16 8 +11 15 6 18 9 7 9 22 19 20 15 ^ +44 0 9 16 16 6 6 21 8 13 6 11 8 5 16 16 1 10 13 13 4 10 21 22 15 10 20 5 3 3 13 +15 13 11 11 15 21 1 21 7 10 1 12 18 7 20 ^ +51 0 7 1 18 8 4 19 2 21 17 19 2 2 19 7 21 19 2 7 15 15 16 5 21 12 1 5 22 1 17 +19 11 5 11 6 4 7 3 10 2 1 3 6 14 11 18 5 1 6 11 17 8 ^ +39 1 8 15 22 21 14 6 22 20 6 20 12 22 18 1 3 2 7 19 22 8 9 18 4 20 12 4 5 6 21 +12 20 21 7 5 20 4 21 14 14 ^ +45 0 15 5 2 16 15 21 5 14 15 6 4 12 22 5 11 20 16 15 4 17 22 1 8 16 11 6 13 18 +3 14 8 13 2 19 16 1 19 1 5 3 16 9 8 20 14 ^ +48 1 5 1 11 15 2 3 17 3 12 7 4 12 18 16 13 7 1 19 5 12 18 12 6 15 19 4 4 9 13 +13 8 17 13 18 12 2 8 4 7 17 17 14 11 13 1 16 11 22 ^ +38 0 21 3 22 17 16 17 18 22 12 20 17 13 1 7 10 7 20 11 1 7 8 14 14 12 15 13 15 +18 15 11 18 1 17 14 15 20 16 10 ^ +43 0 8 2 17 10 4 21 5 19 19 14 22 21 18 13 14 1 3 12 11 11 4 22 13 5 18 7 21 9 +22 19 12 8 16 5 17 5 9 1 2 9 6 12 22 ^ +47 1 1 7 4 3 15 1 14 1 12 3 10 2 10 14 21 13 17 6 6 17 1 21 2 14 16 17 9 11 20 +21 11 12 12 8 20 13 2 9 20 9 14 10 1 16 2 22 20 ^ +53 0 4 16 14 15 1 12 4 14 9 21 3 3 9 8 21 15 14 8 4 14 4 2 3 8 12 8 6 1 2 18 20 +15 3 19 3 10 20 14 6 3 4 21 1 12 4 18 2 6 7 6 9 20 15 ^ +42 1 10 10 19 17 21 12 15 17 7 10 11 8 10 12 1 19 19 9 18 21 4 18 11 9 22 5 15 +8 15 3 5 6 2 19 12 17 4 20 8 11 20 12 ^ +45 0 18 4 16 20 12 9 9 6 16 21 16 3 16 18 3 19 5 16 2 4 2 12 11 15 11 14 17 2 +10 18 5 5 13 3 21 5 3 6 18 18 10 1 21 21 18 ^ +45 0 1 13 12 19 1 14 6 8 21 19 21 11 19 13 2 13 4 1 10 22 16 4 9 4 10 16 3 7 15 +11 9 13 17 15 9 9 15 4 13 15 9 4 19 19 19 ^ +49 0 6 13 22 10 6 12 2 17 15 6 5 7 4 8 11 1 9 10 8 5 20 16 6 10 5 17 3 3 19 12 +13 20 5 12 14 5 14 11 22 12 16 10 8 9 4 15 12 3 22 ^ +39 0 16 22 14 22 7 6 5 13 22 14 13 4 6 14 7 11 13 20 9 19 6 9 11 11 18 19 13 6 +20 19 20 7 22 12 11 6 14 18 17 ^ +43 1 7 17 12 10 3 18 15 5 21 16 8 20 3 21 9 15 18 10 15 10 6 8 18 2 11 3 14 4 6 +10 19 9 8 17 8 22 4 7 22 16 18 21 11 ^ +39 0 11 10 15 6 22 16 22 5 19 15 7 7 2 21 21 3 17 21 16 22 9 3 7 11 4 17 17 20 +21 10 18 9 5 8 12 17 18 17 17 ^ +40 1 12 22 14 17 11 21 10 4 3 1 4 14 10 11 4 3 20 20 22 19 21 19 16 19 16 10 17 +20 19 14 18 14 3 9 17 1 7 13 6 18 ^ +44 1 15 20 12 13 16 21 20 10 8 22 7 12 21 6 16 4 13 11 2 12 15 22 3 18 6 17 6 2 +10 9 2 5 22 5 10 4 7 8 19 10 20 10 22 7 ^ +43 0 8 1 9 1 20 13 21 17 5 5 17 10 13 9 20 18 17 2 14 13 22 22 3 14 21 9 2 14 2 +20 1 10 18 9 12 5 7 18 20 19 10 11 19 ^ +53 1 7 12 2 13 8 8 2 3 13 19 20 3 7 20 7 9 8 3 11 22 3 5 10 9 11 16 14 19 8 15 +8 1 14 20 5 8 7 13 10 22 7 16 9 5 4 5 2 14 20 1 1 15 8 ^ +42 0 13 22 19 17 4 1 3 1 22 10 15 15 2 16 13 11 7 16 17 12 6 19 3 19 8 6 5 9 15 +22 17 7 14 18 14 9 16 7 18 14 22 19 ^ +43 0 2 5 18 13 18 8 18 16 8 11 15 6 18 9 7 9 22 19 20 17 9 16 16 6 6 21 8 13 6 +11 8 5 16 16 1 10 13 13 4 10 21 22 14 ^ +48 0 10 20 5 3 3 13 15 13 11 11 15 21 1 21 7 10 1 12 18 7 2 7 1 18 8 4 19 2 21 +17 19 2 2 19 7 21 19 2 7 15 15 16 5 21 12 1 5 21 ^ +49 1 1 17 19 11 5 11 6 4 7 3 10 2 1 3 6 14 11 18 5 1 6 11 17 8 8 15 22 21 14 6 +22 20 6 20 12 22 18 1 3 2 7 19 22 8 9 18 4 20 10 ^ +45 1 4 5 6 21 12 20 21 7 5 20 4 21 14 2 15 5 2 16 15 21 5 14 15 6 4 12 22 5 11 +20 16 15 4 17 22 1 8 16 11 6 13 18 3 14 13 ^ +52 0 13 2 19 16 1 19 1 5 3 16 9 8 20 7 5 1 11 15 2 3 17 3 12 7 4 12 18 16 13 7 +1 19 5 12 18 12 6 15 19 4 4 9 13 13 8 17 13 18 12 2 8 15 ^ +46 0 20 1 1 11 21 2 3 16 8 12 21 22 1 16 1 10 22 17 4 14 7 2 16 9 18 23 9 4 8 +16 7 9 18 11 11 17 20 2 7 10 20 8 10 16 14 14 ^ +41 1 20 4 16 4 18 1 14 12 19 13 15 19 19 11 22 13 10 2 11 16 10 17 8 8 6 22 2 +15 10 9 13 18 14 22 8 6 18 16 15 14 20 ^ +43 1 14 3 12 14 17 11 3 9 19 10 20 16 11 3 17 7 21 23 12 23 11 13 2 14 14 16 13 +12 11 5 14 3 8 4 13 8 17 17 18 17 2 12 22 ^ +43 1 17 3 11 12 16 5 1 22 6 16 11 20 3 18 17 6 22 14 13 21 21 3 18 13 20 11 18 +19 11 6 1 10 18 7 17 5 16 1 7 10 4 20 22 ^ +46 0 8 10 12 4 11 21 6 13 16 17 6 23 1 9 14 4 11 23 23 19 1 13 6 20 1 9 12 8 5 +23 17 16 8 8 3 10 13 7 6 10 8 14 9 15 20 20 ^ +46 0 20 21 15 12 19 17 1 6 4 5 8 4 12 10 6 5 4 17 3 3 16 13 5 21 16 10 21 18 19 +15 16 12 6 12 17 8 7 8 11 14 1 23 10 15 15 13 ^ +43 0 21 13 15 18 21 10 10 23 3 13 13 9 16 2 17 19 3 22 11 5 18 19 13 7 7 8 19 2 +12 2 19 16 23 9 16 6 3 19 12 5 10 9 17 ^ +47 0 21 3 2 1 7 14 14 7 6 2 20 3 6 19 19 10 2 22 12 17 12 1 20 7 7 15 20 6 18 8 +3 14 23 18 15 4 7 5 23 15 7 14 10 10 19 17 11 ^ +44 0 4 15 17 11 15 11 8 9 17 5 12 18 14 6 20 17 21 12 16 9 22 9 20 15 2 22 11 2 +6 11 9 8 2 4 14 19 3 21 21 23 8 2 11 15 ^ +37 0 8 4 20 22 6 21 18 22 10 19 9 14 17 23 21 10 7 15 13 16 5 4 10 13 14 20 23 +12 20 23 18 10 12 8 21 11 19 ^ +39 0 12 7 19 14 18 14 18 22 6 9 22 5 23 13 6 8 23 20 22 5 22 15 19 20 9 9 1 13 +13 10 14 13 5 22 14 21 9 21 3 ^ +45 1 14 14 4 18 13 12 23 7 3 15 5 17 14 23 14 5 17 22 11 1 8 13 23 6 21 3 6 11 +7 23 8 6 21 4 4 22 19 13 8 5 19 7 5 23 3 ^ +50 1 4 19 11 23 11 21 14 1 3 20 2 20 7 4 17 2 5 13 4 23 5 22 7 7 9 17 13 5 6 2 +21 1 17 7 9 21 23 1 1 12 3 1 15 22 4 12 6 20 5 23 ^ +46 1 23 4 12 22 8 18 16 3 16 4 2 13 1 15 15 1 23 2 3 4 10 1 12 7 11 2 7 22 22 +21 22 13 3 12 22 12 4 3 23 10 14 17 15 9 23 20 ^ +44 0 19 12 21 22 9 17 12 2 18 18 12 21 2 19 4 21 20 4 9 14 5 21 8 22 10 15 23 +14 8 5 11 19 5 7 5 3 11 4 15 18 9 2 23 4 ^ +46 0 9 16 14 15 6 15 1 11 4 16 16 20 14 2 9 19 14 6 3 7 10 16 22 23 7 7 12 5 2 +8 9 5 7 1 17 19 21 19 18 15 3 20 22 14 9 16 ^ +44 1 10 18 11 3 5 9 10 11 22 12 12 15 23 2 10 18 23 5 18 21 20 23 3 9 3 22 7 8 +7 4 1 14 16 16 13 18 2 21 18 15 5 5 16 21 ^ +46 0 2 2 6 23 13 22 20 12 17 4 10 21 2 20 2 8 8 7 20 13 3 20 23 16 6 23 9 12 20 +3 10 5 6 19 18 12 13 14 8 1 1 8 9 13 19 23 ^ +47 0 9 20 20 5 15 13 17 3 15 22 3 1 19 8 15 8 19 9 21 7 12 1 16 21 11 8 10 15 +16 8 1 5 5 20 22 13 11 22 4 4 7 6 22 10 3 21 4 ^ +45 1 9 19 22 18 3 23 6 4 6 19 15 13 17 4 13 9 15 4 6 7 13 11 1 20 15 12 18 18 +16 7 13 4 11 7 11 6 17 9 18 15 21 17 5 20 11 ^ +49 0 1 22 16 18 5 8 11 2 23 10 11 5 2 1 19 16 3 19 16 15 21 5 3 7 18 4 9 15 3 8 +20 1 21 1 21 17 9 6 17 10 16 2 9 7 16 19 15 17 9 ^ +51 0 17 20 19 6 6 14 2 2 5 1 2 10 17 1 18 6 18 20 1 1 11 21 2 3 16 8 12 21 22 1 +16 1 10 22 17 4 14 7 2 16 9 18 23 9 4 8 16 7 9 18 17 ^ +45 1 11 17 20 2 7 10 20 8 10 16 14 11 20 4 16 4 18 1 14 12 19 13 15 19 19 11 22 +13 10 2 11 16 10 17 8 8 6 22 2 15 10 9 13 18 8 ^ +44 0 22 8 6 18 16 15 14 15 14 3 12 14 17 11 3 9 19 10 20 16 11 3 17 7 21 23 12 +23 11 13 2 14 14 16 13 12 11 5 14 3 8 4 13 20 ^ +43 0 17 17 18 17 2 12 3 17 3 11 12 16 5 1 22 6 16 11 20 3 18 17 6 22 14 13 21 +21 3 18 13 20 11 18 19 11 6 1 10 18 7 17 20 ^ +50 1 16 1 7 10 4 20 10 8 10 12 4 11 21 6 13 16 17 6 23 1 9 14 4 11 23 23 19 1 +13 6 20 1 9 12 8 5 23 17 16 8 8 3 10 13 7 6 10 8 14 17 ^ +46 1 15 20 18 20 21 15 12 19 17 1 6 4 5 8 4 12 10 6 5 4 17 3 3 16 13 5 21 16 10 +21 18 19 15 16 12 6 12 17 8 7 8 11 14 1 23 21 ^ +45 0 15 15 2 21 13 15 18 21 10 10 23 3 13 13 9 16 2 17 19 3 22 11 5 18 19 13 7 +7 8 19 2 12 2 19 16 23 9 16 6 3 19 12 5 10 15 ^ +48 1 20 21 3 2 1 7 14 14 7 6 2 20 3 6 19 19 10 2 22 12 17 12 1 20 7 7 15 20 6 +18 8 3 14 23 18 15 4 7 5 23 15 7 14 10 10 19 17 12 ^ +47 0 4 15 17 11 15 11 8 9 17 5 12 18 14 6 20 17 21 12 16 9 22 9 20 15 2 22 11 2 +6 11 9 8 2 4 14 19 3 21 21 23 8 2 11 4 8 4 20 ^ +39 0 22 6 21 18 22 10 19 9 14 17 23 21 10 7 15 13 16 5 4 10 13 14 20 23 12 20 +23 18 10 12 8 21 11 6 12 7 19 14 14 ^ +40 0 14 18 22 6 9 22 5 23 13 6 8 23 20 22 5 22 15 19 20 9 9 1 13 13 10 14 13 5 +22 14 21 9 21 19 14 14 4 18 13 12 ^ +46 0 23 7 3 15 5 17 14 23 14 5 17 22 11 1 8 13 23 6 21 3 6 11 7 23 8 6 21 4 4 +22 19 13 8 5 19 7 5 23 1 4 19 11 23 11 21 9 ^ +52 0 1 3 20 2 20 7 4 17 2 5 13 4 23 5 22 7 7 9 17 13 5 6 2 21 1 17 7 9 21 23 1 +1 12 3 1 15 22 4 12 6 20 5 19 23 4 12 22 8 18 16 3 22 ^ +48 0 4 2 13 1 15 15 1 23 2 3 4 10 1 12 7 11 2 7 22 22 21 22 13 3 12 22 12 4 3 +23 10 14 17 15 9 23 4 19 12 21 22 9 17 12 2 18 18 9 ^ +46 0 21 2 19 4 21 20 4 9 14 5 21 8 22 10 15 23 14 8 5 11 19 5 7 5 3 11 4 15 18 +9 2 23 22 9 16 14 15 6 15 1 11 4 16 16 20 22 ^ +47 0 2 9 19 14 6 3 7 10 16 22 23 7 7 12 5 2 8 9 5 7 1 17 19 21 19 18 15 3 20 22 +14 9 11 10 18 11 3 5 9 10 11 22 12 12 15 23 22 ^ +45 0 10 18 23 5 18 21 20 23 3 9 3 22 7 8 7 4 1 14 16 16 13 18 2 21 18 15 5 5 16 +12 2 2 6 23 13 22 20 12 17 4 10 21 2 20 19 ^ +47 0 8 8 7 20 13 3 20 23 16 6 23 9 12 20 3 10 5 6 19 18 12 13 14 8 1 1 8 9 13 +19 12 9 20 20 5 15 13 17 3 15 22 3 1 19 8 15 23 ^ +48 0 19 9 21 7 12 1 16 21 11 8 10 15 16 8 1 5 5 20 22 13 11 22 4 4 7 6 22 10 3 +21 1 9 19 22 18 3 23 6 4 6 19 15 13 17 4 13 9 17 ^ +49 1 4 6 7 13 11 1 20 15 12 18 18 16 7 13 4 11 7 11 6 17 9 18 15 21 17 5 20 6 1 +22 16 18 5 8 11 2 23 10 11 5 2 1 19 16 3 19 16 15 18 ^ +55 1 5 3 7 18 4 9 15 3 8 20 1 21 1 21 17 9 6 17 10 16 2 9 7 16 19 15 17 10 17 +20 19 6 6 14 2 2 5 1 2 10 17 1 18 6 18 20 1 1 11 21 2 3 16 8 17 ^ +47 0 21 22 1 16 1 10 22 17 4 14 7 2 16 9 18 23 9 4 8 16 7 9 18 11 11 17 20 2 7 +10 20 8 10 16 14 11 20 4 16 4 18 1 14 12 19 13 19 ^ +45 1 19 19 11 22 13 10 2 11 16 10 17 8 8 6 22 2 15 10 9 13 18 14 22 8 6 18 16 +15 14 15 14 3 12 14 17 11 3 9 19 10 20 16 11 3 21 ^ +47 1 7 21 23 12 23 11 13 2 14 14 16 13 12 11 5 14 3 8 4 13 8 17 17 18 17 2 12 3 +17 3 11 12 16 5 1 22 6 16 11 20 3 18 17 6 22 14 20 ^ +47 1 21 21 3 18 13 20 11 18 19 11 6 1 10 18 7 17 5 16 1 7 10 4 20 10 8 10 12 4 +11 21 6 13 16 17 6 23 1 9 14 4 11 23 23 19 1 13 22 ^ +51 0 20 1 9 12 8 5 23 17 16 8 8 3 10 13 7 6 10 8 14 9 15 20 18 20 21 15 12 19 +17 1 6 4 5 8 4 12 10 6 5 4 17 3 3 16 13 5 21 16 10 21 21 ^ +52 0 15 13 4 8 12 22 9 6 3 1 13 16 12 23 10 14 2 1 6 11 8 19 24 16 2 5 21 2 7 +22 4 5 23 3 12 20 8 4 5 17 9 18 18 18 4 10 13 2 4 7 24 21 ^ +51 1 10 21 4 8 24 2 6 19 10 6 22 22 14 22 13 21 5 22 2 4 18 5 11 21 1 7 8 4 17 +5 14 1 2 10 9 12 5 11 10 20 4 14 3 1 3 21 12 11 17 22 21 ^ +43 1 7 5 21 14 15 19 20 12 6 12 18 19 4 7 12 10 5 22 3 15 21 7 23 7 2 22 4 18 +18 3 24 10 17 24 23 18 6 11 18 22 8 6 20 ^ +45 0 2 12 10 14 12 9 2 23 16 20 14 17 9 16 7 21 6 22 24 19 11 9 19 21 15 11 19 +2 2 7 8 10 8 9 8 15 9 14 6 16 8 21 21 22 13 ^ +50 1 17 9 4 24 21 15 15 16 16 13 9 10 16 14 12 7 12 15 15 5 10 10 23 5 13 22 3 +5 1 4 11 14 7 6 10 17 14 6 3 13 18 16 3 5 15 23 8 5 3 22 ^ +47 0 8 12 20 20 9 2 13 24 17 2 2 17 3 13 20 2 6 3 15 7 13 1 18 7 22 18 24 20 14 +7 17 16 20 3 11 6 5 2 18 14 16 22 14 11 7 18 22 ^ +48 1 17 24 12 12 3 13 19 16 22 4 16 4 6 23 8 18 11 2 3 20 22 9 21 8 23 1 23 20 +7 16 13 23 4 13 3 7 4 23 6 13 19 2 3 7 2 9 9 19 ^ +45 1 6 13 4 22 6 19 20 1 9 7 14 1 15 3 23 24 22 18 12 12 17 19 10 8 11 22 12 10 +2 20 15 18 17 18 7 11 12 21 6 12 4 7 18 17 18 ^ +44 0 2 14 24 14 1 23 1 11 15 10 6 18 20 7 1 8 1 16 6 20 23 23 21 10 10 12 24 10 +11 23 2 12 23 9 3 24 24 19 14 10 18 15 14 12 ^ +50 1 16 11 22 2 15 24 8 22 1 4 24 9 10 15 3 9 5 4 17 15 9 12 19 19 1 3 10 6 8 3 +17 8 18 24 19 3 4 15 4 9 2 24 5 20 13 7 20 17 19 11 ^ +43 0 13 8 10 19 15 11 1 14 17 20 22 10 7 11 16 9 21 22 17 23 12 15 4 24 7 21 18 +2 21 16 1 19 18 20 11 3 15 19 18 1 6 14 15 ^ +45 0 5 5 19 13 10 24 19 16 24 15 13 2 19 15 24 21 17 4 13 17 1 1 9 1 10 2 18 1 +21 19 5 18 12 2 22 16 23 15 19 6 18 9 1 23 20 ^ +49 0 21 13 14 11 18 12 13 3 19 9 20 22 20 2 11 12 6 1 12 16 18 2 9 8 4 3 11 17 +11 5 4 19 16 11 23 13 18 1 20 8 2 16 16 21 4 19 5 5 24 ^ +46 0 24 13 23 6 24 5 17 12 5 1 15 17 17 21 11 13 9 23 11 14 21 7 6 9 6 14 7 16 +2 17 1 24 23 4 12 14 4 2 11 23 12 4 23 21 21 4 ^ +49 1 15 13 15 14 15 8 14 9 17 7 15 2 23 2 1 17 6 14 19 24 2 8 8 7 7 10 14 13 7 +9 11 16 11 8 8 18 13 13 18 10 1 20 18 22 19 12 9 16 12 ^ +43 1 13 6 9 17 20 10 5 7 20 18 8 15 23 21 20 5 15 11 3 3 14 21 10 24 6 21 21 6 +23 10 3 21 23 17 20 8 16 10 22 5 16 1 24 ^ +50 0 24 3 9 16 6 7 3 20 12 17 18 21 5 9 7 1 9 12 19 5 7 6 24 11 11 20 23 10 4 7 +1 19 7 19 17 23 15 5 12 21 20 3 1 14 2 15 22 3 16 11 ^ +45 1 10 19 10 20 16 19 17 10 4 21 20 16 21 14 14 8 17 10 19 1 17 4 3 22 23 14 +16 9 22 8 20 24 1 5 11 11 6 4 13 15 12 1 11 13 22 ^ +45 0 3 8 5 6 5 16 12 11 2 17 14 19 23 16 5 6 20 21 9 24 9 22 23 22 12 8 13 23 +17 5 3 16 22 15 22 7 17 3 2 13 13 11 24 13 17 ^ +42 1 21 11 14 20 24 24 4 9 13 5 8 9 18 7 12 1 21 8 24 15 1 22 19 24 14 13 8 20 +14 18 23 19 9 8 14 23 11 4 4 22 20 17 ^ +49 1 17 15 20 6 15 8 24 4 20 19 8 19 14 21 24 18 3 10 16 3 6 4 1 10 15 13 4 8 +12 22 9 6 3 1 13 16 12 23 10 14 2 1 6 11 8 19 24 16 23 ^ +50 0 5 21 2 7 22 4 5 23 3 12 20 8 4 5 17 9 18 18 18 4 10 13 2 4 7 24 8 10 21 4 +8 24 2 6 19 10 6 22 22 14 22 13 21 5 22 2 4 18 5 24 ^ +53 1 21 1 7 8 4 17 5 14 1 2 10 9 12 5 11 10 20 4 14 3 1 3 21 12 11 17 22 11 7 5 +21 14 15 19 20 12 6 12 18 19 4 7 12 10 5 22 3 15 21 7 23 7 18 ^ +43 1 22 4 18 18 3 24 10 17 24 23 18 6 11 18 22 8 6 6 2 12 10 14 12 9 2 23 16 20 +14 17 9 16 7 21 6 22 24 19 11 9 19 21 6 ^ +49 1 11 19 2 2 7 8 10 8 9 8 15 9 14 6 16 8 21 21 22 6 17 9 4 24 21 15 15 16 16 +13 9 10 16 14 12 7 12 15 15 5 10 10 23 5 13 22 3 5 22 ^ +52 0 4 11 14 7 6 10 17 14 6 3 13 18 16 3 5 15 23 8 5 3 18 8 12 20 20 9 2 13 24 +17 2 2 17 3 13 20 2 6 3 15 7 13 1 18 7 22 18 24 20 14 7 23 ^ +45 1 16 20 3 11 6 5 2 18 14 16 22 14 11 7 18 16 17 24 12 12 3 13 19 16 22 4 16 +4 6 23 8 18 11 2 3 20 22 9 21 8 23 1 23 20 23 ^ +51 1 16 13 23 4 13 3 7 4 23 6 13 19 2 3 7 2 9 9 15 6 13 4 22 6 19 20 1 9 7 14 1 +15 3 23 24 22 18 12 12 17 19 10 8 11 22 12 10 2 20 15 15 ^ +48 1 17 18 7 11 12 21 6 12 4 7 18 17 3 2 14 24 14 1 23 1 11 15 10 6 18 20 7 1 8 +1 16 6 20 23 23 21 10 10 12 24 10 11 23 2 12 23 9 20 ^ +49 1 24 24 19 14 10 18 15 14 5 16 11 22 2 15 24 8 22 1 4 24 9 10 15 3 9 5 4 17 +15 9 12 19 19 1 3 10 6 8 3 17 8 18 24 19 3 4 15 4 24 ^ +43 0 2 24 5 20 13 7 20 17 19 22 13 8 10 19 15 11 1 14 17 20 22 10 7 11 16 9 21 +22 17 23 12 15 4 24 7 21 18 2 21 16 1 19 11 ^ +48 1 20 11 3 15 19 18 1 6 14 5 5 5 19 13 10 24 19 16 24 15 13 2 19 15 24 21 17 +4 13 17 1 1 9 1 10 2 18 1 21 19 5 18 12 2 22 16 23 19 ^ +50 1 19 6 18 9 1 23 22 21 13 14 11 18 12 13 3 19 9 20 22 20 2 11 12 6 1 12 16 +18 2 9 8 4 3 11 17 11 5 4 19 16 11 23 13 18 1 20 8 2 16 16 ^ +48 1 16 21 4 19 5 5 20 24 13 23 6 24 5 17 12 5 1 15 17 17 21 11 13 9 23 11 14 +21 7 6 9 6 14 7 16 2 17 1 24 23 4 12 14 4 2 11 23 15 ^ +50 1 4 23 21 21 16 15 13 15 14 15 8 14 9 17 7 15 2 23 2 1 17 6 14 19 24 2 8 8 7 +7 10 14 13 7 9 11 16 11 8 8 18 13 13 18 10 1 20 18 22 3 ^ +44 1 12 9 16 17 13 6 9 17 20 10 5 7 20 18 8 15 23 21 20 5 15 11 3 3 14 21 10 24 +6 21 21 6 23 10 3 21 23 17 20 8 16 10 22 12 ^ +53 0 16 1 5 24 3 9 16 6 7 3 20 12 17 18 21 5 9 7 1 9 12 19 5 7 6 24 11 11 20 23 +10 4 7 1 19 7 19 17 23 15 5 12 21 20 3 1 14 2 15 22 3 16 9 ^ +46 1 10 19 10 20 16 19 17 10 4 21 20 16 21 14 14 8 17 10 19 1 17 4 3 22 23 14 +16 9 22 8 20 24 1 5 11 11 6 4 13 15 12 1 11 13 21 21 ^ +46 0 8 5 6 5 16 12 11 2 17 14 19 23 16 5 6 20 21 9 24 9 22 23 22 12 8 13 23 17 +5 3 16 22 15 22 7 17 3 2 13 13 11 24 13 12 21 7 ^ +43 1 14 20 24 24 4 9 13 5 8 9 18 7 12 1 21 8 24 15 1 22 19 24 14 13 8 20 14 18 +23 19 9 8 14 23 11 4 4 22 20 13 17 15 24 ^ +55 0 6 15 8 24 4 20 19 8 19 14 21 24 18 3 10 16 3 6 4 1 10 15 13 4 8 12 22 9 6 +3 1 13 16 12 23 10 14 2 1 6 11 8 19 24 16 2 5 21 2 7 22 4 5 23 4 ^ +55 1 12 20 8 4 5 17 9 18 18 18 4 10 13 2 4 7 24 8 10 21 4 8 24 2 6 19 10 6 22 +22 14 22 13 21 5 22 2 4 18 5 11 21 1 7 8 4 17 5 14 1 2 10 9 12 14 ^ +49 0 11 10 20 4 14 3 1 3 21 12 11 17 22 11 7 5 21 14 15 19 20 12 6 12 18 19 4 7 +12 10 5 22 3 15 21 7 23 7 2 22 4 18 18 3 24 10 17 24 12 ^ +50 0 18 6 11 18 22 8 6 6 2 12 10 14 12 9 2 23 16 20 14 17 9 16 7 21 6 22 24 19 +11 9 19 21 15 11 19 2 2 7 8 10 8 9 8 15 9 14 6 16 8 22 ^ +51 1 21 22 6 17 9 4 24 21 15 15 16 16 13 9 10 16 14 12 7 12 15 15 5 10 10 23 5 +13 22 3 5 1 4 11 14 7 6 10 17 14 6 3 13 18 16 3 5 15 23 8 21 ^ +51 1 5 3 18 8 12 20 20 9 2 13 24 17 2 2 17 3 13 20 2 6 3 15 7 13 1 18 7 22 18 +24 20 14 7 17 16 20 3 11 6 5 2 18 14 16 22 14 11 7 18 16 20 ^ +52 0 24 12 12 3 13 19 16 22 4 16 4 6 23 8 18 11 2 3 20 22 9 21 8 23 1 23 20 7 +16 13 23 4 13 3 7 4 23 6 13 19 2 3 7 2 9 9 15 6 13 4 22 16 ^ +49 1 19 20 1 9 7 14 1 15 3 23 24 22 18 12 12 17 19 10 8 11 22 12 10 2 20 15 18 +17 18 7 11 12 21 6 12 4 7 18 17 3 2 14 24 14 1 23 1 11 16 ^ +47 0 10 6 18 20 7 1 8 1 16 6 20 23 23 21 10 10 12 24 10 11 23 2 12 23 9 3 24 24 +19 14 10 18 15 14 5 16 11 22 2 15 24 8 22 1 4 24 3 ^ +45 0 17 6 24 11 7 21 9 17 8 25 5 5 22 16 13 5 2 16 4 25 25 8 18 13 13 3 1 22 23 +24 18 12 21 19 2 4 24 13 11 2 7 24 22 17 21 ^ +46 1 15 1 8 3 10 15 18 15 8 10 16 20 20 7 18 22 11 18 9 11 15 22 20 18 6 24 15 +25 4 22 12 17 4 6 17 20 2 4 2 5 20 15 19 24 18 15 ^ +52 1 8 2 5 23 2 10 21 8 5 2 9 16 16 15 6 22 23 5 6 21 5 21 24 3 6 10 17 19 9 15 +11 23 16 17 1 3 12 3 20 4 5 5 3 21 22 15 4 21 20 7 22 18 ^ +43 0 9 24 4 18 7 7 25 24 22 21 23 24 14 20 12 6 7 4 2 12 25 15 3 9 23 8 16 25 +11 14 4 10 19 23 16 13 9 20 25 17 11 8 19 ^ +55 0 19 25 17 7 16 21 6 4 8 2 15 9 2 9 19 3 6 3 3 10 25 13 15 7 8 20 21 12 10 +12 5 24 11 20 3 13 13 16 9 13 10 3 9 16 3 7 15 9 9 14 2 13 17 25 3 ^ +46 0 18 5 19 23 9 25 9 10 23 12 12 7 13 8 15 7 1 6 21 2 8 7 6 16 14 14 12 15 13 +24 10 15 11 10 8 14 15 21 25 21 16 9 18 20 22 21 ^ +50 1 20 11 14 23 22 10 13 14 8 19 12 2 11 20 23 13 4 10 6 5 7 23 11 3 16 8 21 4 +8 18 5 12 14 8 6 20 19 24 8 23 17 3 7 19 1 18 1 14 22 11 ^ +44 1 14 5 8 22 18 14 25 17 11 12 22 2 12 12 16 12 13 18 17 12 17 14 18 8 25 9 +23 5 3 8 14 24 17 7 3 3 23 17 22 19 19 17 16 19 ^ +51 0 24 14 16 20 23 20 9 19 16 7 12 16 5 8 9 7 10 21 24 10 11 19 1 21 14 14 19 +3 22 8 12 20 1 18 5 6 5 12 14 1 1 11 9 22 3 24 9 6 1 11 20 ^ +47 0 1 12 8 11 11 17 10 22 7 3 10 2 6 4 24 16 24 19 4 5 18 11 12 9 20 21 25 2 +21 18 10 20 25 21 3 17 17 5 8 22 25 19 8 10 19 7 25 ^ +55 1 4 8 18 3 18 3 11 24 2 14 9 1 10 4 4 13 19 22 4 7 19 5 10 10 1 8 22 22 6 8 +13 12 11 17 23 14 16 7 5 11 22 24 7 2 11 13 18 4 20 8 1 6 25 20 16 ^ +51 1 20 1 25 10 15 15 2 17 13 9 24 17 24 20 13 15 17 3 11 20 10 5 13 23 18 5 3 +18 15 7 5 7 4 15 20 16 2 17 1 7 4 12 7 25 14 1 4 7 19 19 22 ^ +52 0 3 13 12 4 3 14 4 14 11 6 3 25 18 16 20 24 12 19 18 25 6 23 6 15 5 4 4 6 14 +13 20 5 14 15 2 13 21 11 5 17 2 2 10 11 13 14 12 11 21 15 23 20 ^ +50 1 2 5 7 23 10 20 6 12 1 19 10 24 21 22 25 16 12 19 22 15 10 18 24 1 5 16 10 +18 2 19 14 3 5 1 7 20 7 16 6 20 6 6 25 10 22 20 2 1 15 18 ^ +48 0 23 25 23 4 11 15 15 6 9 22 22 19 22 25 6 19 6 2 20 21 7 22 18 10 7 17 4 16 +12 10 25 12 23 23 9 2 22 1 20 2 8 3 14 7 1 2 3 24 ^ +38 1 21 21 23 20 22 11 25 20 24 25 1 9 21 20 14 10 14 19 9 17 15 13 5 15 24 21 +12 13 25 22 21 1 16 23 7 24 15 22 ^ +54 1 22 5 25 3 4 2 9 12 24 6 19 1 14 9 5 9 1 17 9 4 23 21 1 3 15 16 11 1 12 18 +6 2 7 8 17 8 21 13 22 9 21 4 9 1 13 17 21 10 9 18 24 23 13 24 ^ +43 1 23 23 19 23 22 17 18 23 18 21 17 1 10 12 4 6 1 21 11 18 2 6 6 12 18 13 16 +16 18 19 13 11 21 19 15 12 15 16 19 2 23 19 23 ^ +48 0 1 2 25 14 11 25 24 16 8 14 21 21 16 6 13 1 23 15 8 17 4 3 4 9 23 12 8 8 24 +13 6 11 3 8 24 19 8 23 1 24 24 18 25 13 2 6 25 14 ^ +51 1 9 3 5 11 19 11 16 5 4 17 24 23 15 14 10 7 14 17 25 15 10 14 6 18 18 4 1 13 +10 16 1 25 16 2 24 5 1 17 6 17 6 24 11 7 21 9 17 8 25 5 23 ^ +48 1 22 16 13 5 2 16 4 25 25 8 18 13 13 3 1 22 23 24 18 12 21 19 2 4 24 13 11 2 +7 24 22 17 5 15 1 8 3 10 15 18 15 8 10 16 20 20 7 25 ^ +49 0 22 11 18 9 11 15 22 20 18 6 24 15 25 4 22 12 17 4 6 17 20 2 4 2 5 20 15 19 +24 18 9 8 2 5 23 2 10 21 8 5 2 9 16 16 15 6 22 23 17 ^ +47 1 6 21 5 21 24 3 6 10 17 19 9 15 11 23 16 17 1 3 12 3 20 4 5 5 3 21 22 15 4 +21 20 7 22 14 9 24 4 18 7 7 25 24 22 21 23 24 14 ^ +53 0 20 12 6 7 4 2 12 25 15 3 9 23 8 16 25 11 14 4 10 19 23 16 13 9 20 25 17 11 +8 4 19 25 17 7 16 21 6 4 8 2 15 9 2 9 19 3 6 3 3 10 25 13 15 ^ +54 1 7 8 20 21 12 10 12 5 24 11 20 3 13 13 16 9 13 10 3 9 16 3 7 15 9 9 14 2 13 +17 25 2 18 5 19 23 9 25 9 10 23 12 12 7 13 8 15 7 1 6 21 2 8 25 ^ +44 1 6 16 14 14 12 15 13 24 10 15 11 10 8 14 15 21 25 21 16 9 18 20 22 21 20 11 +14 23 22 10 13 14 8 19 12 2 11 20 23 13 4 10 6 25 ^ +49 1 7 23 11 3 16 8 21 4 8 18 5 12 14 8 6 20 19 24 8 23 17 3 7 19 1 18 1 14 22 +13 14 5 8 22 18 14 25 17 11 12 22 2 12 12 16 12 13 18 25 ^ +45 1 12 17 14 18 8 25 9 23 5 3 8 14 24 17 7 3 3 23 17 22 19 19 17 16 22 24 14 +16 20 23 20 9 19 16 7 12 16 5 8 9 7 10 21 24 7 ^ +58 0 11 19 1 21 14 14 19 3 22 8 12 20 1 18 5 6 5 12 14 1 1 11 9 22 3 24 9 6 1 +11 16 1 12 8 11 11 17 10 22 7 3 10 2 6 4 24 16 24 19 4 5 18 11 12 9 20 21 7 ^ +54 1 2 21 18 10 20 25 21 3 17 17 5 8 22 25 19 8 10 19 7 11 4 8 18 3 18 3 11 24 +2 14 9 1 10 4 4 13 19 22 4 7 19 5 10 10 1 8 22 22 6 8 13 12 11 21 ^ +47 1 23 14 16 7 5 11 22 24 7 2 11 13 18 4 20 8 1 6 25 20 17 20 1 25 10 15 15 2 +17 13 9 24 17 24 20 13 15 17 3 11 20 10 5 13 23 18 21 ^ +57 1 3 18 15 7 5 7 4 15 20 16 2 17 1 7 4 12 7 25 14 1 4 7 19 19 20 3 13 12 4 3 +14 4 14 11 6 3 25 18 16 20 24 12 19 18 25 6 23 6 15 5 4 4 6 14 13 20 7 ^ +51 1 14 15 2 13 21 11 5 17 2 2 10 11 13 14 12 11 21 15 23 3 2 5 7 23 10 20 6 12 +1 19 10 24 21 22 25 16 12 19 22 15 10 18 24 1 5 16 10 18 2 19 8 ^ +49 0 3 5 1 7 20 7 16 6 20 6 6 25 10 22 20 2 1 15 14 23 25 23 4 11 15 15 6 9 22 +22 19 22 25 6 19 6 2 20 21 7 22 18 10 7 17 4 16 12 24 ^ +46 0 10 25 12 23 23 9 2 22 1 20 2 8 3 14 7 1 2 3 19 21 21 23 20 22 11 25 20 24 +25 1 9 21 20 14 10 14 19 9 17 15 13 5 15 24 21 14 ^ +55 0 13 25 22 21 1 16 23 7 24 15 3 22 5 25 3 4 2 9 12 24 6 19 1 14 9 5 9 1 17 9 +4 23 21 1 3 15 16 11 1 12 18 6 2 7 8 17 8 21 13 22 9 21 4 9 22 ^ +45 1 13 17 21 10 9 18 24 23 13 7 23 23 19 23 22 17 18 23 18 21 17 1 10 12 4 6 1 +21 11 18 2 6 6 12 18 13 16 16 18 19 13 11 21 19 8 ^ +50 1 12 15 16 19 2 23 19 4 1 2 25 14 11 25 24 16 8 14 21 21 16 6 13 1 23 15 8 +17 4 3 4 9 23 12 8 8 24 13 6 11 3 8 24 19 8 23 1 24 24 12 ^ +53 0 25 13 2 6 25 7 9 3 5 11 19 11 16 5 4 17 24 23 15 14 10 7 14 17 25 15 10 14 +6 18 18 4 1 13 10 16 1 25 16 2 24 5 1 17 6 17 6 24 11 7 21 9 19 ^ +51 1 8 25 5 5 22 16 13 5 2 16 4 25 25 8 18 13 13 3 1 22 23 24 18 12 21 19 2 4 +24 13 11 2 7 24 22 17 5 15 1 8 3 10 15 18 15 8 10 16 20 20 8 ^ +50 1 18 22 11 18 9 11 15 22 20 18 6 24 15 25 4 22 12 17 4 6 17 20 2 4 2 5 20 15 +19 24 18 9 8 2 5 23 2 10 21 8 5 2 9 16 16 15 6 22 23 18 ^ +48 1 6 21 5 21 24 3 6 10 17 19 9 15 11 23 16 17 1 3 12 3 20 4 5 5 3 21 22 15 4 +21 20 7 22 14 9 24 4 18 7 7 25 24 22 21 23 24 14 19 ^ +55 0 12 6 7 4 2 12 25 15 3 9 23 8 16 25 11 14 4 10 19 23 16 13 9 20 25 17 11 8 +4 19 25 17 7 16 21 6 4 8 2 15 9 2 9 19 3 6 3 3 10 25 13 15 7 8 24 ^ +56 0 21 12 10 12 5 24 11 20 3 13 13 16 9 13 10 3 9 16 3 7 15 9 9 14 2 13 17 25 +2 18 5 19 23 9 25 9 10 23 12 12 7 13 8 15 7 1 6 21 2 8 7 6 16 14 14 22 ^ +47 0 15 13 24 10 15 11 10 8 14 15 21 25 21 16 9 18 20 22 21 20 11 14 23 22 10 +13 14 8 19 12 2 11 20 23 13 4 10 6 5 7 23 11 3 16 8 21 12 ^ +49 0 4 8 18 5 12 14 8 6 20 19 24 8 23 17 3 7 19 1 18 1 14 22 13 14 5 8 22 18 14 +25 17 11 12 22 2 12 12 16 12 13 18 17 12 17 14 18 8 25 22 ^ +46 1 23 5 3 8 14 24 17 7 3 3 23 17 22 19 19 17 16 22 24 14 16 20 23 20 9 19 16 +7 12 16 5 8 9 7 10 21 24 10 11 19 1 21 14 14 19 20 ^ +57 1 22 8 12 20 1 18 5 6 5 12 14 1 1 11 9 22 3 24 9 6 1 11 16 1 12 8 11 11 17 +10 22 7 3 10 2 6 4 24 16 24 19 4 5 18 11 12 9 20 21 25 2 21 18 10 20 25 7 ^ +56 1 3 17 17 5 8 22 25 19 8 10 19 7 11 4 8 18 3 18 3 11 24 2 14 9 1 10 4 4 13 +19 22 4 7 19 5 10 10 1 8 22 22 6 8 13 12 11 17 23 14 16 7 5 11 22 24 18 ^ +54 1 2 11 13 18 4 20 8 1 6 25 20 17 20 1 25 10 15 15 2 17 13 9 24 17 24 20 13 +15 17 3 11 20 10 5 13 23 18 5 3 18 15 7 5 7 4 15 20 16 2 17 1 7 4 23 ^ +56 0 7 25 14 1 4 7 19 19 20 3 13 12 4 3 14 4 14 11 6 3 25 18 16 20 24 12 19 18 +25 6 23 6 15 5 4 4 6 14 13 20 5 14 15 2 13 21 11 5 17 2 2 10 11 13 14 24 ^ +49 0 12 11 20 3 14 2 3 2 23 12 12 17 24 11 8 6 24 16 15 22 21 14 6 12 20 19 5 5 +12 11 6 23 2 16 23 7 24 6 21 2 17 17 5 25 11 25 20 25 19 ^ +54 0 18 6 12 19 25 7 6 5 2 14 12 16 1 15 7 1 26 19 19 13 20 11 17 6 20 5 24 24 +1 21 11 9 20 21 15 10 19 26 3 2 6 7 12 9 10 8 14 10 15 5 17 8 21 7 ^ +56 0 20 25 6 19 8 3 22 16 16 16 17 13 11 10 17 15 12 6 13 14 17 4 12 10 24 5 13 +24 3 5 2 5 11 14 8 5 10 17 16 8 4 14 21 15 3 6 17 25 8 2 3 3 19 10 13 23 ^ +51 1 22 8 2 13 25 17 2 1 19 1 14 20 2 5 4 15 8 14 20 7 25 20 26 20 16 7 17 17 +22 1 13 6 5 1 18 14 15 23 15 10 5 19 18 18 26 12 13 3 25 12 18 ^ +51 1 16 24 4 16 3 6 26 26 10 20 13 1 20 24 10 21 7 25 2 25 22 9 15 16 26 5 12 1 +7 4 24 7 14 20 1 4 7 3 10 10 15 6 13 6 22 6 20 22 2 26 26 ^ +47 1 6 14 1 16 3 24 25 24 17 12 14 18 18 9 9 11 22 13 9 2 22 15 20 20 18 8 13 +13 21 8 11 5 26 8 19 17 4 2 15 26 13 24 26 11 16 9 24 ^ +52 0 8 18 21 6 1 8 1 16 4 20 23 23 24 10 11 12 10 10 25 1 11 25 10 3 26 26 20 +15 11 19 16 17 3 16 12 25 15 9 23 1 2 24 8 10 18 2 9 5 4 17 16 12 ^ +50 0 12 20 20 1 3 11 5 9 3 17 9 17 24 21 3 4 16 2 10 1 25 5 22 16 6 21 19 21 23 +15 9 9 21 17 11 1 15 17 23 24 11 7 10 26 15 8 22 22 18 16 ^ +48 0 11 17 5 26 7 23 19 3 24 17 2 19 18 26 21 12 5 18 22 20 7 15 6 4 5 20 13 10 +23 18 16 25 18 15 2 20 14 24 22 17 3 15 16 1 10 2 12 16 ^ +47 0 21 1 21 21 4 18 13 1 24 18 23 17 19 6 19 9 26 25 23 23 14 13 13 20 12 13 4 +21 10 22 21 22 1 12 12 7 13 16 18 8 9 4 3 10 18 12 25 ^ +47 1 5 19 19 12 24 13 18 1 22 8 1 17 18 24 3 22 7 7 19 26 13 26 6 26 6 18 12 5 +26 17 18 19 22 10 12 8 23 11 17 23 25 5 5 11 4 13 20 ^ +52 0 18 4 19 23 3 13 15 4 3 9 24 14 5 25 21 22 18 17 12 15 14 16 10 14 9 19 7 +16 3 23 4 26 18 5 16 21 24 2 8 8 8 7 11 13 14 7 9 12 18 11 10 20 ^ +47 1 20 12 14 19 11 21 21 22 19 13 10 16 19 14 7 8 16 20 10 3 9 23 18 7 26 16 +22 21 21 5 14 11 2 2 16 22 11 26 7 22 23 5 23 10 4 22 5 ^ +50 0 19 20 9 16 10 24 4 19 26 4 25 4 8 17 7 7 2 23 11 18 19 23 6 10 9 1 9 14 19 +5 6 6 25 12 11 21 26 12 3 8 20 8 21 18 25 25 14 4 11 25 ^ +45 1 23 4 14 3 17 26 22 26 2 15 9 8 25 19 12 23 17 20 17 10 4 23 20 17 21 14 14 +9 18 11 18 2 18 4 2 22 25 15 18 10 23 8 21 26 15 ^ +54 0 7 14 10 6 6 15 15 13 2 11 15 22 2 9 4 4 6 16 11 11 3 16 13 19 25 16 5 7 20 +22 9 25 11 24 24 25 13 8 15 23 16 6 3 18 23 16 23 8 20 4 1 1 14 16 ^ +43 1 12 24 14 14 26 23 13 26 14 21 25 25 4 9 13 5 8 9 21 8 12 26 24 9 24 15 1 +23 22 16 14 8 22 15 19 24 20 7 8 15 24 12 18 ^ +57 0 4 23 21 13 19 15 21 7 15 7 3 21 20 8 22 14 23 26 19 2 10 18 3 5 3 1 9 15 +15 3 7 13 23 9 7 1 13 17 14 25 9 16 2 2 6 13 7 19 25 17 1 5 21 2 7 22 5 ^ +55 1 6 25 3 12 19 6 2 4 24 17 9 18 20 19 4 11 14 1 6 8 26 6 9 22 4 10 2 7 21 9 +8 24 25 14 22 12 22 3 23 3 3 20 6 11 23 6 1 7 5 18 5 15 25 26 23 ^ +53 0 1 10 11 11 4 12 11 20 3 14 2 3 2 23 12 12 17 24 11 8 6 24 16 15 22 21 14 6 +12 20 19 5 5 12 11 6 23 2 16 23 7 24 6 21 2 17 17 5 25 11 25 20 26 ^ +54 0 24 18 6 12 19 25 7 6 5 2 14 12 16 1 15 7 1 26 19 19 13 20 11 17 6 20 5 24 +24 1 21 11 9 20 21 15 10 19 26 3 2 6 7 12 9 10 8 14 10 15 5 17 8 23 ^ +58 0 1 20 25 6 19 8 3 22 16 16 16 17 13 11 10 17 15 12 6 13 14 17 4 12 10 24 5 +13 24 3 5 2 5 11 14 8 5 10 17 16 8 4 14 21 15 3 6 17 25 8 2 3 3 19 10 13 22 19 ^ +52 1 8 2 13 25 17 2 1 19 1 14 20 2 5 4 15 8 14 20 7 25 20 26 20 16 7 17 17 22 1 +13 6 5 1 18 14 15 23 15 10 5 19 18 18 26 12 13 3 25 12 21 16 22 ^ +56 1 4 16 3 6 26 26 10 20 13 1 20 24 10 21 7 25 2 25 22 9 15 16 26 5 12 1 7 4 +24 7 14 20 1 4 7 3 10 10 15 6 13 6 22 6 20 22 2 26 9 6 14 1 16 3 24 12 ^ +52 0 24 17 12 14 18 18 9 9 11 22 13 9 2 22 15 20 20 18 8 13 13 21 8 11 5 26 8 +19 17 4 2 15 26 13 24 26 11 16 9 1 8 18 21 6 1 8 1 16 4 20 23 5 ^ +54 0 24 10 11 12 10 10 25 1 11 25 10 3 26 26 20 15 11 19 16 17 3 16 12 25 15 9 +23 1 2 24 8 10 18 2 9 5 4 17 16 9 12 20 20 1 3 11 5 9 3 17 9 17 24 20 ^ +49 1 3 4 16 2 10 1 25 5 22 16 6 21 19 21 23 15 9 9 21 17 11 1 15 17 23 24 11 7 +10 26 15 8 22 22 18 26 11 17 5 26 7 23 19 3 24 17 2 19 8 ^ +49 0 26 21 12 5 18 22 20 7 15 6 4 5 20 13 10 23 18 16 25 18 15 2 20 14 24 22 17 +3 15 16 1 10 2 12 2 21 1 21 21 4 18 13 1 24 18 23 17 19 23 ^ +50 1 19 9 26 25 23 23 14 13 13 20 12 13 4 21 10 22 21 22 1 12 12 7 13 16 18 8 9 +4 3 10 18 12 4 5 19 19 12 24 13 18 1 22 8 1 17 18 24 3 22 21 ^ +48 1 7 19 26 13 26 6 26 6 18 12 5 26 17 18 19 22 10 12 8 23 11 17 23 25 5 5 11 +4 13 7 18 4 19 23 3 13 15 4 3 9 24 14 5 25 21 22 18 25 ^ +53 1 12 15 14 16 10 14 9 19 7 16 3 23 4 26 18 5 16 21 24 2 8 8 8 7 11 13 14 7 9 +12 18 11 10 7 20 12 14 19 11 21 21 22 19 13 10 16 19 14 7 8 16 20 7 ^ +49 0 3 9 23 18 7 26 16 22 21 21 5 14 11 2 2 16 22 11 26 7 22 23 5 23 10 4 22 24 +19 20 9 16 10 24 4 19 26 4 25 4 8 17 7 7 2 23 11 18 19 ^ +49 0 23 6 10 9 1 9 14 19 5 6 6 25 12 11 21 26 12 3 8 20 8 21 18 25 25 14 4 11 +24 23 4 14 3 17 26 22 26 2 15 9 8 25 19 12 23 17 20 17 10 ^ +54 0 4 23 20 17 21 14 14 9 18 11 18 2 18 4 2 22 25 15 18 10 23 8 21 26 7 14 10 +6 6 15 15 13 2 11 15 22 2 9 4 4 6 16 11 11 3 16 13 19 25 16 5 7 20 23 ^ +47 0 9 25 11 24 24 25 13 8 15 23 16 6 3 18 23 16 23 8 20 4 1 1 14 13 12 24 14 +14 26 23 13 26 14 21 25 25 4 9 13 5 8 9 21 8 12 26 15 ^ +51 1 9 24 15 1 23 22 16 14 8 22 15 19 24 20 7 8 15 24 12 4 4 23 21 13 19 15 21 +7 15 7 3 21 20 8 22 14 23 26 19 2 10 18 3 5 3 1 9 15 15 3 24 ^ +60 0 13 23 9 7 1 13 17 14 25 9 16 2 2 6 13 7 19 25 17 1 5 21 2 7 22 5 6 25 3 12 +19 6 2 4 24 17 9 18 20 19 4 11 14 1 6 8 26 6 9 22 4 10 2 7 21 9 8 24 25 10 ^ +59 0 22 12 22 3 23 3 3 20 6 11 23 6 1 7 5 18 5 15 25 26 1 1 10 11 11 4 12 11 20 +3 14 2 3 2 23 12 12 17 24 11 8 6 24 16 15 22 21 14 6 12 20 19 5 5 12 11 6 23 8 ^ +50 0 16 23 7 24 6 21 2 17 17 5 25 11 25 20 25 24 18 6 12 19 25 7 6 5 2 14 12 16 +1 15 7 1 26 19 19 13 20 11 17 6 20 5 24 24 1 21 11 9 20 14 ^ +60 0 15 10 19 26 3 2 6 7 12 9 10 8 14 10 15 5 17 8 21 1 20 25 6 19 8 3 22 16 16 +16 17 13 11 10 17 15 12 6 13 14 17 4 12 10 24 5 13 24 3 5 2 5 11 14 8 5 10 17 +16 13 ^ +57 0 4 14 21 15 3 6 17 25 8 2 3 3 19 10 13 22 22 8 2 13 25 17 2 1 19 1 14 20 2 +5 4 15 8 14 20 7 25 20 26 20 16 7 17 17 22 1 13 6 5 1 18 14 15 23 15 10 21 ^ +52 1 19 18 18 26 12 13 3 25 12 21 16 24 4 16 3 6 26 26 10 20 13 1 20 24 10 21 7 +25 2 25 22 9 15 16 26 5 12 1 7 4 24 7 14 20 1 4 7 3 10 10 15 19 ^ +51 0 13 6 22 6 20 22 2 26 9 6 14 1 16 3 24 25 24 17 12 14 18 18 9 9 11 22 13 9 +2 22 15 20 20 18 8 13 13 21 8 11 5 26 8 19 17 4 2 15 26 13 21 ^ +52 1 24 26 11 16 9 1 8 18 21 6 1 8 1 16 4 20 23 23 24 10 11 12 10 10 25 1 11 25 +10 3 26 26 20 15 11 19 16 17 3 16 12 25 15 9 23 1 2 24 8 10 18 15 ^ +55 1 9 5 4 17 16 9 12 20 20 1 3 11 5 9 3 17 9 17 24 21 3 4 16 2 10 1 25 5 22 16 +6 21 19 21 23 15 9 9 21 17 11 1 15 17 23 24 11 7 10 26 15 8 22 22 11 ^ +50 1 26 11 17 5 26 7 23 19 3 24 17 2 19 18 26 21 12 5 18 22 20 7 15 6 4 5 20 13 +10 23 18 16 25 18 15 2 20 14 24 22 17 3 15 16 1 10 2 12 2 25 ^ +51 0 1 21 21 4 18 13 1 24 18 23 17 19 6 19 9 26 25 23 23 14 13 13 20 12 13 4 21 +10 22 21 22 1 12 12 7 13 16 18 8 9 4 3 10 18 12 4 5 19 19 12 24 ^ +53 1 13 18 1 22 8 1 17 18 24 3 22 7 7 19 26 13 26 6 26 6 18 12 5 26 17 18 19 22 +10 12 8 23 11 17 23 25 5 5 11 4 13 7 18 4 19 23 3 13 15 4 3 9 18 ^ +51 1 14 5 25 21 22 18 17 12 15 14 16 10 14 9 19 7 16 3 23 4 26 18 5 16 21 24 2 +8 8 8 7 11 13 14 7 9 12 18 11 10 7 20 12 14 19 11 21 21 22 19 26 ^ +49 0 10 16 19 14 7 8 16 20 10 3 9 23 18 7 26 16 22 21 21 5 14 11 2 2 16 22 11 +26 7 22 23 5 23 10 4 22 24 19 20 9 16 10 24 4 19 26 4 25 14 ^ +52 0 8 17 7 7 2 23 11 18 19 23 6 10 9 1 9 14 19 5 6 6 25 12 11 21 26 12 3 8 20 +8 21 18 25 25 14 4 11 24 23 4 14 3 17 26 22 26 2 15 9 8 25 24 ^ +55 1 12 23 17 20 17 10 4 23 20 17 21 14 14 9 18 11 18 2 18 4 2 22 25 15 18 10 +23 8 21 26 7 14 10 6 6 15 15 13 2 11 15 22 2 9 4 4 6 16 11 11 3 16 13 19 15 ^ +49 0 16 5 7 20 22 9 25 11 24 24 25 13 8 15 23 16 6 3 18 23 16 23 8 20 4 1 1 14 +13 12 24 14 14 26 23 13 26 14 21 25 25 4 9 13 5 8 9 21 9 ^ +55 0 22 24 9 27 23 1 13 18 24 1 8 24 8 6 14 1 4 5 15 27 12 20 1 17 5 4 14 25 14 +3 19 24 24 14 8 13 12 19 8 3 6 13 7 10 23 19 10 17 17 11 6 13 8 18 18 ^ +51 0 7 3 25 1 17 8 26 25 11 23 14 27 1 22 11 9 7 19 4 15 18 2 27 20 11 5 20 22 +19 15 5 6 17 8 1 19 22 9 23 10 26 27 26 14 12 3 14 15 11 2 26 ^ +50 0 6 22 20 8 25 4 25 24 23 20 3 3 16 2 2 27 2 15 14 27 3 17 12 27 27 7 26 2 +22 11 9 10 24 15 1 27 11 27 4 1 25 25 16 6 2 22 12 17 21 14 ^ +52 0 8 9 22 17 12 7 18 14 23 2 6 4 23 9 4 22 16 18 23 8 11 25 17 27 16 10 3 24 +8 20 20 18 18 13 4 2 18 22 15 25 26 9 3 1 2 19 15 1 24 17 16 18 ^ +49 0 9 14 11 8 16 19 16 22 10 16 24 25 7 22 12 20 15 23 22 18 22 14 6 26 21 10 +21 7 13 2 16 7 24 16 22 13 10 7 11 16 5 9 25 13 9 14 14 17 14 ^ +54 1 2 10 5 25 5 7 10 22 10 1 24 3 11 7 23 5 17 14 3 18 5 13 26 15 5 13 23 18 +17 3 18 3 27 15 6 25 24 22 27 17 4 25 23 15 9 15 21 8 7 7 15 3 13 25 ^ +47 0 25 3 4 10 24 12 7 16 25 18 21 21 20 27 13 14 23 27 1 21 9 21 14 22 9 9 5 +15 13 17 3 4 9 16 1 8 23 17 23 26 8 24 10 20 25 27 25 ^ +58 1 8 26 8 10 4 3 8 14 5 5 7 11 13 11 26 11 4 26 17 20 19 11 10 3 10 14 9 6 9 +7 16 10 4 4 19 19 2 26 13 19 17 15 24 15 4 21 22 13 13 12 22 2 14 20 5 18 7 25 ^ +58 0 17 24 20 13 6 17 9 20 2 10 19 3 22 4 1 11 3 5 3 21 11 15 12 23 26 5 2 27 6 +5 16 6 3 2 23 5 3 20 20 4 24 2 18 21 7 14 10 27 23 6 24 6 19 23 3 9 22 15 ^ +54 0 21 17 19 25 17 7 21 19 6 16 15 15 20 14 2 25 19 14 18 19 7 9 1 14 11 10 16 +3 23 14 26 10 11 1 18 1 12 24 19 19 1 7 2 3 24 7 12 9 2 8 16 20 24 25 ^ +49 1 26 26 4 9 2 7 25 9 8 12 18 14 26 7 17 18 4 20 1 16 14 21 26 4 6 8 24 11 25 +15 24 16 23 4 10 23 21 24 15 10 9 26 7 14 24 21 6 20 19 ^ +56 1 17 16 17 1 3 12 1 4 13 3 9 21 23 7 18 11 1 19 20 23 12 12 27 13 13 15 16 +13 1 16 15 12 26 3 16 16 8 17 13 21 4 6 5 19 14 16 4 16 11 14 18 18 27 9 13 22 ^ +51 1 3 26 22 3 7 6 4 26 3 15 8 25 1 20 13 9 11 20 6 11 21 27 25 20 7 4 18 26 16 +27 5 12 19 7 23 6 25 25 2 11 13 25 21 18 17 6 12 14 13 24 13 ^ +48 1 14 19 26 27 25 6 1 15 4 7 27 24 27 21 5 27 19 18 8 21 3 23 20 21 25 21 1 9 +17 22 5 22 8 2 13 27 8 19 27 21 2 5 8 4 27 10 6 25 ^ +52 0 2 6 1 1 26 18 13 5 10 18 10 8 5 21 15 5 14 19 12 4 8 20 21 26 1 12 25 10 2 +17 10 15 2 20 25 26 23 25 12 16 15 9 18 15 19 21 16 26 11 18 20 26 ^ +53 0 6 22 7 8 8 12 2 21 18 12 11 5 19 3 19 27 18 25 22 22 23 16 2 1 20 16 14 22 +6 15 22 1 21 6 6 10 2 26 12 11 6 27 14 7 20 26 20 17 7 19 5 23 14 ^ +61 0 16 12 7 15 17 7 5 11 12 15 7 1 10 10 8 4 2 4 17 4 11 17 26 23 24 4 5 12 5 +1 6 9 6 8 27 5 11 11 24 24 13 17 2 24 26 19 11 22 21 2 2 14 21 13 1 23 10 25 8 +15 13 ^ +52 0 19 23 2 9 26 6 23 13 5 24 12 21 11 14 4 12 10 12 22 4 3 20 17 10 13 16 9 +10 27 9 12 13 20 10 12 23 23 11 19 13 25 22 8 1 5 16 20 9 19 9 24 26 ^ +51 0 12 15 6 21 27 22 26 24 18 9 15 8 22 24 9 27 23 1 13 18 24 1 8 24 8 6 14 1 +4 5 15 27 12 20 1 17 5 4 14 25 14 3 19 24 24 14 8 13 12 19 22 ^ +56 0 3 6 13 7 10 23 19 10 17 17 11 6 13 8 18 6 7 3 25 1 17 8 26 25 11 23 14 27 +1 22 11 9 7 19 4 15 18 2 27 20 11 5 20 22 19 15 5 6 17 8 1 19 22 9 23 17 ^ +50 0 26 27 26 14 12 3 14 15 11 2 12 6 22 20 8 25 4 25 24 23 20 3 3 16 2 2 27 2 +15 14 27 3 17 12 27 27 7 26 2 22 11 9 10 24 15 1 27 11 27 21 ^ +52 0 1 25 25 16 6 2 22 12 17 21 12 8 9 22 17 12 7 18 14 23 2 6 4 23 9 4 22 16 +18 23 8 11 25 17 27 16 10 3 24 8 20 20 18 18 13 4 2 18 22 15 25 10 ^ +52 0 9 3 1 2 19 15 1 24 17 16 18 9 14 11 8 16 19 16 22 10 16 24 25 7 22 12 20 +15 23 22 18 22 14 6 26 21 10 21 7 13 2 16 7 24 16 22 13 10 7 11 16 13 ^ +53 1 9 25 13 9 14 14 17 25 2 10 5 25 5 7 10 22 10 1 24 3 11 7 23 5 17 14 3 18 5 +13 26 15 5 13 23 18 17 3 18 3 27 15 6 25 24 22 27 17 4 25 23 15 15 ^ +52 1 15 21 8 7 7 15 3 13 22 25 3 4 10 24 12 7 16 25 18 21 21 20 27 13 14 23 27 +1 21 9 21 14 22 9 9 5 15 13 17 3 4 9 16 1 8 23 17 23 26 8 24 14 ^ +58 0 20 25 27 3 8 26 8 10 4 3 8 14 5 5 7 11 13 11 26 11 4 26 17 20 19 11 10 3 +10 14 9 6 9 7 16 10 4 4 19 19 2 26 13 19 17 15 24 15 4 21 22 13 13 12 22 2 14 +18 ^ +60 0 5 18 7 17 24 20 13 6 17 9 20 2 10 19 3 22 4 1 11 3 5 3 21 11 15 12 23 26 5 +2 27 6 5 16 6 3 2 23 5 3 20 20 4 24 2 18 21 7 14 10 27 23 6 24 6 19 23 3 9 25 ^ +55 0 16 21 17 19 25 17 7 21 19 6 16 15 15 20 14 2 25 19 14 18 19 7 9 1 14 11 10 +16 3 23 14 26 10 11 1 18 1 12 24 19 19 1 7 2 3 24 7 12 9 2 8 16 20 24 27 ^ +51 1 26 26 4 9 2 7 25 9 8 12 18 14 26 7 17 18 4 20 1 16 14 21 26 4 6 8 24 11 25 +15 24 16 23 4 10 23 21 24 15 10 9 26 7 14 24 21 6 20 5 17 15 ^ +57 0 17 1 3 12 1 4 13 3 9 21 23 7 18 11 1 19 20 23 12 12 27 13 13 15 16 13 1 16 +15 12 26 3 16 16 8 17 13 21 4 6 5 19 14 16 4 16 11 14 18 18 27 9 13 21 3 26 23 ^ +52 0 3 7 6 4 26 3 15 8 25 1 20 13 9 11 20 6 11 21 27 25 20 7 4 18 26 16 27 5 12 +19 7 23 6 25 25 2 11 13 25 21 18 17 6 12 14 13 24 11 14 19 26 12 ^ +55 1 25 6 1 15 4 7 27 24 27 21 5 27 19 18 8 21 3 23 20 21 25 21 1 9 17 22 5 22 +8 2 13 27 8 19 27 21 2 5 8 4 27 10 6 18 2 6 1 1 26 18 13 5 10 18 11 ^ +52 0 8 5 21 15 5 14 19 12 4 8 20 21 26 1 12 25 10 2 17 10 15 2 20 25 26 23 25 +12 16 15 9 18 15 19 21 16 26 11 18 20 6 22 7 8 8 12 2 21 18 12 11 27 ^ +53 1 19 3 19 27 18 25 22 22 23 16 2 1 20 16 14 22 6 15 22 1 21 6 6 10 2 26 12 +11 6 27 14 7 20 26 20 17 7 19 5 23 18 16 12 7 15 17 7 5 11 12 15 7 22 ^ +57 1 10 10 8 4 2 4 17 4 11 17 26 23 24 4 5 12 5 1 6 9 6 8 27 5 11 11 24 24 13 +17 2 24 26 19 11 22 21 2 2 14 21 13 1 23 10 25 8 15 26 19 23 2 9 26 6 23 22 ^ +52 1 5 24 12 21 11 14 4 12 10 12 22 4 3 20 17 10 13 16 9 10 27 9 12 13 20 10 12 +23 23 11 19 13 25 22 8 1 5 16 20 9 19 9 24 20 12 15 6 21 27 22 26 16 ^ +58 0 18 9 15 8 22 24 9 27 23 1 13 18 24 1 8 24 8 6 14 1 4 5 15 27 12 20 1 17 5 +4 14 25 14 3 19 24 24 14 8 13 12 19 8 3 6 13 7 10 23 19 10 17 17 11 6 13 8 22 ^ +55 0 6 7 3 25 1 17 8 26 25 11 23 14 27 1 22 11 9 7 19 4 15 18 2 27 20 11 5 20 +22 19 15 5 6 17 8 1 19 22 9 23 10 26 27 26 14 12 3 14 15 11 2 12 6 22 16 ^ +53 0 8 25 4 25 24 23 20 3 3 16 2 2 27 2 15 14 27 3 17 12 27 27 7 26 2 22 11 9 +10 24 15 1 27 11 27 4 1 25 25 16 6 2 22 12 17 21 12 8 9 22 17 12 18 ^ +54 0 7 18 14 23 2 6 4 23 9 4 22 16 18 23 8 11 25 17 27 16 10 3 24 8 20 20 18 18 +13 4 2 18 22 15 25 26 9 3 1 2 19 15 1 24 17 16 18 9 14 11 8 16 19 27 ^ +52 0 22 10 16 24 25 7 22 12 20 15 23 22 18 22 14 6 26 21 10 21 7 13 2 16 7 24 +16 22 13 10 7 11 16 5 9 25 13 9 14 14 17 25 2 10 5 25 5 7 10 22 10 22 ^ +54 1 24 3 11 7 23 5 17 14 3 18 5 13 26 15 5 13 23 18 17 3 18 3 27 15 6 25 24 22 +27 17 4 25 23 15 9 15 21 8 7 7 15 3 13 22 25 3 4 10 24 12 7 16 25 10 ^ +56 0 21 21 20 27 13 14 23 27 1 21 9 21 14 22 9 9 5 15 13 17 3 4 9 16 1 8 23 17 +23 26 8 24 10 20 25 27 3 8 26 8 10 4 3 8 14 5 5 7 11 13 11 26 11 4 26 2 ^ +61 1 20 19 11 10 3 10 14 9 6 9 7 16 10 4 4 19 19 2 26 13 19 17 15 24 15 4 21 22 +13 13 12 22 2 14 20 5 18 7 17 24 20 13 6 17 9 20 2 10 19 3 22 4 1 11 3 5 3 21 +11 15 22 ^ +53 0 23 26 5 2 27 6 5 16 6 3 2 23 5 3 20 20 4 24 2 18 21 7 14 10 27 23 6 24 6 +19 23 3 9 22 16 21 17 19 25 17 7 21 19 6 16 15 15 20 14 2 25 19 25 ^ +60 0 18 19 7 9 1 14 11 10 16 3 23 14 26 10 11 1 18 1 12 24 19 19 1 7 2 3 24 7 +12 9 2 8 16 20 24 5 26 26 4 9 2 7 25 9 8 12 18 14 26 7 17 18 4 20 1 16 14 21 26 +18 ^ +54 0 6 8 24 11 25 15 24 16 23 4 10 23 21 24 15 10 9 26 7 14 24 21 6 20 5 17 16 +17 1 3 12 1 4 13 3 9 21 23 7 18 11 1 19 20 23 12 12 27 13 13 15 16 13 24 ^ +57 0 1 16 15 12 26 3 16 16 8 17 13 21 4 6 5 19 14 16 4 16 11 14 18 18 27 9 13 +21 3 26 22 3 7 6 4 26 3 15 8 25 1 20 13 9 11 20 6 11 21 27 25 20 7 4 18 26 10 ^ +48 0 27 5 12 19 7 23 6 25 25 2 11 13 25 21 18 17 6 12 14 13 24 11 14 19 26 27 +25 6 1 15 4 7 27 24 27 21 5 27 19 18 8 21 3 23 20 21 25 8 ^ +60 1 1 9 17 22 5 22 8 2 13 27 8 19 27 21 2 5 8 4 27 10 6 18 2 6 1 1 26 18 13 5 +10 18 10 8 5 21 15 5 14 19 12 4 8 20 21 26 1 12 25 10 2 17 10 15 2 20 25 26 23 +21 ^ +54 1 12 16 15 9 18 15 19 21 16 26 11 18 20 6 22 7 8 8 12 2 21 18 12 11 5 19 3 +19 27 18 25 22 22 23 16 2 1 20 16 14 22 6 15 22 1 21 6 6 10 2 26 12 11 24 ^ +60 0 27 14 7 20 26 20 17 7 19 5 23 18 16 12 7 15 17 7 5 11 12 15 7 1 10 10 8 4 +2 4 17 4 11 17 26 23 24 4 5 12 5 1 6 9 6 8 27 5 11 11 24 24 13 17 2 24 26 19 11 +22 ^ +55 0 21 2 2 14 21 13 1 23 10 25 8 15 26 19 23 2 9 26 6 23 13 5 24 12 21 11 14 4 +12 10 12 22 4 3 20 17 10 13 16 9 10 27 9 12 13 20 10 12 23 23 11 19 13 25 13 ^ +55 0 8 1 5 16 20 9 19 9 24 20 12 15 6 21 27 22 26 24 18 9 15 8 22 24 9 27 23 1 +13 18 24 1 8 24 8 6 14 1 4 5 15 27 12 20 1 17 5 4 14 25 14 3 19 24 16 ^ +60 0 14 8 13 12 19 8 3 6 13 7 10 23 19 10 17 17 11 6 13 8 18 6 7 3 25 1 17 8 26 +25 11 23 14 27 1 22 11 9 7 19 4 15 18 2 27 20 11 5 20 22 19 15 5 6 17 8 1 19 22 +10 ^ +55 1 15 9 11 26 19 22 27 2 21 8 20 23 26 12 10 21 9 15 13 25 7 26 1 13 5 9 1 3 +9 21 22 7 1 23 28 1 2 8 22 12 18 28 5 18 14 7 11 17 20 20 7 21 13 8 22 ^ +52 1 21 22 2 16 20 15 28 9 3 22 13 10 23 4 16 11 14 1 10 8 14 14 15 18 13 12 21 +18 25 15 27 17 5 1 23 7 17 20 11 14 10 4 21 17 19 25 17 22 18 21 19 17 ^ +57 0 10 15 26 20 8 13 19 7 8 18 7 12 14 6 8 22 21 11 10 14 23 25 9 15 22 18 6 +17 24 7 13 6 12 7 2 18 18 26 13 13 16 8 24 10 3 26 9 20 1 12 2 14 13 23 12 25 5 +^ +57 0 24 11 6 3 8 27 8 21 26 3 11 19 18 5 5 25 26 24 4 23 15 15 23 21 24 5 15 21 +3 3 18 2 24 27 11 20 10 11 4 5 12 2 23 6 5 3 1 14 26 15 12 6 28 12 19 20 9 ^ +55 0 6 23 4 7 7 3 10 24 28 6 10 9 6 20 14 27 10 19 11 1 15 21 5 10 7 11 8 16 9 +27 5 2 6 6 27 20 24 21 2 20 16 14 24 17 15 3 2 26 25 25 14 24 20 28 28 ^ +59 1 17 5 9 10 25 20 12 9 18 3 16 4 10 7 18 23 17 2 8 1 28 7 2 15 5 18 11 23 2 +1 18 22 14 7 20 21 2 11 12 3 15 12 4 1 27 21 16 27 19 18 13 21 14 5 20 9 19 27 +25 ^ +55 0 3 5 16 16 22 2 13 7 4 13 19 27 15 7 16 25 3 4 4 17 12 13 11 12 26 6 1 10 +15 18 4 19 10 27 9 4 25 13 21 25 26 21 20 12 25 21 7 17 28 27 3 13 14 19 18 ^ +53 1 23 19 4 28 3 20 18 9 7 15 4 26 5 6 20 5 23 28 10 24 19 13 28 1 9 12 23 16 +10 13 2 19 21 6 25 22 28 23 16 7 20 4 2 22 11 26 22 6 9 17 11 21 10 ^ +47 0 1 3 28 11 27 25 12 8 26 26 28 24 13 22 17 6 4 24 15 17 18 4 22 23 9 24 12 +27 27 25 9 13 15 11 9 22 28 26 11 18 15 10 6 16 17 14 24 ^ +55 1 25 27 16 28 22 24 1 1 11 7 24 3 28 7 5 28 16 15 1 7 14 9 7 6 15 25 19 9 3 +19 23 1 26 20 17 17 1 16 24 9 16 8 15 6 21 17 22 9 28 8 8 5 4 24 26 ^ +47 1 14 4 21 26 23 7 8 27 23 23 22 19 24 25 16 19 12 22 10 20 3 7 14 1 20 6 26 +23 27 4 16 20 18 12 20 15 19 16 18 20 27 11 11 17 24 18 16 ^ +50 0 19 1 25 23 2 15 16 26 27 23 14 12 28 22 15 8 19 2 20 13 1 24 2 25 1 6 19 +19 8 11 24 24 21 13 27 5 11 28 17 7 25 6 23 24 14 25 12 5 13 25 ^ +60 0 2 5 8 10 16 11 5 26 18 19 21 3 12 11 13 4 14 22 22 14 16 13 3 22 16 23 5 +19 6 13 10 26 17 27 26 4 3 25 6 14 2 3 5 7 23 11 22 8 25 2 9 25 18 17 8 2 14 4 +19 22 ^ +54 1 5 27 13 9 2 27 28 2 17 23 10 27 18 26 7 22 16 3 27 1 26 21 28 10 3 6 2 2 +10 17 13 16 6 17 21 23 13 20 22 5 6 11 12 12 8 23 13 17 9 23 20 3 28 21 ^ +56 0 12 17 25 28 19 5 21 4 27 8 1 19 14 20 6 7 9 1 6 22 3 19 26 14 8 6 7 19 15 +23 1 17 16 6 26 14 5 22 25 4 7 10 16 21 10 18 19 24 16 23 8 3 17 28 18 13 ^ +58 0 2 5 3 21 21 15 6 24 1 4 24 18 10 22 1 21 12 5 4 4 20 25 24 26 8 25 11 2 7 +27 22 19 4 18 27 10 28 4 12 24 8 16 12 11 16 17 25 8 12 16 1 9 9 10 5 24 23 11 ^ +62 1 5 14 18 8 4 9 5 17 8 28 1 22 4 11 3 2 17 3 14 9 27 13 18 24 9 8 7 28 25 14 +21 27 24 6 18 16 2 12 15 9 14 10 1 8 17 4 6 15 26 11 15 2 28 20 26 16 3 7 5 8 9 +24 ^ +50 1 10 12 25 11 9 13 24 15 20 2 4 8 2 22 20 19 4 15 14 28 13 25 10 10 12 28 24 +22 26 28 15 9 11 26 19 22 27 2 21 8 20 23 26 12 10 21 9 15 13 17 ^ +60 1 7 26 1 13 5 9 1 3 9 21 22 7 1 23 28 1 2 8 22 12 18 28 5 18 14 7 11 17 20 +20 7 21 13 8 28 21 22 2 16 20 15 28 9 3 22 13 10 23 4 16 11 14 1 10 8 14 14 15 +18 17 ^ +52 0 12 21 18 25 15 27 17 5 1 23 7 17 20 11 14 10 4 21 17 19 25 17 22 18 21 19 +17 10 15 26 20 8 13 19 7 8 18 7 12 14 6 8 22 21 11 10 14 23 25 9 15 19 ^ +57 1 18 6 17 24 7 13 6 12 7 2 18 18 26 13 13 16 8 24 10 3 26 9 20 1 12 2 14 13 +23 12 25 3 24 11 6 3 8 27 8 21 26 3 11 19 18 5 5 25 26 24 4 23 15 15 23 21 12 ^ +67 1 5 15 21 3 3 18 2 24 27 11 20 10 11 4 5 12 2 23 6 5 3 1 14 26 15 12 6 28 12 +19 20 6 23 4 7 7 3 10 24 28 6 10 9 6 20 14 27 10 19 11 1 15 21 5 10 7 11 8 16 9 +27 5 2 6 6 27 2 ^ +56 1 24 21 2 20 16 14 24 17 15 3 2 26 25 25 14 24 20 28 14 17 5 9 10 25 20 12 9 +18 3 16 4 10 7 18 23 17 2 8 1 28 7 2 15 5 18 11 23 2 1 18 22 14 7 20 21 24 ^ +60 1 11 12 3 15 12 4 1 27 21 16 27 19 18 13 21 14 5 20 9 19 27 6 3 5 16 16 22 2 +13 7 4 13 19 27 15 7 16 25 3 4 4 17 12 13 11 12 26 6 1 10 15 18 4 19 10 27 9 4 +25 27 ^ +51 0 21 25 26 21 20 12 25 21 7 17 28 27 3 13 14 19 3 23 19 4 28 3 20 18 9 7 15 +4 26 5 6 20 5 23 28 10 24 19 13 28 1 9 12 23 16 10 13 2 19 21 23 ^ +49 1 25 22 28 23 16 7 20 4 2 22 11 26 22 6 9 17 11 21 5 1 3 28 11 27 25 12 8 26 +26 28 24 13 22 17 6 4 24 15 17 18 4 22 23 9 24 12 27 27 9 ^ +56 0 9 13 15 11 9 22 28 26 11 18 15 10 6 16 17 14 11 25 27 16 28 22 24 1 1 11 7 +24 3 28 7 5 28 16 15 1 7 14 9 7 6 15 25 19 9 3 19 23 1 26 20 17 17 1 16 16 ^ +51 0 9 16 8 15 6 21 17 22 9 28 8 8 5 4 24 27 14 4 21 26 23 7 8 27 23 23 22 19 +24 25 16 19 12 22 10 20 3 7 14 1 20 6 26 23 27 4 16 20 18 12 22 ^ +51 0 15 19 16 18 20 27 11 11 17 24 18 1 19 1 25 23 2 15 16 26 27 23 14 12 28 22 +15 8 19 2 20 13 1 24 2 25 1 6 19 19 8 11 24 24 21 13 27 5 11 28 16 ^ +59 0 7 25 6 23 24 14 25 12 5 13 26 2 5 8 10 16 11 5 26 18 19 21 3 12 11 13 4 14 +22 22 14 16 13 3 22 16 23 5 19 6 13 10 26 17 27 26 4 3 25 6 14 2 3 5 7 23 11 22 +10 ^ +59 0 25 2 9 25 18 17 8 2 14 4 19 1 5 27 13 9 2 27 28 2 17 23 10 27 18 26 7 22 +16 3 27 1 26 21 28 10 3 6 2 2 10 17 13 16 6 17 21 23 13 20 22 5 6 11 12 12 8 23 +7 ^ +56 1 17 9 23 20 3 28 27 12 17 25 28 19 5 21 4 27 8 1 19 14 20 6 7 9 1 6 22 3 19 +26 14 8 6 7 19 15 23 1 17 16 6 26 14 5 22 25 4 7 10 16 21 10 18 19 24 16 ^ +57 1 23 8 3 17 28 18 10 2 5 3 21 21 15 6 24 1 4 24 18 10 22 1 21 12 5 4 4 20 25 +24 26 8 25 11 2 7 27 22 19 4 18 27 10 28 4 12 24 8 16 12 11 16 17 25 8 12 18 ^ +63 0 1 9 9 10 5 24 23 18 5 14 18 8 4 9 5 17 8 28 1 22 4 11 3 2 17 3 14 9 27 13 +18 24 9 8 7 28 25 14 21 27 24 6 18 16 2 12 15 9 14 10 1 8 17 4 6 15 26 11 15 2 +28 20 16 ^ +52 1 16 3 7 5 8 9 26 10 12 25 11 9 13 24 15 20 2 4 8 2 22 20 19 4 15 14 28 13 +25 10 10 12 28 24 22 26 28 15 9 11 26 19 22 27 2 21 8 20 23 26 12 28 ^ +60 0 21 9 15 13 25 7 26 1 13 5 9 1 3 9 21 22 7 1 23 28 1 2 8 22 12 18 28 5 18 +14 7 11 17 20 20 7 21 13 8 28 21 22 2 16 20 15 28 9 3 22 13 10 23 4 16 11 14 1 +10 20 ^ +54 1 14 14 15 18 13 12 21 18 25 15 27 17 5 1 23 7 17 20 11 14 10 4 21 17 19 25 +17 22 18 21 19 17 10 15 26 20 8 13 19 7 8 18 7 12 14 6 8 22 21 11 10 14 23 11 ^ +58 0 9 15 22 18 6 17 24 7 13 6 12 7 2 18 18 26 13 13 16 8 24 10 3 26 9 20 1 12 +2 14 13 23 12 25 3 24 11 6 3 8 27 8 21 26 3 11 19 18 5 5 25 26 24 4 23 15 15 27 +^ +64 1 21 24 5 15 21 3 3 18 2 24 27 11 20 10 11 4 5 12 2 23 6 5 3 1 14 26 15 12 6 +28 12 19 20 6 23 4 7 7 3 10 24 28 6 10 9 6 20 14 27 10 19 11 1 15 21 5 10 7 11 +8 16 9 27 20 ^ +58 1 2 6 6 27 20 24 21 2 20 16 14 24 17 15 3 2 26 25 25 14 24 20 28 14 17 5 9 +10 25 20 12 9 18 3 16 4 10 7 18 23 17 2 8 1 28 7 2 15 5 18 11 23 2 1 18 22 14 +28 ^ +62 0 20 21 2 11 12 3 15 12 4 1 27 21 16 27 19 18 13 21 14 5 20 9 19 27 6 3 5 16 +16 22 2 13 7 4 13 19 27 15 7 16 25 3 4 4 17 12 13 11 12 26 6 1 10 15 18 4 19 10 +27 9 4 26 ^ +52 0 13 21 25 26 21 20 12 25 21 7 17 28 27 3 13 14 19 3 23 19 4 28 3 20 18 9 7 +15 4 26 5 6 20 5 23 28 10 24 19 13 28 1 9 12 23 16 10 13 2 19 21 27 ^ +49 1 25 22 28 23 16 7 20 4 2 22 11 26 22 6 9 17 11 21 5 1 3 28 11 27 25 12 8 26 +26 28 24 13 22 17 6 4 24 15 17 18 4 22 23 9 24 12 27 27 26 ^ +57 0 9 13 15 11 9 22 28 26 11 18 15 10 6 16 17 14 11 25 27 16 28 22 24 1 1 11 7 +24 3 28 7 5 28 16 15 1 7 14 9 7 6 15 25 19 9 3 19 23 1 26 20 17 17 1 16 24 9 ^ +52 1 9 16 8 15 6 21 17 22 9 28 8 8 5 4 24 27 14 4 21 26 23 7 8 27 23 23 22 19 +24 25 16 19 12 22 10 20 3 7 14 1 20 6 26 23 27 4 16 20 18 12 20 19 ^ +52 1 19 16 18 20 27 11 11 17 24 18 1 19 1 25 23 2 15 16 26 27 23 14 12 28 22 15 +8 19 2 20 13 1 24 2 25 1 6 19 19 8 11 24 24 21 13 27 5 11 28 17 7 24 ^ +59 0 6 23 24 14 25 12 5 13 26 2 5 8 10 16 11 5 26 18 19 21 3 12 11 13 4 14 22 +22 14 16 13 3 22 16 23 5 19 6 13 10 26 17 27 26 4 3 25 6 14 2 3 5 7 23 11 22 8 +25 26 ^ +59 0 9 25 18 17 8 2 14 4 19 1 5 27 13 9 2 27 28 2 17 23 10 27 18 26 7 22 16 3 +27 1 26 21 28 10 3 6 2 2 10 17 13 16 6 17 21 23 13 20 22 5 6 11 12 12 8 23 13 +17 21 ^ +56 1 23 20 3 28 27 12 17 25 28 19 5 21 4 27 8 1 19 14 20 6 7 9 1 6 22 3 19 26 +14 8 6 7 19 15 23 1 17 16 6 26 14 5 22 25 4 7 10 16 21 10 18 19 24 16 23 20 ^ +60 0 3 17 28 18 10 2 5 3 21 21 15 6 24 1 4 24 18 10 22 1 21 12 5 4 4 20 25 24 +26 8 25 11 2 7 27 22 19 4 18 27 10 28 4 12 24 8 16 12 11 16 17 25 8 12 16 1 9 9 +10 21 ^ +60 0 24 23 18 5 14 18 8 4 9 5 17 8 28 1 22 4 11 3 2 17 3 14 9 27 13 18 24 9 8 7 +28 25 14 21 27 24 6 18 16 2 12 15 9 14 10 1 8 17 4 6 15 26 11 15 2 28 20 26 16 +25 ^ +53 1 7 5 8 9 26 10 12 25 11 9 13 24 15 20 2 4 8 2 22 20 19 4 15 14 28 13 25 10 +10 12 28 24 22 26 28 15 9 11 26 19 22 27 2 21 8 20 23 26 12 10 21 9 24 ^ +62 1 13 25 7 26 1 13 5 9 1 3 9 21 22 7 1 23 28 1 2 8 22 12 18 28 5 18 14 7 11 +17 20 20 7 21 13 8 28 21 22 2 16 20 15 28 9 3 22 13 10 23 4 16 11 14 1 10 8 14 +14 15 18 13 ^ +54 0 12 21 18 25 15 27 17 5 1 23 7 17 20 11 14 10 4 21 17 19 25 17 22 18 21 19 +17 10 15 26 20 8 13 19 7 8 18 7 12 14 6 8 22 21 11 10 14 23 25 9 15 22 18 13 ^ +58 0 17 24 7 13 6 12 7 2 18 18 26 13 13 16 8 24 10 3 26 9 20 1 12 2 14 13 23 12 +25 3 24 11 6 3 8 27 8 21 26 3 11 19 18 5 5 25 26 24 4 23 15 15 23 21 24 5 15 26 +^ +67 1 3 3 18 2 24 27 11 20 10 11 4 5 12 2 23 6 5 3 1 14 26 15 12 6 28 12 19 20 6 +23 4 7 7 3 10 24 28 6 10 9 6 20 14 27 10 19 11 1 15 21 5 10 7 11 8 16 9 27 5 2 +6 6 27 20 24 21 12 ^ +62 0 20 16 14 24 17 15 3 2 26 25 25 14 24 20 28 14 17 5 9 10 25 20 12 9 18 3 16 +4 10 7 18 23 17 2 8 1 28 7 2 15 5 18 11 23 2 1 18 22 14 7 20 21 2 11 12 3 15 12 +4 1 27 18 ^ +61 1 4 9 14 16 15 8 11 21 20 10 10 21 23 20 2 11 23 1 11 1 5 3 23 16 15 27 14 5 +16 3 22 2 3 24 3 19 29 4 4 10 8 20 14 15 1 26 12 27 25 4 28 22 11 19 19 24 5 20 +8 9 26 ^ +55 1 25 19 17 19 15 7 24 24 21 3 20 16 8 3 17 28 18 29 9 23 9 10 29 4 12 24 15 +5 8 22 17 29 12 3 8 29 15 21 21 4 7 20 7 10 7 26 10 16 24 6 7 12 8 12 28 ^ +52 1 24 9 17 11 28 12 26 26 6 29 13 10 20 6 23 10 4 3 26 26 14 20 20 25 14 13 +15 24 14 11 4 23 27 24 20 9 16 17 24 13 12 6 1 14 26 25 7 8 21 1 19 27 ^ +65 0 3 2 2 17 21 13 5 9 21 28 9 1 13 2 21 8 24 1 3 27 13 18 19 4 15 12 5 2 16 +27 16 6 2 1 23 17 14 28 19 23 6 22 16 4 19 6 16 28 3 3 1 15 13 22 6 15 11 6 4 +24 25 15 19 23 12 ^ +55 0 1 9 15 10 12 7 25 11 25 2 27 6 6 18 4 13 1 4 11 25 17 6 29 21 24 27 21 17 +17 26 24 13 4 22 24 29 2 11 8 17 4 23 11 26 1 25 28 15 19 10 3 9 29 27 24 ^ +53 1 22 3 27 21 2 26 19 9 19 27 23 3 12 17 10 4 8 27 19 16 1 21 23 28 23 18 8 +25 18 26 20 8 17 19 2 4 11 7 18 6 24 2 25 25 5 27 20 3 28 20 18 21 11 ^ +55 0 25 10 1 28 28 29 16 20 19 26 16 21 6 23 15 28 26 28 7 15 18 11 5 17 20 26 +1 10 14 8 4 16 26 17 8 10 22 22 18 1 20 24 7 1 9 7 19 5 22 1 4 26 11 10 20 ^ +58 0 5 14 2 6 4 2 9 22 15 13 20 22 26 18 16 9 2 15 20 27 8 6 17 5 15 9 25 10 26 +4 5 27 5 19 21 5 6 11 29 19 8 2 24 26 22 19 18 17 23 14 21 14 22 13 20 5 29 12 ^ +54 0 5 26 6 21 29 3 5 12 16 11 13 16 18 18 10 11 20 21 12 11 12 22 14 19 3 21 +15 6 25 26 29 24 19 17 18 25 22 12 13 23 23 12 10 13 1 22 10 2 22 2 28 10 17 28 +^ +56 0 3 6 19 28 17 11 1 9 14 4 29 29 23 25 13 19 18 2 7 21 6 8 29 5 11 22 14 14 +9 28 13 25 24 28 8 14 9 3 14 18 26 9 9 12 13 17 25 16 5 8 4 24 10 24 23 25 ^ +49 0 29 21 9 18 28 25 11 3 16 4 21 25 3 4 18 12 12 29 26 13 26 23 26 7 23 10 9 +27 26 21 25 21 18 9 24 16 22 5 21 7 7 27 4 20 23 13 27 10 27 ^ +58 1 29 7 19 13 13 8 19 20 18 2 19 22 29 3 10 6 9 13 24 17 16 9 20 21 27 2 19 7 +8 26 25 12 2 14 3 1 1 16 12 20 28 24 12 5 24 25 20 1 12 25 9 2 6 20 15 14 29 20 +^ +56 0 21 28 1 17 6 17 27 1 2 10 16 19 5 14 10 27 11 17 3 29 14 27 17 5 2 18 20 +11 27 18 22 27 22 9 8 18 3 14 10 5 2 24 18 23 21 26 8 22 8 1 6 27 27 15 29 18 ^ +64 0 2 29 22 8 16 20 4 12 9 6 12 16 16 7 9 20 29 11 9 4 1 15 25 16 29 10 22 7 2 +8 5 18 14 23 24 4 6 26 3 11 6 12 1 7 14 24 14 6 10 21 16 23 29 25 6 14 17 2 12 +10 5 10 15 25 ^ +62 1 8 15 3 7 13 25 16 14 1 29 22 26 15 27 9 1 8 8 28 6 13 5 13 3 15 5 23 8 23 +2 5 5 4 17 13 14 7 17 12 27 3 18 5 7 5 26 18 15 22 28 16 13 7 2 23 19 25 29 17 +7 16 22 ^ +55 1 23 11 11 15 2 13 9 26 2 24 26 7 28 11 2 29 7 22 23 5 28 19 1 27 29 1 24 11 +18 20 3 13 11 7 3 15 17 24 1 18 13 6 3 25 27 16 28 18 24 8 23 7 29 28 15 ^ +52 0 28 14 12 28 27 22 4 14 25 1 3 9 7 11 14 15 16 10 19 12 19 11 20 13 28 4 27 +28 7 27 12 4 28 21 17 22 20 17 15 15 23 22 13 12 21 22 21 11 12 14 12 28 ^ +62 0 27 8 7 4 9 14 16 15 8 11 21 20 10 10 21 23 20 2 11 23 1 11 1 5 3 23 16 15 +27 14 5 16 3 22 2 3 24 3 19 29 4 4 10 8 20 14 15 1 26 12 27 25 4 28 22 11 19 19 +24 5 20 18 ^ +58 0 9 5 25 19 17 19 15 7 24 24 21 3 20 16 8 3 17 28 18 29 9 23 9 10 29 4 12 24 +15 5 8 22 17 29 12 3 8 29 15 21 21 4 7 20 7 10 7 26 10 16 24 6 7 12 8 12 15 16 ^ +56 0 9 17 11 28 12 26 26 6 29 13 10 20 6 23 10 4 3 26 26 14 20 20 25 14 13 15 +24 14 11 4 23 27 24 20 9 16 17 24 13 12 6 1 14 26 25 7 8 21 1 19 3 2 2 17 21 23 +^ +64 1 5 9 21 28 9 1 13 2 21 8 24 1 3 27 13 18 19 4 15 12 5 2 16 27 16 6 2 1 23 +17 14 28 19 23 6 22 16 4 19 6 16 28 3 3 1 15 13 22 6 15 11 6 4 24 25 15 19 23 +28 1 9 15 10 24 ^ +54 0 7 25 11 25 2 27 6 6 18 4 13 1 4 11 25 17 6 29 21 24 27 21 17 17 26 24 13 4 +22 24 29 2 11 8 17 4 23 11 26 1 25 28 15 19 10 3 9 29 27 7 22 3 27 29 ^ +54 1 2 26 19 9 19 27 23 3 12 17 10 4 8 27 19 16 1 21 23 28 23 18 8 25 18 26 20 +8 17 19 2 4 11 7 18 6 24 2 25 25 5 27 20 3 28 20 18 21 10 25 10 1 28 27 ^ +60 0 29 16 20 19 26 16 21 6 23 15 28 26 28 7 15 18 11 5 17 20 26 1 10 14 8 4 16 +26 17 8 10 22 22 18 1 20 24 7 1 9 7 19 5 22 1 4 26 11 10 28 5 14 2 6 4 2 9 22 +15 22 ^ +54 1 20 22 26 18 16 9 2 15 20 27 8 6 17 5 15 9 25 10 26 4 5 27 5 19 21 5 6 11 +29 19 8 2 24 26 22 19 18 17 23 14 21 14 22 13 20 5 29 6 5 26 6 21 29 28 ^ +57 1 5 12 16 11 13 16 18 18 10 11 20 21 12 11 12 22 14 19 3 21 15 6 25 26 29 24 +19 17 18 25 22 12 13 23 23 12 10 13 1 22 10 2 22 2 28 10 17 18 3 6 19 28 17 11 +1 9 23 ^ +54 0 14 4 29 29 23 25 13 19 18 2 7 21 6 8 29 5 11 22 14 14 9 28 13 25 24 28 8 +14 9 3 14 18 26 9 9 12 13 17 25 16 5 8 4 24 10 24 23 4 29 21 9 18 28 27 ^ +52 1 11 3 16 4 21 25 3 4 18 12 12 29 26 13 26 23 26 7 23 10 9 27 26 21 25 21 18 +9 24 16 22 5 21 7 7 27 4 20 23 13 27 10 23 29 7 19 13 13 8 19 20 23 ^ +61 0 2 19 22 29 3 10 6 9 13 24 17 16 9 20 21 27 2 19 7 8 26 25 12 2 14 3 1 1 16 +12 20 28 24 12 5 24 25 20 1 12 25 9 2 6 20 15 14 29 18 21 28 1 17 6 17 27 1 2 +10 16 19 ^ +57 1 5 14 10 27 11 17 3 29 14 27 17 5 2 18 20 11 27 18 22 27 22 9 8 18 3 14 10 +5 2 24 18 23 21 26 8 22 8 1 6 27 27 15 29 20 2 29 22 8 16 20 4 12 9 6 12 16 24 ^ +64 0 7 9 20 29 11 9 4 1 15 25 16 29 10 22 7 2 8 5 18 14 23 24 4 6 26 3 11 6 12 +1 7 14 24 14 6 10 21 16 23 29 25 6 14 17 2 12 10 5 10 15 25 8 15 3 7 13 25 16 +14 1 29 22 26 10 ^ +63 1 27 9 1 8 8 28 6 13 5 13 3 15 5 23 8 23 2 5 5 4 17 13 14 7 17 12 27 3 18 5 +7 5 26 18 15 22 28 16 13 7 2 23 19 25 29 17 7 16 25 23 11 11 15 2 13 9 26 2 24 +26 7 28 11 ^ +56 1 2 29 7 22 23 5 28 19 1 27 29 1 24 11 18 20 3 13 11 7 3 15 17 24 1 18 13 6 +3 25 27 16 28 18 24 8 23 7 29 28 6 28 14 12 28 27 22 4 14 25 1 3 9 7 11 29 ^ +54 0 15 16 10 19 12 19 11 20 13 28 4 27 28 7 27 12 4 28 21 17 22 20 17 15 15 23 +22 13 12 21 22 21 11 12 14 12 18 27 8 7 4 9 14 16 15 8 11 21 20 10 10 21 23 22 ^ +63 0 2 11 23 1 11 1 5 3 23 16 15 27 14 5 16 3 22 2 3 24 3 19 29 4 4 10 8 20 14 +15 1 26 12 27 25 4 28 22 11 19 19 24 5 20 8 9 5 25 19 17 19 15 7 24 24 21 3 20 +16 8 3 17 19 ^ +59 0 18 29 9 23 9 10 29 4 12 24 15 5 8 22 17 29 12 3 8 29 15 21 21 4 7 20 7 10 +7 26 10 16 24 6 7 12 8 12 15 24 9 17 11 28 12 26 26 6 29 13 10 20 6 23 10 4 3 +26 10 ^ +62 0 14 20 20 25 14 13 15 24 14 11 4 23 27 24 20 9 16 17 24 13 12 6 1 14 26 25 +7 8 21 1 19 3 2 2 17 21 13 5 9 21 28 9 1 13 2 21 8 24 1 3 27 13 18 19 4 15 12 5 +2 16 27 29 ^ +62 0 6 2 1 23 17 14 28 19 23 6 22 16 4 19 6 16 28 3 3 1 15 13 22 6 15 11 6 4 24 +25 15 19 23 28 1 9 15 10 12 7 25 11 25 2 27 6 6 18 4 13 1 4 11 25 17 6 29 21 24 +27 21 18 ^ +54 1 17 26 24 13 4 22 24 29 2 11 8 17 4 23 11 26 1 25 28 15 19 10 3 9 29 27 7 +22 3 27 21 2 26 19 9 19 27 23 3 12 17 10 4 8 27 19 16 1 21 23 28 23 18 17 ^ +52 0 25 18 26 20 8 17 19 2 4 11 7 18 6 24 2 25 25 5 27 20 3 28 20 18 21 10 25 +10 1 28 28 29 16 20 19 26 16 21 6 23 15 28 26 28 7 15 18 11 5 17 20 13 ^ +68 0 1 10 14 8 4 16 26 17 8 10 22 22 18 1 20 24 7 1 9 7 19 5 22 1 4 26 11 10 28 +5 14 2 6 4 2 9 22 15 13 20 22 26 18 16 9 2 15 20 27 8 6 17 5 15 9 25 10 26 4 5 +27 5 19 21 5 6 11 19 ^ +54 1 19 8 2 24 26 22 19 18 17 23 14 21 14 22 13 20 5 29 6 5 26 6 21 29 3 5 12 +16 11 13 16 18 18 10 11 20 21 12 11 12 22 14 19 3 21 15 6 25 26 29 24 19 17 24 ^ +59 0 25 22 12 13 23 23 12 10 13 1 22 10 2 22 2 28 10 17 18 3 6 19 28 17 11 1 9 +14 4 29 29 23 25 13 19 18 2 7 21 6 8 29 5 11 22 14 14 9 28 13 25 24 28 8 14 9 3 +14 16 ^ +53 0 26 9 9 12 13 17 25 16 5 8 4 24 10 24 23 4 29 21 9 18 28 25 11 3 16 4 21 25 +3 4 18 12 12 29 26 13 26 23 26 7 23 10 9 27 26 21 25 21 18 9 24 16 17 ^ +59 0 5 21 7 7 27 4 20 23 13 27 10 23 29 7 19 13 13 8 19 20 18 2 19 22 29 3 10 6 +9 13 24 17 16 9 20 21 27 2 19 7 8 26 25 12 2 14 3 1 1 16 12 20 28 24 12 5 24 25 +19 ^ +60 0 1 12 25 9 2 6 20 15 14 29 18 21 28 1 17 6 17 27 1 2 10 16 19 5 14 10 27 11 +17 3 29 14 27 17 5 2 18 20 11 27 18 22 27 22 9 8 18 3 14 10 5 2 24 18 23 21 26 +8 22 13 ^ +62 0 1 6 27 27 15 29 20 2 29 22 8 16 20 4 12 9 6 12 16 16 7 9 20 29 11 9 4 1 15 +25 16 29 10 22 7 2 8 5 18 14 23 24 4 6 26 3 11 6 12 1 7 14 24 14 6 10 21 16 23 +29 25 24 ^ +67 0 14 17 2 12 10 5 10 15 25 8 15 3 7 13 25 16 14 1 29 22 26 15 27 9 1 8 8 28 +6 13 5 13 3 15 5 23 8 23 2 5 5 4 17 13 14 7 17 12 27 3 18 5 7 5 26 18 15 22 28 +16 13 7 2 23 19 25 14 ^ +58 1 17 7 16 25 23 11 11 15 2 13 9 26 2 24 26 7 28 11 2 29 7 22 23 5 28 19 1 27 +29 1 24 11 18 20 3 13 11 7 3 15 17 24 1 18 13 6 3 25 27 16 28 18 24 8 23 7 29 +11 ^ +55 0 6 28 14 12 28 27 22 4 14 25 1 3 9 7 11 14 15 16 10 19 12 19 11 20 13 28 4 +27 28 7 27 12 4 28 21 17 22 20 17 15 15 23 22 13 12 21 22 21 11 12 14 12 18 27 +10 ^ +65 0 7 4 9 14 16 15 8 11 21 20 10 10 21 23 20 2 11 23 1 11 1 5 3 23 16 15 27 14 +5 16 3 22 2 3 24 3 19 29 4 4 10 8 20 14 15 1 26 12 27 25 4 28 22 11 19 19 24 5 +20 8 9 5 25 19 20 ^ +59 1 19 15 7 24 24 21 3 20 16 8 3 17 28 18 29 9 23 9 10 29 4 12 24 15 5 8 22 17 +29 12 3 8 29 15 21 21 4 7 20 7 10 7 26 10 16 24 6 7 12 8 12 15 24 9 17 11 28 12 +23 ^ +61 0 26 6 29 13 10 20 6 23 10 4 3 26 26 14 20 20 25 14 13 15 24 14 11 4 23 27 +24 20 9 16 17 24 13 12 6 1 14 26 25 7 8 21 1 19 3 2 2 17 21 13 5 9 21 28 9 1 13 +2 21 8 29 ^ +68 0 1 3 27 13 18 19 4 15 12 5 2 16 27 16 6 2 1 23 17 14 28 19 23 6 22 16 4 19 +6 16 28 3 3 1 15 13 22 6 15 11 6 4 24 25 15 19 23 28 1 9 15 10 12 7 25 11 25 2 +27 6 6 18 4 13 1 4 11 26 ^ +54 1 17 6 29 21 24 27 21 17 17 26 24 13 4 22 24 29 2 11 8 17 4 23 11 26 1 25 28 +15 19 10 3 9 29 27 7 22 3 27 21 2 26 19 9 19 27 23 3 12 17 10 4 8 27 20 ^ +52 1 16 1 21 23 28 23 18 8 25 18 26 20 8 17 19 2 4 11 7 18 6 24 2 25 25 5 27 20 +3 28 20 18 21 10 25 10 1 28 28 29 16 20 19 26 16 21 6 23 15 28 26 12 ^ +67 0 7 15 18 11 5 17 20 26 1 10 14 8 4 16 26 17 8 10 22 22 18 1 20 24 7 1 9 7 +19 5 22 1 4 26 11 10 28 5 14 2 6 4 2 9 22 15 13 20 22 26 18 16 9 2 15 20 27 8 6 +17 5 15 9 25 10 26 19 ^ +58 0 5 27 5 19 21 5 6 11 29 19 8 2 24 26 22 19 18 17 23 14 21 14 22 13 20 5 29 +6 5 26 6 21 29 3 5 12 16 11 13 16 18 18 10 11 20 21 12 11 12 22 14 19 3 21 15 6 +25 27 ^ +57 0 29 24 19 17 18 25 22 12 13 23 23 12 10 13 1 22 10 2 22 2 28 10 17 18 3 6 +19 28 17 11 1 9 14 4 29 29 23 25 13 19 18 2 7 21 6 8 29 5 11 22 14 14 9 28 13 +25 25 ^ +52 0 15 29 9 28 20 2 30 26 21 17 8 28 17 22 29 24 8 11 18 29 15 6 7 27 27 17 24 +18 23 11 19 8 30 5 24 22 12 25 15 28 23 5 10 21 5 8 7 3 10 19 17 18 ^ +62 0 9 15 29 10 7 4 1 16 21 16 29 13 18 5 3 8 15 8 21 29 20 5 27 2 13 27 7 7 30 +2 18 26 10 2 5 29 21 15 25 26 24 8 12 20 3 9 10 30 7 12 24 5 13 1 6 10 25 13 9 +29 30 7 ^ +62 0 29 17 26 6 25 4 7 25 8 15 26 30 11 2 9 6 22 6 21 28 3 3 6 12 13 15 7 17 16 +26 3 19 3 5 2 29 16 16 22 26 13 12 9 19 16 27 25 16 7 15 22 22 5 6 13 4 12 11 +27 5 19 15 ^ +57 0 9 30 9 1 28 3 21 22 7 17 2 25 1 28 21 11 17 20 28 12 10 10 3 15 13 20 1 20 +11 1 30 22 23 15 26 12 21 7 27 9 27 29 5 26 16 11 23 28 18 1 13 23 30 6 3 11 25 +^ +61 1 16 10 13 13 19 15 18 7 22 10 29 3 25 30 8 22 13 4 4 27 22 18 21 23 17 15 +16 19 20 17 10 17 21 20 6 14 14 1 10 18 4 5 5 9 17 18 14 5 12 22 22 11 8 18 24 +21 3 7 21 9 22 ^ +58 1 3 4 23 14 17 25 27 10 5 16 30 23 2 4 25 3 16 28 4 6 6 17 12 18 2 23 7 29 +23 29 27 19 7 20 21 25 5 17 9 7 1 21 20 19 29 19 14 8 23 23 19 3 18 17 3 29 14 +17 ^ +62 1 23 28 5 22 8 10 1 1 11 27 18 3 2 22 28 14 24 12 1 3 30 29 11 22 19 7 16 1 +11 4 28 8 20 25 2 6 8 5 14 11 21 9 16 8 25 6 26 27 1 29 12 8 16 4 17 5 30 30 24 +12 19 21 ^ +57 1 25 11 13 12 27 16 14 3 24 20 24 23 22 9 14 19 26 8 13 6 13 25 19 5 1 19 1 +17 28 30 13 21 11 4 10 23 25 7 5 11 20 7 24 29 27 13 16 17 1 15 12 29 4 16 27 +12 21 ^ +65 0 2 2 24 17 13 22 20 22 4 20 16 2 17 3 11 29 1 5 10 14 23 3 14 9 2 7 18 20 +13 2 16 25 24 4 4 14 7 13 8 20 12 23 1 26 7 9 19 6 16 3 8 26 21 10 26 23 24 28 +16 12 14 25 22 16 15 ^ +53 0 21 24 27 30 15 10 15 2 18 13 26 28 23 16 23 10 2 11 26 26 4 29 18 4 24 24 +1 24 13 5 21 29 26 2 10 16 6 5 7 23 19 11 28 22 21 1 24 19 7 26 18 30 26 ^ +58 0 21 6 18 22 2 1 14 2 14 5 25 1 27 24 6 23 16 5 1 20 29 22 25 9 25 10 3 28 +28 25 19 18 16 24 14 15 5 28 12 28 26 29 2 15 15 9 5 18 19 22 12 15 4 6 15 24 +16 22 ^ +59 0 4 26 25 18 27 19 20 4 26 12 3 22 1 22 30 3 28 10 9 24 14 29 6 30 3 10 20 +14 6 3 19 21 21 28 16 18 11 30 11 20 30 1 9 8 11 5 19 10 24 4 22 4 2 26 5 15 20 +8 25 ^ +55 1 13 30 18 8 1 25 28 20 20 15 21 18 18 12 16 13 24 9 21 2 28 6 1 23 9 18 27 +27 4 9 13 10 8 14 16 15 12 11 14 21 14 10 11 25 17 17 30 21 13 27 26 26 22 14 +21 ^ +57 0 17 21 19 9 9 20 23 13 7 10 28 24 10 22 27 23 27 8 17 14 6 4 21 26 15 1 8 +29 27 6 28 15 3 27 25 25 14 19 13 29 8 24 2 8 2 4 12 19 11 10 6 26 14 22 24 30 +2 ^ +56 1 11 12 2 12 17 23 8 8 12 28 13 14 28 2 17 4 8 3 26 9 23 21 30 30 20 4 13 28 +29 9 3 17 7 19 30 28 1 2 20 9 12 24 15 30 20 27 3 23 11 6 29 25 23 26 17 23 ^ +61 1 10 22 15 23 6 25 5 4 30 2 19 23 15 27 14 26 1 1 7 19 12 7 6 20 18 14 4 15 +17 28 7 11 7 8 9 22 17 12 5 23 18 25 18 6 12 26 30 12 30 14 3 1 18 10 20 27 21 +8 6 24 30 ^ +54 0 20 11 24 7 2 4 18 15 14 30 16 19 2 27 15 4 19 25 29 29 7 14 18 9 11 9 27 +11 15 29 9 28 20 2 30 26 21 17 8 28 17 22 29 24 8 11 18 29 15 6 7 27 27 7 ^ +63 1 24 18 23 11 19 8 30 5 24 22 12 25 15 28 23 5 10 21 5 8 7 3 10 19 17 6 9 15 +29 10 7 4 1 16 21 16 29 13 18 5 3 8 15 8 21 29 20 5 27 2 13 27 7 7 30 2 18 26 +10 2 5 29 12 ^ +63 1 15 25 26 24 8 12 20 3 9 10 30 7 12 24 5 13 1 6 10 25 13 9 29 30 17 29 17 +26 6 25 4 7 25 8 15 26 30 11 2 9 6 22 6 21 28 3 3 6 12 13 15 7 17 16 26 3 19 3 +5 2 29 16 17 ^ +60 1 22 26 13 12 9 19 16 27 25 16 7 15 22 22 5 6 13 4 12 11 27 5 19 28 9 30 9 1 +28 3 21 22 7 17 2 25 1 28 21 11 17 20 28 12 10 10 3 15 13 20 1 20 11 1 30 22 23 +15 26 6 ^ +56 0 21 7 27 9 27 29 5 26 16 11 23 28 18 1 13 23 30 6 3 11 11 16 10 13 13 19 15 +18 7 22 10 29 3 25 30 8 22 13 4 4 27 22 18 21 23 17 15 16 19 20 17 10 17 21 20 +11 ^ +64 1 14 14 1 10 18 4 5 5 9 17 18 14 5 12 22 22 11 8 18 24 21 3 7 21 9 4 3 4 23 +14 17 25 27 10 5 16 30 23 2 4 25 3 16 28 4 6 6 17 12 18 2 23 7 29 23 29 27 19 7 +20 21 25 5 30 ^ +63 1 9 7 1 21 20 19 29 19 14 8 23 23 19 3 18 17 3 29 14 27 23 28 5 22 8 10 1 1 +11 27 18 3 2 22 28 14 24 12 1 3 30 29 11 22 19 7 16 1 11 4 28 8 20 25 2 6 8 5 +14 11 21 9 29 ^ +57 0 8 25 6 26 27 1 29 12 8 16 4 17 5 30 30 24 12 19 24 25 11 13 12 27 16 14 3 +24 20 24 23 22 9 14 19 26 8 13 6 13 25 19 5 1 19 1 17 28 30 13 21 11 4 10 23 25 +6 ^ +68 0 5 11 20 7 24 29 27 13 16 17 1 15 12 29 4 16 27 12 6 2 2 24 17 13 22 20 22 +4 20 16 2 17 3 11 29 1 5 10 14 23 3 14 9 2 7 18 20 13 2 16 25 24 4 4 14 7 13 8 +20 12 23 1 26 7 9 19 6 30 ^ +54 1 3 8 26 21 10 26 23 24 28 16 12 14 25 22 16 2 21 24 27 30 15 10 15 2 18 13 +26 28 23 16 23 10 2 11 26 26 4 29 18 4 24 24 1 24 13 5 21 29 26 2 10 16 6 27 ^ +56 0 7 23 19 11 28 22 21 1 24 19 7 26 18 30 25 21 6 18 22 2 1 14 2 14 5 25 1 27 +24 6 23 16 5 1 20 29 22 25 9 25 10 3 28 28 25 19 18 16 24 14 15 5 28 12 28 9 ^ +58 0 29 2 15 15 9 5 18 19 22 12 15 4 6 15 24 16 9 4 26 25 18 27 19 20 4 26 12 3 +22 1 22 30 3 28 10 9 24 14 29 6 30 3 10 20 14 6 3 19 21 21 28 16 18 11 30 11 20 +29 ^ +65 0 1 9 8 11 5 19 10 24 4 22 4 2 26 5 15 20 8 3 13 30 18 8 1 25 28 20 20 15 21 +18 18 12 16 13 24 9 21 2 28 6 1 23 9 18 27 27 4 9 13 10 8 14 16 15 12 11 14 21 +14 10 11 25 17 17 20 ^ +55 0 21 13 27 26 26 22 14 13 17 21 19 9 9 20 23 13 7 10 28 24 10 22 27 23 27 8 +17 14 6 4 21 26 15 1 8 29 27 6 28 15 3 27 25 25 14 19 13 29 8 24 2 8 2 4 30 ^ +57 1 19 11 10 6 26 14 22 24 30 10 11 12 2 12 17 23 8 8 12 28 13 14 28 2 17 4 8 +3 26 9 23 21 30 30 20 4 13 28 29 9 3 17 7 19 30 28 1 2 20 9 12 24 15 30 20 27 +30 ^ +59 0 23 11 6 29 25 23 26 17 20 10 22 15 23 6 25 5 4 30 2 19 23 15 27 14 26 1 1 +7 19 12 7 6 20 18 14 4 15 17 28 7 11 7 8 9 22 17 12 5 23 18 25 18 6 12 26 30 12 +30 18 ^ +56 0 3 1 18 10 20 27 21 8 6 24 26 20 11 24 7 2 4 18 15 14 30 16 19 2 27 15 4 19 +25 29 29 7 14 18 9 11 9 27 11 15 29 9 28 20 2 30 26 21 17 8 28 17 22 29 24 7 ^ +62 0 11 18 29 15 6 7 27 27 17 24 18 23 11 19 8 30 5 24 22 12 25 15 28 23 5 10 +21 5 8 7 3 10 19 17 6 9 15 29 10 7 4 1 16 21 16 29 13 18 5 3 8 15 8 21 29 20 5 +27 2 13 27 7 ^ +62 1 7 30 2 18 26 10 2 5 29 21 15 25 26 24 8 12 20 3 9 10 30 7 12 24 5 13 1 6 +10 25 13 9 29 30 17 29 17 26 6 25 4 7 25 8 15 26 30 11 2 9 6 22 6 21 28 3 3 6 +12 13 15 26 ^ +62 0 17 16 26 3 19 3 5 2 29 16 16 22 26 13 12 9 19 16 27 25 16 7 15 22 22 5 6 +13 4 12 11 27 5 19 28 9 30 9 1 28 3 21 22 7 17 2 25 1 28 21 11 17 20 28 12 10 +10 3 15 13 20 19 ^ +56 1 20 11 1 30 22 23 15 26 12 21 7 27 9 27 29 5 26 16 11 23 28 18 1 13 23 30 6 +3 11 11 16 10 13 13 19 15 18 7 22 10 29 3 25 30 8 22 13 4 4 27 22 18 21 23 17 +22 ^ +66 1 16 19 20 17 10 17 21 20 6 14 14 1 10 18 4 5 5 9 17 18 14 5 12 22 22 11 8 +18 24 21 3 7 21 9 4 3 4 23 14 17 25 27 10 5 16 30 23 2 4 25 3 16 28 4 6 6 17 12 +18 2 23 7 29 23 29 24 ^ +62 0 19 7 20 21 25 5 17 9 7 1 21 20 19 29 19 14 8 23 23 19 3 18 17 3 29 14 27 +23 28 5 22 8 10 1 1 11 27 18 3 2 22 28 14 24 12 1 3 30 29 11 22 19 7 16 1 11 4 +28 8 20 25 7 ^ +59 0 6 8 5 14 11 21 9 16 8 25 6 26 27 1 29 12 8 16 4 17 5 30 30 24 12 19 24 25 +11 13 12 27 16 14 3 24 20 24 23 22 9 14 19 26 8 13 6 13 25 19 5 1 19 1 17 28 30 +13 26 ^ +70 0 11 4 10 23 25 7 5 11 20 7 24 29 27 13 16 17 1 15 12 29 4 16 27 12 6 2 2 24 +17 13 22 20 22 4 20 16 2 17 3 11 29 1 5 10 14 23 3 14 9 2 7 18 20 13 2 16 25 24 +4 4 14 7 13 8 20 12 23 1 26 7 ^ +54 1 9 19 6 16 3 8 26 21 10 26 23 24 28 16 12 14 25 22 16 2 21 24 27 30 15 10 +15 2 18 13 26 28 23 16 23 10 2 11 26 26 4 29 18 4 24 24 1 24 13 5 21 29 26 27 ^ +58 1 10 16 6 5 7 23 19 11 28 22 21 1 24 19 7 26 18 30 25 21 6 18 22 2 1 14 2 14 +5 25 1 27 24 6 23 16 5 1 20 29 22 25 9 25 10 3 28 28 25 19 18 16 24 14 15 5 28 +28 ^ +58 1 28 26 29 2 15 15 9 5 18 19 22 12 15 4 6 15 24 16 9 4 26 25 18 27 19 20 4 +26 12 3 22 1 22 30 3 28 10 9 24 14 29 6 30 3 10 20 14 6 3 19 21 21 28 16 18 11 +30 22 ^ +65 1 20 30 1 9 8 11 5 19 10 24 4 22 4 2 26 5 15 20 8 3 13 30 18 8 1 25 28 20 20 +15 21 18 18 12 16 13 24 9 21 2 28 6 1 23 9 18 27 27 4 9 13 10 8 14 16 15 12 11 +14 21 14 10 11 25 20 ^ +53 0 17 30 21 13 27 26 26 22 14 13 17 21 19 9 9 20 23 13 7 10 28 24 10 22 27 23 +27 8 17 14 6 4 21 26 15 1 8 29 27 6 28 15 3 27 25 25 14 19 13 29 8 24 15 ^ +61 0 8 2 4 12 19 11 10 6 26 14 22 24 30 10 11 12 2 12 17 23 8 8 12 28 13 14 28 +2 17 4 8 3 26 9 23 21 30 30 20 4 13 28 29 9 3 17 7 19 30 28 1 2 20 9 12 24 15 +30 20 27 20 ^ +60 0 23 11 6 29 25 23 26 17 20 10 22 15 23 6 25 5 4 30 2 19 23 15 27 14 26 1 1 +7 19 12 7 6 20 18 14 4 15 17 28 7 11 7 8 9 22 17 12 5 23 18 25 18 6 12 26 30 12 +30 14 20 ^ +56 0 3 1 18 10 20 27 21 8 6 24 26 20 11 24 7 2 4 18 15 14 30 16 19 2 27 15 4 19 +25 29 29 7 14 18 9 11 9 27 11 15 29 9 28 20 2 30 26 21 17 8 28 17 22 29 24 23 ^ +62 0 11 18 29 15 6 7 27 27 17 24 18 23 11 19 8 30 5 24 22 12 25 15 28 23 5 10 +21 5 8 7 3 10 19 17 6 9 15 29 10 7 4 1 16 21 16 29 13 18 5 3 8 15 8 21 29 20 5 +27 2 13 27 23 ^ +64 1 7 30 2 18 26 10 2 5 29 21 15 25 26 24 8 12 20 3 9 10 30 7 12 24 5 13 1 6 +10 25 13 9 29 30 17 29 17 26 6 25 4 7 25 8 15 26 30 11 2 9 6 22 6 21 28 3 3 6 +12 13 15 7 17 18 ^ +65 0 26 3 19 3 5 2 29 16 16 22 26 13 12 9 19 16 27 25 16 7 15 22 22 5 6 13 4 12 +11 27 5 19 28 9 30 9 1 28 3 21 22 7 17 2 25 1 28 21 11 17 20 28 12 10 10 3 15 +13 20 1 20 11 1 30 5 ^ +57 0 23 15 26 12 21 7 27 9 27 29 5 26 16 11 23 28 18 1 13 23 30 6 3 11 11 16 10 +13 13 19 15 18 7 22 10 29 3 25 30 8 22 13 4 4 27 22 18 21 23 17 15 16 19 20 17 +10 25 ^ +66 1 21 20 6 14 14 1 10 18 4 5 5 9 17 18 14 5 12 22 22 11 8 18 24 21 3 7 21 9 4 +3 4 23 14 17 25 27 10 5 16 30 23 2 4 25 3 16 28 4 6 6 17 12 18 2 23 7 29 23 29 +27 19 7 20 21 25 20 ^ +65 1 17 9 7 1 21 20 19 29 19 14 8 23 23 19 3 18 17 3 29 14 27 23 28 5 22 8 10 1 +1 11 27 18 3 2 22 28 14 24 12 1 3 30 29 11 22 19 7 16 1 11 4 28 8 20 25 2 6 8 5 +14 11 21 9 16 28 ^ +59 1 25 6 26 27 1 29 12 8 16 4 17 5 30 30 24 12 19 24 25 11 13 12 27 16 14 3 24 +20 24 23 22 9 14 19 26 8 13 6 13 25 19 5 1 19 1 17 28 30 13 21 11 4 10 23 25 7 +5 11 23 ^ +70 0 20 7 24 29 27 13 16 17 1 15 12 29 4 16 27 12 6 2 2 24 17 13 22 20 22 4 20 +16 2 17 3 11 29 1 5 10 14 23 3 14 9 2 7 18 20 13 2 16 25 24 4 4 14 7 13 8 20 12 +23 1 26 7 9 19 6 16 3 8 26 25 ^ +56 0 10 26 23 24 28 16 12 14 25 22 16 2 21 24 27 30 15 10 15 2 18 13 26 28 23 +16 23 10 2 11 26 26 4 29 18 4 24 24 1 24 13 5 21 29 26 2 10 16 6 5 7 23 19 11 +28 24 ^ +59 1 21 1 24 19 7 26 18 30 25 21 6 18 22 2 1 14 2 14 5 25 1 27 24 6 23 16 5 1 +20 29 22 25 9 25 10 3 28 28 25 19 18 16 24 14 15 5 28 12 28 26 29 2 15 15 9 5 +18 19 13 ^ +63 1 12 15 4 6 15 24 16 9 4 26 25 18 27 19 20 4 26 12 3 22 1 22 30 3 28 10 9 24 +14 29 6 30 3 10 20 14 6 3 19 21 21 28 16 18 11 30 11 20 30 1 9 8 11 5 19 10 24 +4 22 4 2 26 20 ^ +59 1 15 20 8 3 13 30 18 8 1 25 28 20 20 15 21 18 18 12 16 13 24 9 21 2 28 6 1 +23 9 18 27 27 4 9 13 10 8 14 16 15 12 11 14 21 14 10 11 25 17 17 30 21 13 27 26 +26 22 14 23 ^ +61 0 16 21 30 25 8 9 18 30 17 4 6 31 26 16 25 18 23 9 20 8 7 25 26 11 27 17 28 +2 23 2 12 24 2 8 6 3 12 20 16 4 10 17 30 12 11 5 31 19 19 19 30 13 18 2 3 8 2 +17 8 24 28 ^ +69 0 22 2 7 26 1 13 26 6 6 6 18 24 7 6 7 30 19 12 22 24 25 3 11 17 3 10 12 11 +11 25 7 13 31 4 7 27 13 10 30 16 30 16 29 4 27 5 6 27 8 12 29 9 1 10 9 26 4 19 +1 3 3 4 16 13 17 6 16 14 28 ^ +62 0 3 20 3 2 1 30 14 14 21 29 13 11 10 29 20 19 26 27 19 6 17 26 26 7 9 13 16 +9 31 2 20 28 10 10 4 28 3 24 21 6 29 16 1 22 31 1 24 9 16 22 28 11 7 7 3 17 13 +22 4 17 9 27 ^ +60 0 21 23 17 24 16 24 11 26 5 31 30 2 24 14 9 23 28 18 4 13 23 4 3 9 9 14 12 +13 8 20 12 18 6 21 12 25 3 27 8 21 13 5 26 21 18 19 23 16 12 14 20 17 16 7 16 +19 22 9 15 25 ^ +64 0 31 7 18 29 5 7 2 5 16 18 10 7 11 21 21 9 8 18 25 19 3 6 19 29 10 3 5 23 15 +16 27 26 12 2 19 23 1 22 3 19 28 5 2 9 4 21 11 18 1 23 6 30 23 30 26 20 11 22 +19 27 2 16 10 31 ^ +60 0 4 24 17 20 25 20 15 8 23 23 20 30 18 16 3 30 15 26 23 28 7 21 8 7 31 31 14 +26 18 3 1 26 28 15 25 11 31 3 25 9 21 20 2 6 14 4 9 5 28 8 17 22 1 4 8 7 10 14 +19 19 ^ +62 0 14 8 27 9 24 26 4 30 11 8 19 5 21 7 2 27 20 16 20 20 22 14 13 16 26 14 10 +3 25 22 25 23 21 10 15 15 29 8 13 4 2 13 22 20 7 4 20 31 16 2 2 28 13 19 14 12 +23 27 6 2 14 24 ^ +62 0 22 6 25 30 29 31 13 14 16 31 12 16 30 5 14 31 11 4 1 1 25 21 13 26 22 21 5 +22 14 29 1 21 3 14 30 4 2 29 12 15 23 3 15 5 1 6 23 22 13 1 14 27 25 5 15 6 13 +3 22 11 23 21 ^ +56 1 24 6 5 20 4 14 3 29 8 29 19 7 29 23 25 28 19 11 15 27 21 14 1 19 20 26 12 +7 12 1 18 13 29 28 23 29 14 23 7 1 9 29 24 5 30 18 5 25 25 31 25 13 7 24 25 11 ^ +54 0 1 12 19 9 7 6 28 20 14 28 21 19 31 20 20 6 24 18 27 24 4 18 21 1 31 15 1 +15 2 27 4 26 25 4 23 19 2 31 22 30 21 22 5 27 12 30 28 28 27 15 18 14 25 23 ^ +59 1 17 7 28 11 28 29 30 1 17 12 10 2 18 20 21 2 11 12 5 4 12 25 14 5 5 24 22 +18 31 15 22 29 11 3 21 31 21 27 3 28 7 10 25 2 15 30 9 30 7 22 15 9 3 20 24 24 +28 14 25 ^ +58 0 9 27 14 22 27 31 10 8 14 7 15 7 20 5 26 1 29 7 17 17 8 3 13 27 18 8 31 27 +28 22 22 17 19 18 18 11 19 13 25 10 19 6 28 4 31 23 10 18 26 31 5 10 13 12 8 15 +19 24 ^ +56 1 11 14 15 24 15 12 9 22 16 16 24 13 2 26 24 29 26 15 13 21 24 20 10 10 22 +23 13 6 12 28 25 12 2 21 26 28 26 8 16 15 4 5 19 24 12 31 8 30 31 9 28 12 3 26 +29 8 ^ +65 0 27 10 20 13 30 8 25 1 8 1 5 11 20 9 12 4 29 15 21 25 27 7 14 11 1 11 16 23 +8 8 11 1 13 15 28 1 16 5 8 3 24 10 23 24 17 5 13 28 30 5 3 16 6 20 28 31 6 22 +10 11 29 25 17 27 23 ^ +60 0 26 3 23 14 4 30 27 23 24 21 17 12 21 17 23 4 22 7 5 27 1 20 23 12 26 10 24 +31 29 4 11 15 11 6 9 17 18 15 5 17 21 28 6 9 6 8 10 21 16 11 2 23 18 27 29 18 9 +11 24 24 ^ +58 1 11 15 29 29 3 31 18 12 17 31 19 8 4 25 29 17 29 9 25 6 1 2 18 17 15 19 15 +1 26 17 20 27 30 30 6 10 18 5 9 10 26 9 17 2 30 10 28 17 1 27 29 2 19 16 8 28 +16 28 ^ +61 1 30 25 8 9 18 30 17 4 6 31 26 16 25 18 23 9 20 8 7 25 26 11 27 17 28 2 23 2 +12 24 2 8 6 3 12 20 16 4 10 17 30 12 11 5 31 19 19 19 30 13 18 2 3 8 2 17 8 24 +30 22 29 ^ +70 0 7 26 1 13 26 6 6 6 18 24 7 6 7 30 19 12 22 24 25 3 11 17 3 10 12 11 11 25 +7 13 31 4 7 27 13 10 30 16 30 16 29 4 27 5 6 27 8 12 29 9 1 10 9 26 4 19 1 3 3 +4 16 13 17 6 16 14 24 3 20 21 ^ +62 1 2 1 30 14 14 21 29 13 11 10 29 20 19 26 27 19 6 17 26 26 7 9 13 16 9 31 2 +20 28 10 10 4 28 3 24 21 6 29 16 1 22 31 1 24 9 16 22 28 11 7 7 3 17 13 22 4 17 +9 4 21 23 21 ^ +62 1 24 16 24 11 26 5 31 30 2 24 14 9 23 28 18 4 13 23 4 3 9 9 14 12 13 8 20 12 +18 6 21 12 25 3 27 8 21 13 5 26 21 18 19 23 16 12 14 20 17 16 7 16 19 22 9 15 +10 31 7 18 29 7 ^ +66 1 7 2 5 16 18 10 7 11 21 21 9 8 18 25 19 3 6 19 29 10 3 5 23 15 16 27 26 12 +2 19 23 1 22 3 19 28 5 2 9 4 21 11 18 1 23 6 30 23 30 26 20 11 22 19 27 2 16 10 +6 4 24 17 20 25 20 21 ^ +62 1 8 23 23 20 30 18 16 3 30 15 26 23 28 7 21 8 7 31 31 14 26 18 3 1 26 28 15 +25 11 31 3 25 9 21 20 2 6 14 4 9 5 28 8 17 22 1 4 8 7 10 14 19 10 14 8 27 9 24 +26 4 30 8 ^ +62 1 8 19 5 21 7 2 27 20 16 20 20 22 14 13 16 26 14 10 3 25 22 25 23 21 10 15 +15 29 8 13 4 2 13 22 20 7 4 20 31 16 2 2 28 13 19 14 12 23 27 6 2 14 2 22 6 25 +30 29 31 13 14 21 ^ +65 0 31 12 16 30 5 14 31 11 4 1 1 25 21 13 26 22 21 5 22 14 29 1 21 3 14 30 4 2 +29 12 15 23 3 15 5 1 6 23 22 13 1 14 27 25 5 15 6 13 3 22 11 23 31 24 6 5 20 4 +14 3 29 8 29 19 31 ^ +55 1 29 23 25 28 19 11 15 27 21 14 1 19 20 26 12 7 12 1 18 13 29 28 23 29 14 23 +7 1 9 29 24 5 30 18 5 25 25 31 25 13 7 24 25 24 1 12 19 9 7 6 28 20 14 28 27 ^ +53 1 19 31 20 20 6 24 18 27 24 4 18 21 1 31 15 1 15 2 27 4 26 25 4 23 19 2 31 +22 30 21 22 5 27 12 30 28 28 27 15 18 14 25 15 17 7 28 11 28 29 30 1 17 21 ^ +61 0 10 2 18 20 21 2 11 12 5 4 12 25 14 5 5 24 22 18 31 15 22 29 11 3 21 31 21 +27 3 28 7 10 25 2 15 30 9 30 7 22 15 9 3 20 24 24 28 14 18 9 27 14 22 27 31 10 +8 14 7 15 19 ^ +59 1 20 5 26 1 29 7 17 17 8 3 13 27 18 8 31 27 28 22 22 17 19 18 18 11 19 13 25 +10 19 6 28 4 31 23 10 18 26 31 5 10 13 12 8 15 19 17 11 14 15 24 15 12 9 22 16 +16 24 13 23 ^ +57 0 26 24 29 26 15 13 21 24 20 10 10 22 23 13 6 12 28 25 12 2 21 26 28 26 8 16 +15 4 5 19 24 12 31 8 30 31 9 28 12 3 26 29 22 27 10 20 13 30 8 25 1 8 1 5 11 20 +16 ^ +61 1 12 4 29 15 21 25 27 7 14 11 1 11 16 23 8 8 11 1 13 15 28 1 16 5 8 3 24 10 +23 24 17 5 13 28 30 5 3 16 6 20 28 31 6 22 10 11 29 25 17 27 22 26 3 23 14 4 30 +27 23 24 31 ^ +61 1 17 12 21 17 23 4 22 7 5 27 1 20 23 12 26 10 24 31 29 4 11 15 11 6 9 17 18 +15 5 17 21 28 6 9 6 8 10 21 16 11 2 23 18 27 29 18 9 11 24 27 11 15 29 29 3 31 +18 12 17 31 12 ^ +60 1 8 4 25 29 17 29 9 25 6 1 2 18 17 15 19 15 1 26 17 20 27 30 30 6 10 18 5 9 +10 26 9 17 2 30 10 28 17 1 27 29 2 19 16 8 28 16 21 30 25 8 9 18 30 17 4 6 31 +26 16 18 ^ +67 1 18 23 9 20 8 7 25 26 11 27 17 28 2 23 2 12 24 2 8 6 3 12 20 16 4 10 17 30 +12 11 5 31 19 19 19 30 13 18 2 3 8 2 17 8 24 30 22 2 7 26 1 13 26 6 6 6 18 24 7 +6 7 30 19 12 22 24 28 ^ +69 1 3 11 17 3 10 12 11 11 25 7 13 31 4 7 27 13 10 30 16 30 16 29 4 27 5 6 27 8 +12 29 9 1 10 9 26 4 19 1 3 3 4 16 13 17 6 16 14 24 3 20 3 2 1 30 14 14 21 29 13 +11 10 29 20 19 26 27 19 6 28 ^ +62 1 26 26 7 9 13 16 9 31 2 20 28 10 10 4 28 3 24 21 6 29 16 1 22 31 1 24 9 16 +22 28 11 7 7 3 17 13 22 4 17 9 4 21 23 17 24 16 24 11 26 5 31 30 2 24 14 9 23 +28 18 4 13 26 ^ +70 1 4 3 9 9 14 12 13 8 20 12 18 6 21 12 25 3 27 8 21 13 5 26 21 18 19 23 16 12 +14 20 17 16 7 16 19 22 9 15 10 31 7 18 29 5 7 2 5 16 18 10 7 11 21 21 9 8 18 25 +19 3 6 19 29 10 3 5 23 15 16 17 ^ +60 1 26 12 2 19 23 1 22 3 19 28 5 2 9 4 21 11 18 1 23 6 30 23 30 26 20 11 22 19 +27 2 16 10 6 4 24 17 20 25 20 15 8 23 23 20 30 18 16 3 30 15 26 23 28 7 21 8 7 +31 31 7 ^ +66 0 26 18 3 1 26 28 15 25 11 31 3 25 9 21 20 2 6 14 4 9 5 28 8 17 22 1 4 8 7 +10 14 19 10 14 8 27 9 24 26 4 30 11 8 19 5 21 7 2 27 20 16 20 20 22 14 13 16 26 +14 10 3 25 22 25 23 17 ^ +64 1 10 15 15 29 8 13 4 2 13 22 20 7 4 20 31 16 2 2 28 13 19 14 12 23 27 6 2 14 +2 22 6 25 30 29 31 13 14 16 31 12 16 30 5 14 31 11 4 1 1 25 21 13 26 22 21 5 22 +14 29 1 21 3 14 27 ^ +64 0 4 2 29 12 15 23 3 15 5 1 6 23 22 13 1 14 27 25 5 15 6 13 3 22 11 23 31 24 +6 5 20 4 14 3 29 8 29 19 7 29 23 25 28 19 11 15 27 21 14 1 19 20 26 12 7 12 1 +18 13 29 28 23 29 13 ^ +58 0 23 7 1 9 29 24 5 30 18 5 25 25 31 25 13 7 24 25 24 1 12 19 9 7 6 28 20 14 +28 21 19 31 20 20 6 24 18 27 24 4 18 21 1 31 15 1 15 2 27 4 26 25 4 23 19 2 31 +28 ^ +57 0 30 21 22 5 27 12 30 28 28 27 15 18 14 25 15 17 7 28 11 28 29 30 1 17 12 10 +2 18 20 21 2 11 12 5 4 12 25 14 5 5 24 22 18 31 15 22 29 11 3 21 31 21 27 3 28 +7 26 ^ +59 0 25 2 15 30 9 30 7 22 15 9 3 20 24 24 28 14 18 9 27 14 22 27 31 10 8 14 7 +15 7 20 5 26 1 29 7 17 17 8 3 13 27 18 8 31 27 28 22 22 17 19 18 18 11 19 13 25 +10 19 19 ^ +59 0 28 4 31 23 10 18 26 31 5 10 13 12 8 15 19 17 11 14 15 24 15 12 9 22 16 16 +24 13 2 26 24 29 26 15 13 21 24 20 10 10 22 23 13 6 12 28 25 12 2 21 26 28 26 8 +16 15 4 5 31 ^ +66 1 24 12 31 8 30 31 9 28 12 3 26 29 22 27 10 20 13 30 8 25 1 8 1 5 11 20 9 12 +4 29 15 21 25 27 7 14 11 1 11 16 23 8 8 11 1 13 15 28 1 16 5 8 3 24 10 23 24 17 +5 13 28 30 5 3 16 21 ^ +59 0 20 28 31 6 22 10 11 29 25 17 27 22 26 3 23 14 4 30 27 23 24 21 17 12 21 17 +23 4 22 7 5 27 1 20 23 12 26 10 24 31 29 4 11 15 11 6 9 17 18 15 5 17 21 28 6 9 +6 8 26 ^ +59 0 21 16 11 2 23 18 27 29 18 9 11 24 27 11 15 29 29 3 31 18 12 17 31 19 8 4 +25 29 17 29 9 25 6 1 2 18 17 15 19 15 1 26 17 20 27 30 30 6 10 18 5 9 10 26 9 +17 2 30 24 ^ +61 0 28 17 1 27 29 2 19 16 8 28 16 21 30 25 8 9 18 30 17 4 6 31 26 16 25 18 23 +9 20 8 7 25 26 11 27 17 28 2 23 2 12 24 2 8 6 3 12 20 16 4 10 17 30 12 11 5 31 +19 19 19 25 ^ +74 0 13 18 2 3 8 2 17 8 24 30 22 2 7 26 1 13 26 6 6 6 18 24 7 6 7 30 19 12 22 +24 25 3 11 17 3 10 12 11 11 25 7 13 31 4 7 27 13 10 30 16 30 16 29 4 27 5 6 27 +8 12 29 9 1 10 9 26 4 19 1 3 3 4 16 16 ^ +64 1 17 6 16 14 24 3 20 3 2 1 30 14 14 21 29 13 11 10 29 20 19 26 27 19 6 17 26 +26 7 9 13 16 9 31 2 20 28 10 10 4 28 3 24 21 6 29 16 1 22 31 1 24 9 16 22 28 11 +7 7 3 17 13 22 27 ^ +65 0 17 9 4 21 23 17 24 16 24 11 26 5 31 30 2 24 14 9 23 28 18 4 13 23 4 3 9 9 +14 12 13 8 20 12 18 6 21 12 25 3 27 8 21 13 5 26 21 18 19 23 16 12 14 20 17 16 +7 16 19 22 9 15 10 31 1 ^ +68 1 18 29 5 7 2 5 16 18 10 7 11 21 21 9 8 18 25 19 3 6 19 29 10 3 5 23 15 16 +27 26 12 2 19 23 1 22 3 19 28 5 2 9 4 21 11 18 1 23 6 30 23 30 26 20 11 22 19 +27 2 16 10 6 4 24 17 20 25 20 ^ +63 0 15 8 23 23 20 30 18 16 3 30 15 26 23 28 7 21 8 7 31 31 14 26 18 3 1 26 28 +15 25 11 31 3 25 9 21 20 2 6 14 4 9 5 28 8 17 22 1 4 8 7 10 14 19 10 14 8 27 9 +24 26 4 30 24 ^ +64 1 8 19 5 21 7 2 27 20 16 20 20 22 14 13 16 26 14 10 3 25 22 25 23 21 10 15 +15 29 8 13 4 2 13 22 20 7 4 20 31 16 2 2 28 13 19 14 12 23 27 6 2 14 2 22 6 25 +30 29 31 13 14 16 31 5 ^ +67 0 16 30 5 14 31 11 4 1 1 25 21 13 26 22 21 5 22 14 29 1 21 3 14 30 4 2 29 12 +15 23 3 15 5 1 6 23 22 13 1 14 27 25 5 15 6 13 3 22 11 23 31 24 6 5 20 4 14 3 +29 8 29 19 7 29 23 25 21 ^ +58 0 19 11 15 27 21 14 1 19 20 26 12 7 12 1 18 13 29 28 23 29 14 23 7 1 9 29 24 +5 30 18 5 25 25 31 25 13 7 24 25 24 1 12 19 9 7 6 28 20 14 28 21 19 31 20 20 6 +24 22 ^ +60 0 27 24 4 18 21 1 31 15 1 15 2 27 4 26 25 4 23 19 2 31 22 30 21 22 5 27 12 +30 28 28 27 15 18 14 25 15 17 7 28 11 28 29 30 1 17 12 10 2 18 20 21 2 11 12 5 +4 12 25 14 22 ^ +60 1 5 24 22 18 31 15 22 29 11 3 21 31 21 27 3 28 7 10 25 2 15 30 9 30 7 22 15 +9 3 20 24 24 28 14 18 9 27 14 22 27 31 10 8 14 7 15 7 20 5 26 1 29 7 17 17 8 3 +13 27 31 ^ +58 0 8 31 27 28 22 22 17 19 18 18 11 19 13 25 10 19 6 28 4 31 23 10 18 26 31 5 +10 13 12 8 15 19 17 11 14 15 24 15 12 9 22 16 16 24 13 2 26 24 29 26 15 13 21 +24 20 10 10 25 ^ +65 0 23 13 6 12 28 25 12 2 21 26 28 26 8 16 15 4 5 19 24 12 31 8 30 31 9 28 12 +3 26 29 22 27 10 20 13 30 8 25 1 8 1 5 11 20 9 12 4 29 15 21 25 27 7 14 11 1 11 +16 23 8 8 11 1 13 21 ^ +60 1 28 1 16 5 8 3 24 10 23 24 17 5 13 28 30 5 3 16 6 20 28 31 6 22 10 11 29 25 +17 27 22 26 3 23 14 4 30 27 23 24 21 17 12 21 17 23 4 22 7 5 27 1 20 23 12 26 +10 24 31 11 ^ +64 1 4 11 15 11 6 9 17 18 15 5 17 21 28 6 9 6 8 10 21 16 11 2 23 18 27 29 18 9 +11 24 27 11 15 29 29 3 31 18 12 17 31 19 8 4 25 29 17 29 9 25 6 1 2 18 17 15 19 +15 1 26 17 20 27 25 ^ +64 0 30 6 10 18 5 9 10 26 9 17 2 30 10 28 17 1 27 29 2 19 16 8 28 16 21 30 25 8 +9 18 30 17 4 6 31 26 16 25 18 23 9 20 8 7 25 26 11 27 17 28 2 23 2 12 24 2 8 6 +3 12 20 16 4 31 ^ +60 0 28 5 24 16 10 27 28 19 29 19 22 10 23 17 25 7 26 5 5 27 1 20 24 13 27 16 +24 32 31 5 12 21 13 6 11 21 20 15 3 14 18 32 2 9 6 10 13 23 16 17 3 20 19 27 29 +21 5 11 28 14 ^ +SHS Type 2 Strings +60 1 16 13 19 5 16 14 27 2 22 7 5 28 15 18 25 17 13 12 29 24 21 29 25 16 5 17 +22 24 8 8 18 3 13 10 28 3 23 28 12 8 3 25 5 25 24 7 14 30 27 32 30 23 8 15 27 +28 13 8 12 21 ^ +86 1 33 5 40 26 3 19 12 36 43 5 35 37 5 14 11 45 35 16 10 8 32 4 15 35 26 2 39 +22 37 22 30 29 28 36 45 14 36 4 29 37 30 34 36 20 9 42 29 9 11 11 18 42 13 6 20 +42 20 30 22 35 34 6 14 41 19 30 17 35 33 26 41 15 5 44 39 8 20 3 44 32 15 18 10 +15 10 36 ^ +112 0 10 44 24 53 35 22 40 20 15 51 22 18 22 42 6 54 49 38 21 7 13 30 16 7 52 +16 22 13 38 7 11 44 33 9 25 13 37 42 14 45 53 30 38 5 25 5 35 38 22 28 10 29 52 +31 39 35 23 5 17 14 31 46 5 41 54 43 33 13 23 46 45 3 46 3 55 15 6 53 28 52 22 +27 45 32 53 51 15 37 15 49 36 35 35 15 3 13 22 25 3 4 10 24 12 7 44 25 18 21 21 +20 55 24 ^ +123 1 43 9 1 52 4 21 49 61 18 50 23 13 46 62 23 45 62 9 56 18 23 31 8 30 27 36 +13 38 4 58 53 47 24 18 41 58 19 12 18 52 42 29 44 45 26 63 34 32 41 64 15 26 55 +19 2 49 6 30 53 13 54 12 53 37 12 37 29 60 53 21 47 42 45 52 40 10 28 47 43 17 +16 17 61 36 12 34 60 37 13 52 58 37 39 29 34 11 45 8 36 1 50 50 5 51 13 15 32 +51 33 61 16 31 50 58 63 16 5 30 17 24 10 26 52 ^ +144 1 64 62 63 30 15 1 35 28 16 40 20 14 50 33 19 38 30 27 55 10 16 46 47 7 55 +12 53 26 56 33 29 55 25 17 48 43 21 43 18 24 63 27 68 46 38 33 35 10 18 11 27 5 +9 58 35 70 36 36 39 47 2 10 66 47 5 18 21 44 71 51 57 3 22 7 56 55 28 25 14 40 +16 24 48 37 66 50 24 45 18 39 53 29 64 60 26 50 6 47 61 46 44 60 17 4 58 45 26 +20 26 32 8 7 68 37 3 24 44 47 64 54 71 57 12 68 27 58 29 54 43 42 60 13 14 56 +49 1 32 9 61 43 36 33 20 59 ^ +166 0 7 38 57 33 61 73 7 64 1 49 35 76 14 27 21 45 68 38 58 73 13 72 47 73 33 8 +66 23 38 4 56 77 47 10 71 13 20 31 41 6 51 3 18 17 61 47 14 48 76 46 28 34 43 1 +56 4 25 7 65 41 1 34 37 23 59 59 27 26 13 15 14 75 60 14 1 28 59 26 65 61 16 23 +17 28 6 19 2 35 49 30 29 48 2 63 73 59 1 3 76 41 11 19 18 43 54 63 67 51 4 9 78 +60 8 72 31 35 77 54 58 20 36 58 51 76 40 20 37 49 3 75 1 29 20 57 64 22 25 6 25 +59 32 43 58 40 51 77 1 2 36 10 12 28 39 11 46 2 41 27 27 53 76 13 66 69 76 28 ^ +186 1 5 73 38 30 30 48 21 75 80 40 21 8 53 9 26 30 34 81 71 71 51 23 75 33 41 +23 32 5 8 66 40 72 40 16 66 45 14 48 34 21 41 27 3 55 27 37 23 41 65 4 57 51 74 +22 19 75 42 16 19 46 16 10 48 20 19 37 41 14 57 9 17 55 38 5 60 7 46 20 43 36 +39 52 20 10 62 45 23 46 7 35 75 29 70 35 36 34 25 12 15 84 26 10 6 71 29 79 33 +32 25 59 76 82 64 58 7 8 19 41 74 2 53 65 24 1 55 51 36 21 79 28 5 17 41 36 63 +51 18 48 25 46 45 36 77 76 22 57 14 44 63 56 45 56 20 1 64 49 9 12 28 30 72 82 +73 33 3 22 30 43 56 67 62 2 57 13 50 20 57 38 43 61 9 8 57 65 76 9 ^ +183 1 54 34 83 10 33 51 86 81 82 69 18 8 22 64 19 86 62 58 33 37 17 34 5 29 83 +42 76 50 54 66 39 9 1 36 43 17 65 6 35 56 72 71 83 88 10 1 8 87 22 6 21 78 25 +89 43 62 40 55 85 31 89 74 63 46 28 24 26 31 17 7 8 27 19 12 85 17 20 27 77 10 +2 54 80 17 52 74 76 69 78 11 20 80 4 29 24 85 75 18 39 23 70 83 29 57 67 72 70 +33 4 15 46 42 2 69 13 53 33 69 64 33 64 14 40 69 59 78 71 19 85 16 65 38 82 55 +40 56 40 24 84 29 25 44 68 13 85 76 64 32 18 25 45 23 6 80 31 30 30 58 14 13 72 +57 14 41 28 52 73 26 76 83 56 54 2 36 11 65 66 38 50 8 41 88 77 ^ +200 1 25 57 40 46 78 57 34 78 61 36 66 57 38 80 22 32 68 71 30 74 37 81 66 77 +66 55 2 51 24 93 61 40 68 45 61 12 63 24 89 59 52 72 43 20 20 69 36 40 88 46 9 +62 55 77 84 20 18 6 77 15 52 39 75 3 26 4 85 17 62 29 11 92 46 58 29 59 28 42 +80 71 96 2 49 85 37 63 4 61 14 2 53 87 25 86 6 75 76 93 41 39 93 92 42 56 41 63 +26 28 18 77 11 50 78 79 1 12 12 91 29 13 58 5 56 92 66 59 4 39 47 95 5 5 62 33 +13 80 69 60 43 51 22 30 32 42 5 38 3 50 7 48 90 56 96 68 47 41 61 60 96 20 14 4 +19 19 23 25 13 9 38 52 17 11 96 48 19 25 88 42 7 74 59 48 70 55 24 18 28 44 46 +3 24 38 56 19 96 22 50 60 17 96 ^ +195 1 25 51 45 35 66 19 61 60 9 31 93 64 70 30 42 86 53 1 71 46 42 22 38 96 10 +99 34 76 26 55 73 63 63 97 23 92 81 64 46 1 30 31 35 86 91 88 64 87 16 37 69 84 +94 60 100 3 47 52 8 71 87 57 29 76 43 18 45 46 15 65 12 44 42 66 60 15 68 19 58 +39 62 76 9 92 101 57 32 4 34 15 41 62 32 89 71 43 35 31 41 21 17 82 33 96 27 62 +29 82 57 46 62 15 24 99 37 83 40 52 46 56 80 98 3 91 74 6 27 7 58 94 10 41 79 +97 84 77 74 26 99 95 61 19 17 24 55 15 85 84 30 45 93 44 100 44 39 59 46 18 95 +3 41 15 82 77 16 48 18 51 83 20 82 60 53 53 12 99 92 54 5 99 51 39 100 61 2 31 +52 49 86 94 16 78 84 91 42 ^ +212 0 56 98 16 98 78 22 72 33 103 104 52 84 12 65 15 85 101 97 84 31 51 26 100 +100 38 80 13 2 78 7 24 44 84 103 27 7 28 16 33 99 25 103 54 14 42 62 87 92 27 +22 42 5 52 100 84 73 72 63 24 48 56 52 23 5 17 76 31 1 95 58 43 60 50 62 30 23 +35 79 20 35 3 72 32 45 51 87 41 84 27 79 77 70 102 15 54 15 100 8 52 69 105 3 +30 84 42 93 66 89 69 74 24 33 42 97 4 38 99 106 13 93 6 106 74 100 54 45 21 59 +56 37 9 50 32 75 79 31 77 9 61 1 8 68 6 60 81 7 100 99 14 61 48 25 73 26 70 72 +94 3 11 98 31 5 67 7 39 92 73 88 101 32 105 34 82 81 11 72 48 10 59 71 51 71 35 +33 27 49 49 19 98 47 43 75 64 17 15 24 94 49 4 84 58 58 74 39 47 104 82 5 63 69 +90 19 ^ +236 1 29 79 41 40 72 51 12 92 34 52 44 69 104 21 97 89 96 48 21 4 61 40 28 67 +34 23 85 44 22 62 52 33 84 23 30 73 74 4 79 12 81 47 80 53 47 89 40 19 80 62 34 +61 29 41 95 43 1 70 63 55 53 18 19 13 48 10 19 89 49 4 52 53 56 76 10 8 104 77 +15 28 38 75 109 3 85 90 8 40 8 93 90 43 39 14 60 17 36 78 56 105 80 35 75 36 58 +82 50 100 98 45 74 13 66 95 72 71 95 34 14 98 72 33 38 37 52 6 14 107 59 3 29 +61 67 98 92 5 93 17 98 36 87 41 75 71 57 88 17 25 91 84 3 58 20 92 69 51 50 36 +31 14 25 18 30 18 1 41 104 30 82 59 87 70 34 96 28 47 62 81 103 109 103 100 7 +17 16 104 1 12 34 5 102 42 16 22 71 39 5 73 45 45 54 41 13 2 26 41 22 100 109 +30 44 4 90 108 53 38 104 68 28 56 47 51 94 22 7 81 85 26 50 9 72 98 54 59 96 52 +^ +232 1 92 72 47 37 33 38 92 17 8 28 88 22 62 69 32 89 75 3 72 96 85 13 105 24 38 +37 94 115 83 72 108 114 24 93 76 103 60 99 102 9 43 10 59 95 46 33 93 15 26 69 +44 2 86 107 55 45 61 65 92 66 9 55 39 70 83 29 98 67 13 111 15 20 31 62 8 2 51 +20 19 33 44 14 115 71 112 97 10 41 28 53 51 26 57 15 38 98 55 106 22 56 31 50 +95 107 110 84 70 10 108 96 73 100 25 36 55 88 71 63 96 30 90 96 79 22 7 30 23 +28 59 89 8 51 99 47 86 34 18 43 65 98 104 107 49 7 79 71 8 57 21 29 80 2 74 78 +44 57 9 61 22 13 68 52 91 74 98 43 30 58 68 95 101 72 102 76 42 99 108 47 25 73 +27 104 34 59 52 36 104 20 98 14 97 4 50 46 106 83 17 22 105 79 77 46 39 15 113 +20 37 100 106 65 66 76 7 12 72 35 8 22 50 40 68 101 23 54 96 44 51 87 18 6 46 +110 ^ +245 0 70 30 81 46 53 119 85 6 104 47 92 72 70 5 70 15 115 68 105 33 97 13 85 +106 14 61 29 22 86 45 57 69 91 38 38 28 66 13 60 95 103 3 15 5 113 38 23 62 5 +65 94 107 73 104 37 47 102 117 3 78 35 7 95 56 78 45 52 28 46 43 37 32 53 19 55 +29 47 97 76 115 83 71 11 45 62 73 99 116 2 24 116 7 28 41 2 29 37 52 23 5 118 +79 31 57 89 61 24 101 78 50 93 73 41 7 33 45 47 24 1 48 73 36 3 25 87 46 28 108 +54 68 53 67 119 28 36 118 104 42 88 27 112 4 74 85 1 63 39 97 71 74 75 76 10 49 +12 79 11 50 103 118 94 117 118 37 27 12 94 60 28 51 47 82 110 17 15 105 23 52 +43 12 21 22 81 41 12 74 90 42 108 117 98 67 4 69 44 76 105 38 101 21 80 70 10 +111 23 110 32 101 83 91 101 31 5 3 83 76 15 90 57 74 95 46 33 112 62 63 54 63 +49 59 4 64 40 68 110 74 105 91 86 102 27 55 34 88 55 ^ +240 0 55 79 75 84 113 22 4 113 109 31 33 17 96 11 29 63 98 103 107 116 34 14 9 +95 38 18 51 75 33 109 118 55 66 4 76 7 75 70 82 74 23 1 26 69 40 112 99 47 65 +31 70 119 52 103 88 85 86 28 16 12 76 25 22 78 64 21 86 27 61 77 72 108 2 18 +106 119 121 54 16 85 72 2 73 26 88 66 60 80 35 24 117 63 24 44 67 52 122 119 33 +72 16 99 98 69 54 19 42 28 53 114 32 117 81 100 57 49 123 56 21 68 80 53 95 1 +45 95 107 98 87 1 27 24 99 116 16 67 1 113 91 84 25 40 25 72 3 28 90 87 112 80 +16 117 45 77 36 90 105 59 88 122 64 108 108 71 98 18 50 115 93 105 77 35 6 46 +55 47 102 4 26 87 111 120 81 113 4 57 105 3 84 94 115 61 3 121 72 71 24 62 14 +60 99 61 96 103 51 107 6 65 81 114 83 121 109 49 104 30 73 82 92 94 9 8 11 98 +19 10 55 97 22 97 95 88 67 15 20 39 65 13 123 77 ^ +253 1 45 7 15 24 51 5 98 115 24 49 90 104 117 66 128 94 64 80 12 43 91 46 111 +59 58 77 30 14 88 60 123 68 41 44 68 40 104 118 41 43 93 90 105 92 16 127 26 54 +125 114 79 71 24 48 21 25 118 40 103 49 91 44 67 65 25 119 109 18 48 23 69 112 +38 61 64 87 84 104 119 110 122 92 22 1 8 83 34 100 32 62 41 46 112 34 102 76 56 +39 4 127 30 13 19 110 124 7 16 128 95 4 124 11 104 116 126 49 95 3 55 96 70 90 +101 4 122 96 75 118 39 128 99 92 18 42 20 87 83 35 75 111 61 67 71 28 101 9 56 +34 105 95 71 23 73 71 26 57 15 23 76 55 99 89 128 98 117 68 43 88 62 38 62 39 2 +83 36 15 26 60 128 96 73 74 10 1 12 42 22 2 77 33 33 32 57 13 14 82 57 12 39 3 +58 80 14 87 85 44 69 109 19 117 67 68 44 63 106 37 88 64 82 56 37 89 4 126 55 +98 114 84 99 91 43 92 21 26 58 84 102 75 116 124 5 101 5 97 46 109 15 29 79 72 +93 92 110 ^ +289 1 83 5 76 20 32 15 10 1 103 18 22 116 98 9 51 104 102 44 33 15 12 24 31 89 +1 6 28 101 8 64 72 106 30 5 52 89 111 39 108 64 85 17 57 124 22 105 78 115 3 40 +108 66 108 77 128 103 44 35 38 13 95 10 111 63 98 117 61 51 126 69 96 70 70 59 +39 13 97 33 112 2 77 7 123 70 83 29 66 67 49 79 19 104 115 14 60 2 55 40 71 33 +28 114 51 91 17 46 45 128 57 87 62 25 115 38 50 55 90 74 8 51 102 79 43 94 36 +122 94 12 41 36 25 104 91 24 7 99 80 30 126 32 63 122 107 114 27 28 79 41 12 35 +51 115 122 70 22 79 65 2 88 27 17 59 15 23 44 57 5 65 6 26 78 80 125 93 84 100 +45 22 129 68 36 111 74 118 11 50 42 120 47 21 8 86 112 26 67 60 99 45 93 47 8 +38 59 52 56 124 20 82 18 117 24 18 46 106 19 117 26 41 47 45 130 7 15 1 4 5 100 +10 85 50 44 11 48 92 119 108 42 118 24 20 69 107 90 96 48 103 7 2 90 50 18 130 +126 45 106 17 35 25 102 68 23 68 120 58 41 34 75 103 20 45 117 37 61 73 34 62 1 +125 58 74 21 21 129 7 86 110 76 66 124 ^ +263 1 100 135 7 75 23 5 81 110 31 118 29 1 62 11 41 88 109 119 102 37 3 30 123 +47 31 56 134 29 124 116 118 99 21 56 77 91 23 37 135 81 44 51 67 95 51 133 30 +57 67 116 122 48 100 7 132 97 106 69 93 4 95 125 102 103 119 81 57 133 96 37 +118 50 117 113 81 127 17 45 103 32 121 129 60 43 65 127 30 36 132 110 52 53 35 +71 12 76 22 72 130 112 99 76 26 21 73 63 63 97 23 58 115 132 114 1 132 31 35 18 +23 54 30 53 118 37 35 84 94 60 100 3 47 18 110 105 87 57 63 76 43 52 45 46 49 +65 12 10 42 66 60 117 34 19 92 5 28 76 9 126 101 125 32 38 34 15 7 62 32 21 3 +43 69 31 109 123 51 116 135 130 129 130 63 14 57 80 62 15 126 31 105 83 108 120 +80 124 46 98 105 91 6 6 27 7 58 128 78 7 79 63 84 77 74 128 65 61 95 121 17 24 +123 117 51 50 64 79 59 44 134 78 73 59 114 18 27 3 109 49 82 43 118 116 52 119 +15 122 82 26 87 53 114 133 92 88 39 99 17 107 134 95 104 31 52 49 94 ^ +286 0 120 16 104 136 117 82 138 32 65 114 119 137 121 8 12 46 126 26 119 73 130 +60 76 113 100 14 133 26 116 34 120 80 95 84 53 15 24 44 51 4 10 23 77 24 99 66 +37 54 63 42 136 21 34 76 5 17 128 101 1 59 40 113 112 32 97 31 93 105 79 91 18 +39 1 103 132 51 68 124 111 13 97 43 128 69 84 85 72 15 12 26 87 16 16 92 101 13 +77 4 118 89 103 56 42 16 60 44 39 126 46 18 83 93 41 105 3 82 106 115 91 6 4 54 +115 15 120 109 113 48 41 9 95 20 62 67 105 111 25 132 7 116 46 138 44 83 61 124 +131 35 107 6 109 81 114 67 41 137 77 56 74 73 34 12 14 69 52 11 98 47 54 83 81 +6 1 15 88 35 139 80 83 49 89 27 47 130 92 133 87 51 112 76 49 109 49 57 93 73 +22 117 50 64 58 97 139 36 131 111 133 58 33 8 88 55 38 90 46 30 118 57 29 82 74 +41 117 38 46 94 92 5 105 15 117 70 103 68 60 120 48 21 110 85 40 81 38 58 129 +56 10 99 86 76 81 26 23 25 68 16 28 127 65 18 71 75 77 100 26 11 130 104 28 34 +56 106 7 8 120 112 12 58 21 130 124 67 61 19 87 119 ^ +286 1 35 94 61 130 98 35 88 34 65 104 56 126 118 50 87 10 81 109 90 86 118 32 6 +114 88 39 38 39 62 3 12 134 72 137 35 75 81 115 106 140 112 11 123 41 103 45 95 +84 71 107 13 26 110 96 62 16 109 84 59 53 38 27 8 28 13 32 137 17 138 41 122 36 +99 65 99 83 36 112 29 49 70 96 126 136 131 116 3 18 17 126 142 14 37 141 141 +123 42 13 20 83 42 139 83 54 49 58 42 7 137 29 48 16 121 127 34 52 140 106 128 +58 36 124 83 24 69 54 61 112 17 6 95 97 24 57 86 124 59 71 119 67 1 109 54 68 +49 57 132 32 5 71 113 40 80 104 75 106 133 31 126 130 104 62 9 39 44 66 116 141 +135 96 132 19 41 121 126 124 77 8 4 60 82 6 101 124 89 51 123 48 40 85 77 21 +112 10 69 66 115 87 16 108 30 84 65 80 103 32 131 134 73 47 10 63 39 50 93 37 +135 114 69 48 34 58 23 27 133 37 9 40 98 41 115 99 70 83 29 42 67 133 55 79 80 +91 122 12 2 115 112 23 33 16 102 3 19 60 101 130 105 116 117 27 2 1 103 38 14 +55 78 26 116 123 54 67 139 82 74 70 84 72 17 132 25 68 31 120 103 140 ^ +285 1 65 30 51 119 48 107 92 84 69 28 136 143 54 20 6 70 47 142 64 4 65 59 73 +99 134 146 102 125 116 57 137 137 72 48 128 78 5 80 63 54 85 30 22 129 68 21 21 +74 28 128 107 27 60 2 93 95 71 37 11 37 15 39 102 3 104 65 80 59 52 113 34 20 +67 60 27 81 135 46 106 106 102 68 128 17 15 100 124 15 43 136 122 100 67 142 35 +14 53 120 2 89 93 99 73 9 122 39 77 15 96 90 43 79 134 60 92 105 55 96 31 119 +77 97 72 23 140 38 30 43 83 136 88 107 117 72 109 118 58 91 119 73 95 100 59 +138 123 54 49 143 50 133 66 106 45 80 88 42 93 5 59 77 101 74 110 104 40 92 19 +77 76 86 102 129 3 144 101 139 134 56 90 18 91 94 85 55 10 137 11 58 1 107 113 +70 22 7 56 29 143 111 8 46 45 116 122 129 89 7 121 53 95 14 49 118 62 125 91 37 +97 15 35 100 63 140 63 50 51 58 26 127 6 45 59 102 121 114 85 141 135 10 72 19 +106 66 66 41 53 13 38 1 21 103 50 108 46 66 70 43 140 124 40 63 144 97 137 47 +60 88 103 115 132 145 116 143 115 10 133 9 118 37 105 51 94 60 67 117 116 ^ +305 1 109 110 75 42 12 139 137 43 128 106 107 19 126 12 101 148 127 15 117 125 +125 62 96 13 76 70 96 101 110 138 8 95 76 143 17 32 97 79 149 39 31 94 123 21 +41 135 55 84 70 33 135 118 50 62 121 81 1 45 144 93 60 5 64 137 8 105 91 82 67 +27 113 119 53 18 98 79 48 84 32 135 128 5 1 20 76 17 85 108 72 36 141 140 49 +150 105 104 3 149 14 54 18 148 64 49 125 37 28 28 101 22 104 91 32 82 117 12 +114 69 58 2 58 115 9 108 47 59 65 14 92 7 4 86 98 16 82 92 95 38 94 10 10 48 97 +104 66 115 97 142 115 122 119 40 97 16 32 47 34 88 89 26 50 12 76 80 51 40 9 +133 24 44 40 122 84 108 22 142 140 99 44 15 54 8 42 125 150 130 21 79 124 62 46 +119 15 29 91 57 150 42 138 71 61 68 80 114 6 1 70 121 18 35 113 56 87 86 10 73 +14 29 41 72 89 1 133 87 101 123 59 90 142 77 133 52 78 48 34 138 134 27 17 60 +131 147 61 93 148 39 132 49 62 71 36 91 4 139 49 100 120 43 113 144 30 94 73 +127 40 34 50 100 110 88 114 94 35 138 33 72 61 58 65 24 107 6 54 81 114 56 137 +71 11 23 19 73 1 108 110 25 148 11 98 132 150 17 70 146 50 ^ +314 1 99 88 7 139 24 13 35 47 97 145 74 36 119 3 51 84 48 119 53 49 15 79 17 +120 103 148 64 30 41 97 120 75 111 63 58 131 134 18 13 10 48 18 16 48 43 15 54 +18 41 47 122 144 80 92 145 77 1 33 89 54 46 78 48 21 54 43 40 53 24 16 73 42 94 +29 44 34 151 152 23 123 12 142 140 43 37 88 29 19 35 72 96 151 130 62 112 34 36 +91 120 50 112 138 2 105 60 68 137 131 5 17 19 139 74 11 120 78 149 58 128 15 +104 16 126 78 20 57 134 71 49 90 76 108 126 100 54 68 39 132 153 42 147 146 124 +62 87 35 75 61 65 46 100 82 105 113 31 63 5 95 54 71 77 127 150 80 36 144 2 130 +59 74 39 3 152 121 122 18 117 12 117 141 118 135 62 36 69 5 39 53 150 52 153 +143 30 66 96 126 131 56 137 8 7 86 142 14 7 111 141 93 136 137 134 43 12 89 23 +44 9 152 146 121 97 19 38 110 91 67 14 32 110 66 68 8 130 84 73 118 59 24 41 72 +121 150 55 37 138 27 104 66 124 9 51 109 47 125 109 148 8 29 47 72 146 149 61 +93 10 20 54 15 76 133 125 106 110 94 32 9 29 148 36 66 121 125 56 112 9 1 111 +116 94 57 8 108 50 62 140 71 74 89 1 83 152 20 85 17 145 102 39 56 115 47 150 +108 64 98 ^ +335 1 28 103 19 92 95 152 152 10 11 13 155 67 11 83 101 69 153 152 45 141 14 +120 129 140 119 59 2 89 73 70 83 29 16 67 81 29 1 54 65 96 117 2 37 47 128 33 3 +89 108 98 139 49 78 27 103 39 119 94 132 90 38 132 55 65 131 90 58 2 54 100 69 +118 22 44 19 7 148 93 25 29 123 81 64 131 55 30 1 89 38 97 82 64 9 28 86 123 +151 10 133 40 154 102 4 111 65 9 63 59 124 116 72 105 76 57 137 97 32 145 108 +78 112 50 43 34 75 20 22 129 68 11 118 74 125 118 57 17 20 129 53 65 61 144 1 +17 142 156 52 100 54 15 20 59 52 63 131 20 57 124 31 125 46 106 76 92 8 98 154 +152 80 114 15 140 136 112 100 17 92 25 151 150 80 99 69 83 49 43 156 102 19 57 +122 96 30 3 39 134 40 32 75 5 76 127 138 99 17 57 52 150 130 18 127 33 23 116 +107 78 77 77 42 69 68 48 41 69 33 75 40 49 128 103 4 146 93 10 83 66 96 152 30 +38 12 33 5 39 47 41 34 60 74 20 42 156 67 46 56 102 89 3 124 81 99 104 56 50 8 +61 74 55 15 87 108 28 138 47 93 60 2 124 46 126 103 91 145 36 25 116 122 79 79 +7 111 13 85 121 9 98 32 125 81 134 77 112 15 70 33 110 13 50 148 8 133 127 153 +45 19 42 121 94 45 91 95 117 22 9 46 6 26 31 53 150 8 148 128 53 141 ^ +326 0 80 123 24 147 1 112 82 159 63 74 97 109 33 151 32 89 87 132 117 46 129 59 +115 91 114 118 37 21 9 94 60 25 89 47 79 110 55 12 143 99 87 43 88 56 57 160 76 +12 71 128 77 146 117 95 105 42 66 3 76 20 76 101 100 118 149 45 26 143 148 32 +57 39 129 19 31 84 123 1 152 135 5 54 30 13 125 68 30 62 101 51 142 5 94 83 20 +116 24 107 109 105 91 42 17 27 93 69 3 139 68 79 38 84 2 85 128 126 122 131 46 +17 35 98 42 26 111 100 29 120 55 84 114 109 145 14 18 138 14 9 85 7 18 129 91 2 +94 51 133 82 87 123 64 39 8 103 38 75 110 78 7 9 45 115 42 138 135 86 78 16 62 +52 75 159 54 151 121 149 77 74 16 85 47 102 105 82 119 10 67 137 153 148 135 28 +49 26 151 153 36 80 11 130 113 24 44 30 102 24 58 133 122 140 99 24 156 54 119 +42 115 140 90 132 19 94 2 157 99 136 19 71 7 130 153 108 51 21 58 70 74 137 1 +40 111 149 5 103 6 27 76 141 23 125 140 1 72 29 152 103 87 51 93 29 80 132 77 +123 153 68 159 14 98 114 158 121 158 81 137 41 93 118 140 122 19 22 31 147 41 4 +89 150 50 120 144 113 104 20 44 53 97 20 4 90 60 48 84 74 25 138 23 62 61 159 5 +14 107 6 4 81 114 46 97 11 112 154 130 73 132 60 ^ +325 0 58 137 96 11 98 67 98 103 57 146 21 59 88 151 139 148 127 25 17 47 115 34 +160 109 107 51 64 28 69 13 49 149 69 141 90 93 118 64 10 1 67 80 35 111 13 58 +101 124 132 147 154 18 162 6 162 33 5 34 142 41 161 82 114 70 92 145 57 155 137 +114 79 44 36 48 48 21 14 13 40 33 14 150 33 32 54 143 14 4 101 142 23 93 136 +132 120 147 17 38 163 143 5 52 46 151 130 32 72 34 124 150 51 100 112 128 126 +65 10 28 87 81 159 131 19 99 54 125 110 58 119 28 78 129 104 140 126 38 154 27 +114 61 153 90 66 98 76 50 158 48 39 82 123 22 147 136 114 52 37 35 75 41 15 150 +60 52 55 103 21 23 129 95 24 71 47 97 130 50 140 144 106 100 9 64 19 117 122 71 +92 8 77 156 97 121 98 85 2 36 39 109 143 23 120 156 133 93 154 36 66 116 131 +160 127 162 161 46 142 14 141 81 141 63 86 117 104 3 146 39 127 34 133 102 106 +91 57 9 28 60 61 7 158 12 80 26 8 122 80 44 63 68 49 158 21 32 81 150 15 141 +108 161 64 46 124 123 31 99 27 105 109 98 112 9 37 12 116 149 51 73 144 124 4 +119 46 133 75 86 90 84 2 9 19 108 6 16 101 115 16 92 163 125 101 106 64 37 8 68 +40 42 130 41 24 89 115 43 112 85 121 125 92 154 9 46 115 7 140 108 158 ^ +336 0 38 42 155 103 9 62 65 102 122 10 138 160 125 47 158 43 91 69 123 132 35 +121 4 110 89 130 69 29 139 69 53 70 83 29 163 67 41 9 108 34 45 76 87 2 144 164 +98 33 160 79 78 48 89 9 38 134 93 146 79 54 122 80 38 112 55 55 101 70 8 129 44 +70 59 98 149 24 136 124 138 63 25 166 83 51 34 91 45 30 118 59 28 87 72 44 116 +28 36 103 101 113 10 114 62 111 71 65 126 53 19 114 86 42 85 36 57 137 57 159 +95 88 78 72 20 23 14 65 10 22 129 68 1 68 74 75 108 7 7 147 109 13 35 51 104 +158 164 122 126 2 50 4 132 127 59 52 13 81 20 47 107 74 148 115 46 106 46 82 +115 68 144 142 60 104 15 90 136 102 100 134 42 15 141 100 40 49 49 73 166 13 +156 82 166 37 82 96 137 130 166 134 20 139 45 122 56 107 98 79 124 17 32 130 +120 165 77 23 130 96 67 68 47 37 12 29 18 38 158 19 160 55 147 39 118 83 121 96 +43 137 33 66 86 112 147 155 149 140 5 19 17 148 161 10 44 159 146 57 16 26 102 +49 3 104 61 59 74 56 10 165 31 54 25 142 157 37 58 165 128 154 73 50 149 94 36 +76 63 71 135 26 5 116 122 29 69 7 101 140 75 81 136 78 2 125 71 84 57 62 162 40 +3 80 130 50 98 125 93 127 153 45 146 149 121 74 5 41 55 77 139 166 153 113 153 +21 53 140 145 148 88 162 ^ +341 0 4 62 78 167 102 144 94 55 141 63 29 97 91 24 115 166 80 69 132 99 1 120 +23 88 64 87 118 37 137 152 94 60 168 71 47 52 110 37 155 125 63 42 43 52 11 12 +151 31 12 44 110 32 128 117 68 87 24 39 164 76 145 58 101 91 100 140 151 143 +130 32 21 3 111 1 31 75 123 153 116 135 130 27 164 165 116 23 12 62 83 24 133 +139 49 74 154 80 158 80 64 105 91 6 142 27 75 24 128 112 41 79 29 84 145 40 128 +99 95 95 19 17 160 89 15 17 84 64 11 93 10 66 78 73 127 148 18 129 139 143 49 +150 9 84 82 154 85 15 88 82 60 87 19 12 133 58 20 39 65 51 141 134 27 70 167 +120 117 86 60 16 44 16 57 132 18 142 85 104 59 47 141 58 2 66 96 46 119 153 40 +110 126 103 90 144 13 26 106 144 80 145 134 103 95 24 44 21 84 140 13 97 104 +140 99 6 147 54 83 42 106 131 54 96 135 67 118 121 81 109 10 53 132 112 117 81 +33 155 49 61 38 119 1 13 102 131 148 94 131 143 67 123 148 89 104 135 72 145 +152 76 87 6 66 2 71 123 77 114 108 59 123 166 62 96 140 94 149 116 36 128 23 93 +91 95 113 162 156 165 111 166 4 44 105 5 120 99 113 68 11 169 35 70 2 147 125 +81 15 12 57 56 16 138 14 53 61 114 121 5 107 6 129 81 114 37 61 127 67 136 94 +73 114 32 34 119 72 11 98 37 74 73 51 146 161 35 146 ^ +349 0 142 139 121 91 16 163 2 88 171 133 100 62 51 46 10 24 150 49 131 60 114 +63 84 91 64 165 138 40 44 172 111 141 58 74 115 96 129 145 164 153 170 126 24 +169 16 115 41 125 46 87 61 92 145 39 155 92 78 70 35 27 21 48 21 151 159 40 15 +5 132 170 23 18 107 160 150 56 133 23 66 109 123 102 102 172 166 145 116 151 34 +1 151 130 5 36 34 97 114 15 82 128 112 119 99 29 138 165 42 36 159 95 19 63 36 +89 101 40 92 1 33 93 104 113 126 2 136 96 52 108 90 57 89 31 5 113 30 39 37 96 +4 147 127 105 43 165 35 75 23 143 105 24 25 10 94 12 160 102 95 170 71 20 70 +112 23 95 144 61 73 137 55 1 81 95 26 65 172 41 147 79 103 80 40 121 36 12 64 +98 169 93 111 115 48 127 9 39 107 131 115 118 162 161 10 142 14 123 54 141 36 +41 99 77 140 128 167 82 25 106 57 70 64 21 19 15 34 126 149 167 53 163 127 86 +35 8 54 23 40 140 3 169 45 150 152 96 81 143 28 28 124 87 13 90 9 87 109 53 67 +164 28 131 89 149 42 55 126 79 132 74 19 133 30 68 72 75 148 9 10 72 152 144 83 +106 153 74 163 98 92 97 37 19 8 32 31 24 121 14 152 89 79 7 76 155 85 76 107 83 +154 155 37 115 144 131 108 116 26 36 137 103 3 44 47 72 104 10 120 154 107 35 +152 19 85 69 105 120 29 109 171 104 65 124 39 11 127 57 41 70 83 29 157 67 164 ^ +370 1 167 63 16 27 58 60 2 99 128 71 33 160 70 51 3 44 149 2 89 84 101 43 18 +113 71 38 94 55 46 74 52 139 102 35 43 50 80 122 6 100 88 129 36 25 148 47 24 7 +55 36 30 82 32 19 78 63 26 71 28 167 85 56 167 95 159 78 26 66 35 65 90 44 159 +105 59 15 67 57 137 21 132 50 70 78 36 169 5 172 56 1 22 129 68 168 23 74 30 99 +138 174 120 91 153 8 42 68 158 155 104 99 133 5 135 96 82 59 52 144 36 20 38 62 +29 112 106 46 106 19 73 70 41 135 133 42 95 15 45 136 93 100 98 173 6 132 55 4 +4 31 64 130 162 156 64 157 19 46 96 92 103 139 134 2 94 18 86 38 89 62 61 79 +157 14 112 111 156 32 14 85 78 31 59 20 1 161 169 149 29 122 150 133 37 102 30 +109 65 85 51 174 110 164 66 77 76 111 119 131 95 5 1 166 103 134 141 17 158 123 +137 48 165 175 102 13 3 86 43 23 47 56 150 165 4 36 174 115 157 168 13 147 119 +109 55 41 140 67 27 31 27 53 126 17 163 116 122 160 60 7 92 113 66 45 109 60 +151 125 62 39 39 17 153 13 152 53 94 50 53 89 57 127 153 45 119 104 121 56 145 +172 19 41 103 166 108 68 126 12 53 131 127 148 52 134 168 50 48 155 72 132 82 +37 129 63 175 97 79 18 91 148 74 57 132 87 147 114 175 70 46 69 118 37 107 140 +94 60 156 59 47 34 110 25 143 113 39 12 43 28 157 158 145 1 12 26 98 2 116 117 +50 75 12 21 164 76 121 46 101 85 88 134 146 127 143 79 ^ +364 0 32 164 146 93 162 31 66 123 144 80 135 94 137 156 107 157 173 62 65 176 +124 112 4 65 127 44 131 53 19 105 91 149 106 27 57 158 92 85 14 79 20 84 127 +174 128 72 68 59 171 17 124 80 167 8 57 28 172 66 144 48 42 37 109 121 18 120 +103 116 13 132 39 73 145 76 158 43 82 33 51 153 164 97 13 2 3 20 24 114 98 9 25 +131 102 99 86 42 16 26 159 39 105 161 133 49 59 41 20 105 31 136 30 87 10 119 +135 13 83 99 58 45 99 156 26 61 135 143 80 118 107 76 77 24 44 12 66 95 147 61 +86 140 99 167 138 54 47 42 97 122 18 60 90 40 73 85 63 82 1 35 96 94 81 54 15 +128 40 52 2 101 1 165 93 113 130 85 95 98 58 105 112 53 68 108 72 100 152 49 87 +140 39 154 62 114 77 105 63 50 87 157 26 78 122 67 140 71 170 119 5 93 64 50 +104 144 129 138 75 130 4 178 60 139 120 54 113 32 2 133 17 43 163 129 89 72 149 +155 30 38 7 138 5 44 61 69 76 175 107 6 93 81 114 28 25 82 22 118 58 73 96 175 +177 92 36 11 98 171 38 28 42 146 125 178 88 136 139 103 67 10 151 151 70 153 +115 94 32 51 34 177 173 132 49 119 54 96 45 78 73 64 159 120 22 20 154 111 117 +58 56 109 72 117 139 152 147 170 102 18 169 4 97 41 101 22 69 55 92 145 27 155 +62 54 64 29 21 3 48 21 133 147 40 3 178 120 152 17 173 83 148 138 26 127 23 48 +91 117 90 72 166 142 133 98 139 22 150 151 130 140 ^ +372 0 34 70 78 161 64 92 112 110 72 175 102 138 179 173 159 59 19 27 18 53 92 +22 65 156 170 57 104 86 126 148 118 155 78 43 63 90 48 80 168 142 68 12 39 174 +69 168 147 118 96 34 129 35 75 5 107 60 170 180 147 85 3 133 75 95 152 71 175 +43 94 178 50 144 16 46 101 46 165 45 68 163 38 172 5 138 61 85 62 177 76 36 167 +19 53 151 66 66 97 3 100 164 12 98 131 70 109 162 161 156 142 14 105 27 141 9 +178 81 50 113 110 131 37 16 79 12 34 37 167 173 10 152 7 81 140 158 26 136 82 +50 172 154 45 160 31 122 167 142 9 150 125 51 54 125 174 10 124 51 177 81 173 +69 109 8 22 155 19 86 62 149 33 37 108 34 96 29 174 133 167 50 54 66 130 9 1 36 +134 108 65 97 126 56 163 71 83 88 10 1 8 178 22 6 112 169 116 89 43 153 40 146 +85 31 89 74 154 137 28 115 117 122 108 98 8 27 110 103 176 17 20 27 77 10 93 +145 80 17 143 165 76 69 78 102 20 91 171 95 29 115 176 166 109 39 23 70 83 29 +148 67 163 161 33 4 15 46 42 2 69 104 53 33 160 64 33 155 14 131 160 59 78 71 +19 176 107 65 38 82 55 40 56 40 115 84 29 25 44 68 104 176 76 64 123 18 25 136 +23 6 171 31 30 30 58 14 13 72 57 14 41 28 143 73 26 167 83 147 54 2 36 11 65 66 +38 141 99 41 179 55 158 57 137 179 114 20 58 78 12 157 175 166 50 177 22 129 68 +168 175 74 93 114 174 102 79 135 172 36 44 158 149 92 81 109 157 111 72 119 ^ +372 0 59 52 112 180 20 30 22 173 80 98 46 106 179 65 30 17 127 125 26 87 15 5 +136 85 100 66 141 182 124 15 156 148 15 56 98 146 156 48 149 3 14 96 52 79 115 +134 170 54 178 54 22 73 30 45 39 133 182 96 103 148 176 6 45 62 183 51 180 153 +145 145 117 21 90 118 109 21 62 22 101 49 53 11 142 86 132 66 69 44 79 87 115 +55 5 169 150 63 110 109 177 150 91 129 40 149 159 102 165 3 70 27 175 23 56 126 +165 164 20 158 91 157 136 157 131 111 69 39 33 132 43 19 175 179 37 118 9 155 +116 122 128 52 7 84 89 58 13 85 44 135 125 54 183 23 161 145 173 136 29 62 50 +13 57 25 127 153 45 95 64 121 40 121 140 171 9 71 166 68 28 102 4 53 123 111 +148 20 102 160 34 8 139 32 116 66 13 113 63 143 97 63 10 59 124 66 41 132 71 +115 106 151 46 22 45 118 37 67 124 94 60 140 43 47 10 110 9 127 97 7 156 43 180 +125 126 137 145 12 2 82 146 100 117 26 59 180 181 164 76 89 30 101 77 72 126 +114 95 143 102 32 149 131 83 157 31 61 123 139 60 135 74 169 122 151 102 137 +168 62 55 166 119 97 163 60 112 24 116 38 178 105 91 134 86 27 47 138 72 70 183 +79 15 84 117 154 128 57 53 39 161 17 104 75 157 3 42 8 167 51 124 38 22 17 99 +106 18 115 83 101 177 122 179 14 68 140 71 143 18 82 18 31 133 154 77 172 176 +167 179 9 99 78 183 111 92 89 86 32 16 16 144 29 90 146 128 29 34 31 5 85 16 +116 10 82 174 119 125 79 ^ +391 0 59 75 18 5 59 132 26 21 127 119 80 94 83 52 61 24 44 4 50 55 115 29 70 +140 99 159 130 54 15 42 89 114 173 28 50 16 33 53 47 58 180 19 64 78 49 30 186 +104 32 44 157 85 1 149 85 97 114 77 63 58 50 89 80 21 36 84 72 60 152 25 87 108 +15 138 54 106 77 97 23 42 55 149 181 62 106 43 132 31 138 111 176 93 40 10 96 +128 105 114 43 98 4 146 20 107 120 14 113 181 101 1 19 155 113 57 64 117 131 6 +22 186 138 184 36 61 29 36 175 107 6 61 81 114 20 180 42 169 102 26 73 80 151 +153 68 4 11 98 139 6 175 34 146 93 154 88 128 139 79 35 2 135 119 46 129 91 86 +179 51 18 169 141 108 49 103 46 72 21 70 49 64 151 96 185 175 130 111 85 58 32 +101 40 101 131 136 139 170 70 10 169 175 73 41 69 177 45 47 92 145 11 155 22 22 +56 21 13 166 48 21 109 131 40 174 178 104 128 9 149 51 132 122 173 119 23 24 67 +109 74 32 158 110 117 74 123 6 118 151 130 150 167 34 55 58 146 54 72 112 105 +57 160 82 123 159 153 159 39 19 7 8 33 87 12 50 146 150 37 104 71 126 133 108 +145 68 38 38 90 43 75 148 122 43 2 39 154 54 163 147 113 91 29 109 35 75 182 87 +35 155 170 127 80 185 118 60 95 142 71 165 28 84 168 25 144 178 31 81 41 160 25 +53 143 23 172 172 133 51 75 52 157 51 36 157 181 28 141 51 41 87 165 85 154 184 +93 131 45 104 162 161 141 142 14 95 12 141 181 158 71 35 98 100 111 12 11 64 +174 14 22 152 173 5 132 179 56 135 153 11 121 57 30 152 139 40 140 53 ^ +384 1 106 159 118 167 150 101 11 30 109 150 184 124 19 169 73 165 53 109 158 +172 147 11 46 38 149 25 21 92 184 64 179 158 133 135 34 38 58 114 9 183 4 118 +76 49 89 102 40 163 47 75 80 176 175 8 154 14 180 104 153 84 89 11 129 8 138 85 +181 73 66 154 121 20 115 93 114 108 82 182 19 86 103 176 183 186 177 53 10 69 +137 56 1 135 141 68 69 54 86 12 75 171 87 187 107 144 150 93 23 7 70 83 29 140 +67 139 153 183 178 189 30 18 2 29 72 29 33 160 56 9 123 164 107 136 19 70 31 +177 152 99 57 38 66 55 32 32 24 83 60 21 1 36 52 80 168 44 32 115 184 25 120 +181 172 155 189 22 30 26 180 5 64 49 188 1 28 111 57 176 167 67 131 22 160 186 +169 65 34 30 117 91 17 163 39 134 57 137 155 90 170 42 78 170 141 167 158 42 +177 22 129 68 168 143 74 150 85 82 174 78 63 111 156 28 12 158 141 76 57 77 125 +79 40 12 59 52 88 156 20 24 182 149 56 92 46 106 167 59 189 121 119 14 81 15 +165 136 79 100 42 117 182 118 175 138 124 3 50 74 134 156 36 143 181 180 96 22 +61 97 134 164 24 166 30 10 61 6 33 9 115 176 84 97 142 152 15 50 165 45 168 135 +133 127 93 15 66 94 91 9 32 16 95 37 29 171 118 68 108 66 63 20 55 63 103 25 5 +163 138 33 92 85 165 144 67 123 34 137 147 102 147 3 58 15 157 5 56 108 165 152 +8 146 73 157 112 133 119 105 39 27 27 126 25 13 151 161 25 112 3 149 116 122 +104 46 7 78 71 52 179 67 32 123 125 48 159 11 137 139 161 110 ^ +394 0 2 26 50 161 21 182 127 153 45 68 19 121 22 94 104 144 166 35 166 23 176 +75 188 53 114 93 148 177 66 151 16 156 121 180 98 48 179 95 63 107 97 45 1 23 +97 57 23 132 53 79 97 124 19 188 18 118 37 22 106 94 60 122 25 47 176 110 184 +109 79 164 120 43 153 89 90 128 109 12 168 64 110 82 117 192 41 171 163 164 76 +53 12 101 68 54 117 78 59 143 84 32 122 104 65 148 31 52 123 130 24 135 38 151 +95 142 93 101 159 62 37 148 110 70 127 51 85 181 89 11 142 105 91 107 50 27 29 +102 36 43 165 79 6 84 99 118 128 30 26 3 143 17 68 66 139 187 15 165 158 24 88 +20 179 174 81 79 18 106 47 74 150 104 179 162 59 131 62 116 166 82 184 188 97 +136 41 136 167 140 143 175 72 42 174 148 75 74 71 86 14 16 191 117 11 63 119 +119 186 182 13 171 49 182 80 167 73 147 119 107 164 41 57 181 168 29 114 26 184 +121 101 80 76 65 34 49 24 44 191 38 25 91 5 58 140 99 153 124 54 184 42 83 108 +155 4 20 191 3 29 35 40 180 7 40 66 25 12 180 86 26 38 139 73 1 137 79 85 102 +71 39 28 44 77 56 190 12 66 72 30 152 7 87 84 190 126 48 100 77 91 186 36 31 +143 163 50 94 25 126 1 114 105 170 93 22 173 90 116 87 96 19 74 4 122 183 83 +120 177 113 169 181 77 182 1 149 101 33 58 93 113 181 10 186 138 184 30 61 192 +6 175 107 6 37 81 114 14 162 12 145 90 2 73 68 133 135 50 173 11 98 115 175 151 +28 146 69 136 88 122 139 61 11 189 123 95 28 111 73 80 155 51 6 163 117 90 49 +91 40 54 189 ^ +390 0 62 25 64 143 72 169 151 106 111 53 58 8 93 8 85 123 120 131 170 38 2 169 +167 49 41 37 153 21 39 92 145 190 155 177 185 48 13 5 150 48 21 85 115 40 166 +178 88 104 1 125 19 116 106 141 111 23 43 101 58 187 150 78 101 50 107 185 86 +151 130 134 143 34 31 26 122 38 40 112 97 33 136 50 99 127 121 159 7 19 170 187 +1 79 191 26 130 118 5 104 47 126 109 92 129 52 30 193 90 35 67 116 90 3 181 39 +122 30 155 147 105 83 21 77 35 75 174 55 190 131 154 95 72 185 94 36 95 126 71 +149 4 68 152 180 144 146 7 49 33 152 188 29 111 194 172 148 125 35 59 36 125 11 +36 141 149 183 125 27 1 71 133 61 138 168 85 131 5 96 162 161 117 142 14 79 183 +141 165 126 55 11 74 84 79 167 3 40 142 177 193 128 173 192 100 163 16 127 145 +182 97 17 193 120 115 32 108 18 96 154 103 152 150 86 181 15 99 135 179 124 194 +164 68 160 43 109 138 152 142 6 21 23 149 20 11 82 164 44 159 148 133 115 24 28 +53 104 9 183 179 108 56 39 84 87 30 163 32 70 75 166 170 8 139 9 175 99 143 64 +89 186 114 183 133 85 161 63 61 154 111 15 115 78 109 108 72 177 14 71 103 176 +173 176 157 38 10 54 132 41 186 130 126 63 69 39 76 7 65 171 82 172 102 124 140 +83 13 192 70 83 29 135 67 124 148 163 173 184 20 3 2 4 52 14 33 160 51 189 103 +144 92 121 189 65 6 162 137 94 52 38 56 55 27 17 14 63 45 16 181 31 42 65 163 +24 12 110 174 25 110 166 162 145 174 17 30 6 170 59 44 183 171 28 91 47 156 172 +^ +400 1 51 115 188 136 154 145 65 2 22 93 83 191 147 23 110 57 137 131 66 138 26 +78 146 125 159 150 34 177 22 129 68 168 111 74 118 77 50 174 54 47 87 140 20 +178 158 133 60 33 45 93 47 8 170 59 52 56 124 20 16 150 117 24 84 46 106 151 51 +158 173 113 111 196 73 15 133 136 71 100 10 85 182 110 143 114 92 185 42 42 118 +156 20 135 173 156 96 180 37 73 134 156 182 150 196 192 45 172 17 167 91 168 68 +89 134 120 190 173 34 141 37 152 111 117 103 61 7 34 62 67 191 190 8 87 21 195 +139 86 44 76 66 55 186 23 31 87 183 5 155 122 191 68 53 149 136 35 115 26 121 +131 102 123 3 42 197 133 179 56 84 165 136 190 130 49 157 80 101 103 97 197 11 +19 118 1 5 119 137 9 104 193 141 116 122 72 38 7 70 47 44 155 43 16 107 125 40 +127 193 105 131 145 108 185 6 50 141 1 167 127 153 45 53 192 121 12 79 84 129 +151 15 166 196 156 60 188 53 109 83 148 162 46 146 6 136 111 160 88 38 169 85 +63 87 97 35 194 3 82 52 13 132 43 59 92 109 4 178 3 118 37 195 96 94 60 112 15 +47 166 110 179 99 69 149 100 43 138 69 70 123 89 12 158 54 90 72 117 182 31 166 +153 164 76 33 2 101 63 44 112 58 39 143 74 32 107 89 55 143 31 47 123 125 4 135 +18 141 80 137 88 81 154 62 27 138 105 55 107 46 70 166 74 194 122 105 91 92 30 +27 19 82 16 28 155 79 1 84 89 98 128 15 11 181 133 17 48 61 129 187 150 153 9 +68 10 164 159 71 64 18 101 27 59 135 94 179 142 54 126 57 101 146 82 174 173 77 +126 21 116 162 125 123 165 57 22 169 153 ^ +394 0 47 60 57 86 16 184 96 197 42 98 112 165 154 199 157 21 168 52 146 66 126 +119 93 150 20 36 153 140 194 93 26 156 114 80 80 55 44 13 35 24 44 191 24 190 +63 177 44 140 99 146 117 54 163 42 76 101 134 176 185 177 168 1 21 19 180 193 +12 52 197 191 173 65 19 31 118 59 1 123 72 71 88 64 11 193 37 63 28 169 184 45 +72 195 152 186 87 56 176 112 41 93 77 84 158 29 3 136 142 36 80 4 119 166 86 98 +163 93 1 145 83 102 66 75 191 46 4 94 155 55 120 149 113 148 181 49 175 180 142 +87 5 51 65 92 167 196 186 138 184 23 61 164 171 175 107 6 9 81 114 7 141 177 +117 76 174 73 54 112 114 29 152 11 98 87 154 123 21 146 41 115 88 115 139 40 +183 189 109 67 7 90 52 73 127 51 192 156 89 69 49 77 33 33 182 57 10 64 138 57 +159 136 91 111 33 58 193 88 188 75 118 110 126 170 18 197 169 162 34 41 17 138 +6 34 92 145 185 155 157 170 43 8 140 48 21 70 105 40 161 178 78 89 196 110 199 +106 96 121 106 23 185 28 96 48 167 145 58 91 35 97 180 66 151 130 124 128 34 16 +6 107 28 20 112 92 18 121 30 84 107 101 159 187 19 155 182 181 74 186 11 120 98 +185 104 32 126 94 82 119 42 25 173 90 30 62 96 70 178 176 39 102 15 150 147 100 +78 16 57 35 75 169 35 170 116 144 75 67 185 79 21 95 116 71 139 189 58 142 160 +144 126 192 29 28 147 173 14 91 184 172 133 120 25 49 26 105 186 36 131 129 163 +115 12 176 61 113 46 128 158 80 131 180 91 162 161 102 142 14 69 173 141 155 +106 45 196 59 74 59 147 195 ^ +412 0 16 110 153 177 104 173 192 68 147 179 119 137 166 73 180 169 88 91 24 76 +10 80 146 79 128 150 62 149 194 83 111 171 124 170 156 60 152 27 109 106 120 +134 201 184 202 149 12 198 66 132 12 127 132 133 83 8 12 45 88 9 183 155 92 24 +23 76 63 14 163 8 62 67 150 162 8 115 1 167 91 127 32 89 162 90 159 125 85 129 +47 53 154 95 7 115 54 101 108 56 169 6 47 103 176 157 160 125 14 10 30 124 17 +178 122 102 55 69 15 60 202 49 171 74 148 94 92 124 67 200 184 70 83 29 127 67 +100 140 131 165 176 4 182 2 167 20 193 33 160 43 173 71 112 68 97 157 57 169 +138 113 86 44 38 40 55 19 196 201 31 21 8 165 23 26 41 155 195 183 102 158 25 +94 142 146 129 150 9 30 177 154 195 51 36 175 139 28 59 31 124 167 41 105 173 +121 134 130 65 185 17 78 78 181 137 13 95 57 137 116 51 118 16 78 131 115 154 +145 29 177 22 129 68 168 91 74 98 72 30 174 39 37 72 130 15 163 158 128 50 18 +25 73 27 191 150 59 52 36 104 20 11 130 97 4 79 46 106 141 46 138 163 108 106 +191 68 15 113 136 66 100 193 65 182 105 123 99 72 180 37 22 108 156 10 130 168 +141 96 160 22 58 134 151 162 140 181 187 35 157 7 147 76 163 58 84 129 100 190 +153 24 126 32 142 96 107 88 41 2 14 42 52 186 170 3 82 11 180 119 66 29 56 66 +50 171 3 11 77 163 5 150 112 171 53 33 139 131 15 110 21 111 121 102 108 3 32 +192 118 169 56 69 165 126 185 120 34 157 60 81 93 92 177 1 14 113 189 99 122 +202 99 193 136 116 122 52 33 7 65 32 39 140 28 6 97 125 35 107 188 85 126 135 +98 175 189 50 121 184 116 ^ +413 1 127 153 45 32 164 121 203 58 56 108 130 192 166 168 128 39 188 53 102 69 +148 141 18 139 197 108 97 132 74 24 155 71 63 59 97 21 194 180 61 45 204 132 29 +31 85 88 188 164 187 118 37 167 82 94 60 98 1 47 152 110 172 85 55 128 72 43 +117 41 42 116 61 12 144 40 62 58 117 168 17 159 139 164 76 5 193 101 56 30 105 +30 11 143 60 32 86 68 41 136 31 40 123 118 181 135 195 127 59 130 81 53 147 62 +13 124 98 34 79 39 49 145 53 180 94 105 91 71 2 27 5 54 193 7 141 79 199 84 75 +70 128 199 195 160 119 17 20 54 115 187 184 129 146 193 40 201 143 138 57 43 18 +94 204 38 114 80 179 114 47 119 50 80 118 82 160 152 49 112 198 88 155 104 95 +151 36 199 162 100 27 50 47 86 195 16 179 81 192 27 83 107 150 134 194 147 1 +158 32 131 61 111 119 83 140 5 21 133 120 174 78 26 136 109 65 80 40 29 203 25 +24 44 191 14 170 43 162 34 140 99 141 112 54 148 42 71 96 119 161 165 167 148 +186 11 4 180 188 197 42 182 181 168 50 14 26 103 49 1 113 67 61 78 59 196 173 +32 53 8 154 169 30 72 175 152 176 87 36 166 102 36 88 77 79 138 24 188 131 127 +26 70 194 114 146 66 93 158 93 191 125 78 92 51 60 176 26 4 74 135 35 120 129 +113 133 181 29 170 170 137 77 190 46 45 77 157 191 186 138 184 18 61 144 151 +175 107 6 194 81 114 2 126 157 97 66 159 73 44 97 99 14 137 11 98 67 139 103 16 +146 21 100 88 110 139 25 168 189 99 47 197 75 37 68 107 51 187 151 69 54 49 67 +28 18 172 52 200 64 133 42 149 121 76 111 13 58 183 83 173 65 113 100 121 170 +203 197 169 157 19 202 ^ +434 1 193 114 190 26 92 145 177 155 125 146 35 200 124 48 21 46 89 40 153 178 +62 65 196 86 175 90 80 89 98 23 169 4 88 32 135 137 26 75 11 81 172 34 151 130 +108 104 34 200 182 83 12 196 112 84 202 97 206 60 75 69 159 163 19 131 174 157 +66 178 195 104 66 161 104 8 126 70 66 103 26 17 141 90 22 54 64 38 146 168 39 +70 199 142 147 92 70 8 25 35 75 161 3 138 92 128 43 59 185 55 205 95 100 71 123 +173 42 126 128 144 94 176 205 20 139 149 198 59 168 172 109 112 9 33 10 73 154 +36 115 97 131 99 196 144 45 81 22 112 142 72 131 148 83 162 161 78 142 14 53 +157 141 139 74 29 180 35 58 27 115 198 1 90 138 167 89 173 192 48 137 159 114 +132 156 58 160 154 68 76 19 56 5 70 141 64 113 150 47 129 184 73 96 166 124 155 +151 55 147 17 109 86 100 129 201 164 192 149 7 193 56 112 200 107 122 133 63 +206 2 40 78 9 183 140 82 4 13 71 48 4 163 201 57 62 140 157 8 100 204 162 86 +117 12 89 147 75 144 120 85 109 37 48 154 85 2 115 39 96 108 46 164 1 32 103 +176 147 150 105 207 10 15 119 2 173 117 87 50 69 50 202 39 171 69 133 89 72 114 +57 195 179 70 83 29 122 67 85 135 111 160 171 202 172 2 147 183 33 160 38 163 +51 92 53 82 137 52 149 123 98 81 39 38 30 55 14 186 196 11 6 3 155 18 16 26 150 +180 168 97 148 25 84 127 136 119 135 4 30 162 144 195 46 31 170 119 28 39 21 +104 167 31 95 158 106 114 115 65 170 12 63 73 171 127 3 80 57 137 101 36 98 6 +78 116 105 149 140 24 177 22 129 68 168 71 74 78 67 10 174 24 27 57 120 10 148 +158 123 40 3 5 53 7 176 130 59 52 16 84 20 6 110 77 192 74 46 106 131 41 118 +153 144 ^ +438 1 99 184 61 15 85 136 59 100 172 37 182 98 95 78 44 173 30 204 94 156 206 +123 161 120 96 132 1 37 134 144 134 126 160 180 21 136 203 119 55 156 44 77 122 +72 190 125 10 105 25 128 75 93 67 13 205 196 14 31 179 142 206 75 207 159 91 38 +8 28 66 43 150 185 193 63 135 5 143 98 143 32 5 125 124 197 103 14 97 107 102 +87 3 18 185 97 155 56 48 165 112 178 106 13 157 32 53 79 85 149 197 7 106 175 +203 71 101 195 92 193 129 116 122 24 26 7 58 11 32 119 7 202 83 125 28 79 181 +57 119 121 84 161 168 50 93 163 131 127 153 45 17 144 121 198 43 36 93 115 177 +166 148 108 24 188 53 97 59 148 126 208 134 192 88 87 112 64 14 145 61 63 39 97 +11 194 165 46 40 199 132 19 11 80 73 178 154 177 118 37 147 72 94 60 88 201 47 +142 110 167 75 45 113 52 43 102 21 22 111 41 12 134 30 42 48 117 158 7 154 129 +164 76 195 188 101 51 20 100 10 201 143 50 32 71 53 31 131 31 35 123 113 166 +135 180 117 44 125 76 33 142 62 3 114 93 19 59 34 34 130 38 170 74 105 91 56 +192 27 205 34 178 202 131 79 199 84 65 50 128 189 185 145 109 17 49 105 187 174 +114 141 183 20 196 128 123 47 28 18 89 189 23 99 70 179 94 42 114 45 65 98 82 +150 137 29 102 183 68 150 89 75 141 21 184 157 80 7 40 37 86 190 16 174 66 187 +12 68 102 135 114 189 137 191 148 12 116 56 96 119 73 130 200 6 113 100 154 63 +26 116 104 50 80 25 14 193 15 24 44 191 4 150 23 147 24 140 99 136 107 54 133 +42 66 91 104 146 145 157 128 171 1 199 180 183 182 32 167 171 163 35 9 21 88 39 +1 103 62 51 68 54 181 153 27 43 198 139 154 15 72 155 152 166 87 16 156 92 31 +83 77 74 118 19 173 126 202 ^ +431 0 10 54 178 106 114 34 85 150 93 175 93 70 76 27 36 152 207 4 42 103 3 120 +97 113 109 181 210 162 154 129 61 166 38 13 53 141 183 186 138 184 10 61 112 +119 175 107 6 170 81 114 207 102 125 65 50 135 73 28 73 75 203 113 11 98 35 115 +71 8 146 202 76 88 102 139 1 144 189 83 15 181 51 13 60 75 51 179 143 37 30 49 +51 20 207 156 44 184 64 125 18 133 97 52 111 194 58 167 75 149 49 105 84 113 +170 179 197 169 149 208 41 178 99 180 21 92 145 172 155 105 131 30 208 200 114 +48 21 31 79 40 148 178 52 50 196 71 160 80 70 69 93 23 159 202 83 22 115 132 6 +65 209 71 167 14 151 130 98 89 34 190 167 68 2 181 112 79 192 82 191 45 55 49 +159 148 19 116 169 142 61 173 185 94 46 146 104 206 126 55 56 93 16 12 121 90 +17 49 44 18 126 163 39 50 189 137 147 87 65 3 5 35 75 156 196 118 77 118 23 54 +185 40 195 95 90 71 113 163 32 116 108 144 74 166 190 15 134 134 188 39 158 172 +94 107 212 23 53 134 36 105 77 111 89 186 124 35 61 7 102 132 67 131 128 78 162 +161 63 142 14 43 147 141 129 54 19 170 20 48 7 95 198 199 70 123 157 74 173 192 +28 127 139 109 127 146 43 140 139 48 61 14 36 60 136 49 98 150 32 109 174 63 81 +161 124 140 146 50 142 7 109 66 80 124 201 144 182 149 2 188 46 92 185 87 112 +133 43 201 205 35 68 9 183 125 72 197 3 66 33 207 163 191 52 57 130 152 8 85 +204 157 81 107 205 89 132 60 129 115 85 89 27 43 154 75 210 115 24 91 108 36 +159 209 17 103 176 137 140 85 197 10 114 200 168 112 72 45 69 198 40 202 29 171 +64 118 84 52 104 47 190 174 70 83 29 117 67 70 130 91 155 166 197 162 2 127 193 +173 82 ^ +464 1 160 31 149 23 64 32 61 109 45 121 102 77 74 32 38 16 55 7 172 189 198 200 +211 141 11 2 5 143 159 147 90 134 25 70 106 122 105 114 212 30 141 130 195 39 +24 163 91 28 11 7 76 167 17 81 137 85 86 94 65 149 5 42 66 157 113 204 59 57 +137 80 15 70 207 78 95 91 142 133 17 177 22 129 68 168 43 74 50 60 197 174 3 13 +36 106 3 127 158 116 26 197 192 25 194 155 102 59 52 203 56 20 214 82 49 171 67 +46 106 117 34 90 139 96 94 179 56 15 65 136 54 100 157 17 182 93 75 63 24 168 +25 189 84 156 201 118 156 105 96 112 201 22 134 139 114 116 145 175 11 121 198 +99 40 151 34 72 117 52 190 105 90 20 118 60 83 52 208 205 181 209 16 174 122 +206 70 202 144 71 18 208 8 66 38 135 170 178 53 115 5 138 88 123 17 200 115 119 +182 98 9 87 97 102 72 3 8 180 82 145 56 33 165 102 173 96 213 157 12 33 69 80 +129 192 2 101 165 203 51 86 190 87 193 124 116 122 4 21 7 53 211 27 104 207 197 +73 125 23 59 176 37 114 111 74 151 153 50 73 148 116 127 153 45 2 124 121 193 +28 16 78 100 162 166 128 88 9 188 53 92 49 148 111 193 129 187 68 77 92 54 4 +135 51 63 19 97 1 194 150 31 35 194 132 9 206 75 58 168 144 167 118 37 127 62 +94 60 78 196 47 132 110 162 65 35 98 32 43 87 1 2 106 21 12 124 20 22 38 117 +148 212 149 119 164 76 180 183 101 46 10 95 205 186 143 40 32 56 38 21 126 31 +30 123 108 151 135 165 107 29 120 71 13 137 62 208 104 88 4 39 29 19 115 23 160 +54 105 91 41 177 27 200 14 163 192 121 79 199 84 55 30 128 179 175 130 99 17 +195 44 95 187 164 99 136 173 191 113 108 37 13 18 84 174 8 84 60 179 74 37 109 +40 50 78 82 140 122 9 92 168 48 145 74 55 131 6 169 152 60 202 30 27 86 185 16 +169 51 182 212 53 97 185 ^ +452 1 82 181 121 167 132 198 92 48 72 119 57 114 184 200 81 68 122 39 26 84 96 +26 80 1 208 177 217 24 44 191 206 118 209 123 8 140 99 128 99 54 109 42 58 83 +80 122 113 141 96 147 203 183 180 175 158 16 143 155 155 11 1 13 64 23 1 87 54 +35 52 46 157 121 19 27 174 115 130 209 72 123 152 150 87 202 140 76 23 75 77 66 +86 11 149 118 88 44 168 101 94 14 80 145 93 165 73 65 66 12 21 137 192 4 22 83 +201 120 77 113 94 181 195 157 144 124 51 151 33 211 38 131 178 186 138 184 5 61 +92 99 175 107 6 155 81 114 207 87 105 45 40 120 73 18 58 60 193 98 11 98 15 100 +51 3 146 187 61 88 97 139 204 129 189 73 213 171 36 216 55 55 51 174 138 17 15 +49 41 15 197 146 39 174 64 120 3 123 82 37 111 179 58 157 70 134 39 100 74 108 +170 164 197 169 144 198 41 163 84 170 16 92 145 167 155 85 116 25 208 200 104 +48 21 16 69 40 143 178 42 35 196 56 145 70 60 49 88 23 149 192 78 12 95 127 204 +55 199 61 162 212 151 130 88 74 34 180 152 53 210 166 112 74 182 67 176 30 35 +29 159 133 19 101 164 127 56 168 175 84 26 131 104 196 126 40 46 83 6 7 101 90 +12 44 24 216 106 158 39 30 179 132 147 82 60 216 203 35 75 151 181 98 62 108 3 +49 185 25 185 95 80 71 103 153 22 106 88 144 54 156 175 10 129 119 178 19 148 +172 79 102 207 13 208 33 114 36 95 57 91 79 176 104 25 41 210 92 122 62 131 108 +73 162 161 48 142 14 33 137 141 119 34 9 160 5 38 205 75 198 189 50 108 147 59 +173 192 8 117 119 104 122 136 28 120 124 28 46 9 16 213 50 131 34 83 150 17 89 +164 53 66 156 124 125 141 45 137 215 109 46 60 119 201 124 172 149 215 183 36 +72 170 67 102 133 23 196 200 30 58 9 183 110 62 182 211 61 18 202 163 97 ^ +463 1 45 50 116 145 8 64 204 150 74 93 184 89 111 39 108 108 85 61 13 36 154 61 +210 115 3 84 108 22 152 209 216 103 176 123 126 57 183 10 199 107 186 161 105 +51 38 69 184 26 202 15 171 57 97 77 24 90 33 183 167 70 83 29 110 67 49 123 63 +148 159 190 148 2 99 172 159 33 160 26 139 3 44 17 46 89 40 101 87 62 69 27 38 +6 55 2 162 184 183 190 211 131 6 212 210 138 144 132 85 124 25 60 91 112 95 99 +212 30 126 120 195 34 19 158 71 28 211 217 56 167 7 71 122 70 66 79 65 134 27 +61 147 103 199 44 57 137 65 50 202 78 80 81 137 128 12 177 22 129 68 168 23 74 +30 55 182 174 208 3 21 96 218 112 158 111 16 187 177 5 179 140 82 59 52 188 36 +20 214 62 29 156 62 46 106 107 29 70 129 91 89 174 51 15 45 136 49 100 142 217 +182 88 55 48 4 163 20 174 74 156 196 113 151 90 96 92 191 7 134 134 94 106 130 +170 1 106 193 79 25 146 24 67 112 32 190 85 210 75 15 108 45 73 37 193 205 166 +194 1 169 102 206 65 197 129 51 218 198 208 66 33 120 155 163 43 95 5 133 78 +103 2 185 105 114 167 93 4 77 87 102 57 3 218 175 67 135 56 18 165 92 168 86 +203 157 212 13 59 75 109 187 217 96 155 203 31 71 185 82 193 119 116 122 204 16 +7 48 201 22 89 197 192 63 125 18 39 171 17 109 101 64 141 138 50 53 133 101 127 +153 45 207 104 121 188 13 216 63 85 147 166 108 68 214 188 53 87 39 148 96 178 +124 182 48 67 72 44 214 125 41 63 219 97 211 194 135 16 30 189 132 219 191 70 +43 158 134 157 118 37 107 52 94 60 68 191 47 122 110 157 55 25 83 12 43 72 201 +202 101 1 12 114 10 2 28 117 138 207 144 109 164 76 165 178 101 41 90 190 171 +143 30 32 41 23 11 121 31 25 123 103 136 135 150 97 14 115 66 213 132 62 203 94 +83 209 19 24 4 100 8 150 160 ^ +474 0 105 91 20 156 27 193 208 142 178 107 79 199 84 41 2 128 165 161 109 85 17 +174 37 81 187 150 78 129 159 194 184 92 87 23 214 18 77 153 209 63 46 179 46 30 +102 33 29 50 82 126 101 203 78 147 20 138 53 27 117 207 148 145 32 181 16 13 86 +178 16 162 30 175 198 32 90 99 66 177 113 155 124 186 80 44 60 119 49 106 176 +192 65 52 106 27 26 68 92 14 80 211 200 169 213 24 44 191 202 102 197 111 140 +99 124 95 54 97 42 54 79 68 110 97 133 80 135 199 175 180 171 146 8 131 147 151 +221 219 9 52 15 1 79 50 27 44 42 145 105 15 19 162 103 118 201 72 107 152 142 +87 190 132 68 19 71 77 62 70 7 137 114 76 214 36 160 97 78 220 76 141 93 157 57 +61 58 9 125 180 4 6 67 189 120 61 113 82 181 183 153 136 120 43 139 29 199 26 +123 174 186 138 184 1 61 76 83 175 107 6 143 81 114 207 75 89 29 32 108 73 10 +46 48 185 86 11 98 221 88 35 221 146 175 49 88 93 139 196 117 189 65 201 163 24 +208 51 39 51 170 134 1 3 49 33 11 189 138 35 166 64 116 213 115 70 25 111 167 +58 149 66 122 31 96 66 104 170 152 197 169 140 190 41 151 72 162 12 92 145 163 +155 69 104 21 208 200 96 48 21 4 61 40 139 178 34 23 196 44 133 62 52 33 84 23 +141 184 74 4 79 123 192 47 191 53 158 200 151 130 80 62 34 172 140 41 206 154 +112 70 174 55 164 18 19 13 159 121 19 89 160 115 52 164 167 76 10 119 104 188 +126 28 38 75 220 3 85 90 8 40 8 204 90 154 39 14 171 128 147 78 56 216 191 35 +75 147 169 82 50 100 209 45 185 13 177 95 72 71 95 145 14 98 72 144 38 148 163 +6 125 107 170 3 140 172 67 98 203 5 204 17 98 36 87 41 75 71 168 88 17 25 202 +84 114 58 131 92 69 162 161 36 142 14 25 129 141 111 18 1 152 215 30 193 59 198 +181 34 96 139 47 173 192 214 109 103 100 118 128 16 104 112 198 ^ +466 0 25 2 213 213 36 124 13 62 150 221 61 150 39 45 149 124 104 134 38 130 208 +109 18 32 112 201 96 158 149 215 176 22 44 149 39 88 133 220 189 193 23 44 9 +183 89 48 161 204 54 222 195 163 167 40 45 106 140 8 49 204 145 69 83 169 89 96 +24 93 103 85 41 3 31 154 51 210 115 213 79 108 12 147 209 206 103 176 113 116 +37 173 10 189 102 176 156 100 36 33 69 174 16 202 5 171 52 82 72 4 80 23 178 +162 70 83 29 105 67 34 118 43 143 154 185 138 2 79 157 149 33 160 21 129 208 24 +2 31 69 35 81 72 47 64 22 38 221 55 222 152 179 168 180 211 121 1 207 200 133 +129 117 80 114 25 50 76 102 85 84 212 30 111 110 195 29 14 153 51 28 196 212 36 +167 222 61 107 55 46 64 65 119 220 12 56 137 93 194 29 57 137 50 210 30 197 78 +65 71 132 123 7 177 22 129 68 168 3 74 10 50 167 174 198 218 6 86 218 97 158 +106 6 177 162 210 164 125 62 59 52 173 16 20 214 42 9 141 57 46 106 97 24 50 +119 86 84 169 46 15 25 136 44 100 127 202 182 83 35 33 209 158 15 159 64 156 +191 108 146 75 96 72 181 217 134 129 74 96 115 165 216 91 188 59 10 141 14 62 +107 12 190 65 205 60 10 98 30 63 22 178 205 151 179 211 164 82 206 60 192 114 +31 203 188 193 66 28 105 140 148 33 75 5 128 68 83 212 170 95 109 152 88 224 67 +77 102 42 3 213 170 52 125 56 3 165 82 163 76 193 157 197 218 49 70 89 182 217 +91 145 203 11 56 180 77 193 114 116 122 189 11 7 43 191 17 74 187 187 53 125 13 +19 166 222 104 91 54 131 123 50 33 118 86 127 153 45 197 84 121 183 223 201 48 +70 132 166 88 48 204 188 53 82 29 148 81 163 119 177 28 57 52 34 209 115 31 63 +204 97 206 194 120 1 25 184 132 214 176 65 28 148 124 147 118 37 87 42 94 60 58 +186 47 112 110 152 45 15 68 217 43 57 186 187 218 ^ +477 1 200 12 100 223 201 14 117 124 200 137 95 164 76 144 171 101 34 213 83 169 +150 143 16 32 20 2 224 114 31 18 123 96 115 135 129 83 220 108 59 192 125 62 +196 80 76 195 218 17 210 79 214 136 6 105 91 5 141 27 188 193 127 168 97 79 199 +84 31 209 128 155 151 94 75 17 159 32 71 187 140 63 124 149 179 179 77 72 13 +204 18 72 138 199 48 36 179 26 25 97 28 14 30 82 116 86 188 68 132 133 38 7 107 +197 133 140 12 166 6 3 86 173 16 157 15 170 188 17 85 84 46 172 103 140 114 171 +65 39 45 119 39 96 166 182 45 32 86 12 26 48 87 226 80 201 190 159 208 24 44 +191 197 82 182 96 217 140 99 119 90 54 82 42 49 74 53 95 77 123 60 120 194 165 +180 166 131 225 116 137 146 211 219 4 37 5 1 69 45 17 34 37 130 85 10 9 147 88 +103 191 72 87 152 132 87 175 122 58 14 66 77 57 50 2 122 109 61 209 26 150 92 +58 205 71 136 93 147 37 56 48 212 221 110 165 4 213 47 174 120 41 113 67 181 +168 148 126 115 33 124 24 184 11 113 169 186 138 184 223 61 56 63 175 107 6 128 +81 114 207 60 69 9 22 93 73 31 33 175 71 11 98 206 73 15 221 146 160 34 88 88 +139 186 102 189 55 186 153 9 198 46 19 51 165 129 208 215 49 23 6 179 128 30 +156 64 111 203 105 55 10 111 152 58 139 61 107 21 91 56 99 170 137 197 169 135 +180 41 136 57 152 7 92 145 158 155 49 89 16 208 200 86 48 21 216 51 40 134 178 +24 8 196 29 118 52 42 13 79 23 131 174 69 221 59 118 177 37 181 43 153 185 151 +130 70 47 34 162 125 26 201 139 112 65 164 40 149 3 226 220 159 106 19 74 155 +100 47 159 157 66 217 104 104 178 126 13 28 65 215 225 65 90 3 35 215 189 70 +149 39 221 161 123 147 73 51 216 176 35 75 142 154 62 35 90 194 40 185 225 167 +95 62 71 85 135 4 88 52 144 18 138 148 1 120 92 160 210 130 172 52 93 198 222 +199 224 19 ^ +479 0 36 73 13 47 57 154 60 3 226 188 70 100 51 131 64 62 162 161 15 142 14 11 +115 141 97 219 216 138 201 16 172 31 198 167 6 75 125 26 173 192 193 95 75 93 +111 114 224 76 91 213 13 227 201 213 28 120 1 50 150 213 45 142 31 33 145 124 +92 130 34 126 204 109 2 16 108 201 80 150 149 215 172 14 28 137 23 80 133 208 +185 189 19 36 9 183 77 40 149 200 50 214 191 163 159 36 41 98 136 8 37 204 141 +65 75 157 89 84 12 81 99 85 25 224 27 154 43 210 115 205 75 108 4 143 209 198 +103 176 105 108 21 165 10 181 98 168 152 96 24 29 69 166 8 202 226 171 48 70 68 +217 72 15 174 158 70 83 29 101 67 22 114 27 139 150 181 130 2 63 145 141 33 160 +17 121 196 8 219 19 53 31 65 60 35 60 18 38 217 55 222 144 175 156 172 211 113 +226 203 192 129 117 105 76 106 25 42 64 94 77 72 212 30 99 102 195 25 10 149 35 +28 184 208 20 167 218 53 95 43 30 52 65 107 220 52 129 85 190 17 57 137 38 202 +14 193 78 53 63 128 119 3 177 22 129 68 168 216 74 223 46 155 174 190 214 223 +78 218 85 158 102 227 169 150 198 152 113 46 59 52 161 20 214 26 222 129 53 46 +106 89 20 34 111 82 80 165 42 15 9 136 40 100 115 190 182 79 19 21 197 154 11 +147 56 156 187 104 142 63 96 56 173 209 134 125 58 88 103 161 212 79 184 43 227 +137 6 58 103 225 190 49 201 48 6 90 18 55 10 166 205 139 167 203 160 66 206 56 +188 102 15 191 180 181 66 24 93 128 136 25 59 5 124 60 67 204 158 87 105 140 84 +224 59 69 102 30 3 209 166 40 117 56 220 165 74 159 68 185 157 185 206 41 66 73 +178 217 87 137 203 224 44 176 73 193 110 116 122 177 7 7 39 183 13 62 179 183 +45 125 9 3 162 210 100 83 46 123 111 50 17 106 74 127 153 45 189 68 121 179 215 +189 36 58 120 166 72 32 196 188 53 78 21 148 69 151 115 173 12 49 36 26 205 107 +23 63 192 112 ^ +485 1 200 194 102 214 19 178 132 208 158 59 10 136 112 135 118 37 63 30 94 60 +46 180 47 100 110 146 33 3 50 199 43 39 168 169 90 188 12 92 219 189 6 117 116 +196 133 87 164 76 132 167 101 30 209 79 157 138 143 8 32 8 221 220 110 31 14 +123 92 103 135 117 75 212 104 55 180 121 62 192 72 72 187 206 13 202 67 206 128 +221 105 91 224 129 27 184 181 115 160 89 79 199 84 23 197 128 147 143 82 67 17 +147 28 63 187 132 51 120 141 167 175 65 60 5 196 18 68 126 191 36 28 179 10 21 +93 24 2 14 82 108 74 176 60 120 215 129 26 222 99 189 121 136 227 154 229 226 +86 169 16 153 3 166 180 5 81 72 30 168 95 128 106 159 53 35 33 119 31 88 158 +174 29 16 70 26 32 83 218 80 193 182 151 204 24 44 191 193 66 170 84 213 140 99 +115 86 54 70 42 45 70 41 83 61 115 44 108 190 157 180 162 119 221 104 129 142 +203 219 25 228 1 61 41 9 26 33 118 69 6 1 135 76 91 183 72 71 152 124 87 163 +114 50 10 62 77 53 34 229 110 105 49 205 18 142 88 42 193 67 132 93 139 21 52 +40 204 213 98 153 4 201 31 162 120 25 113 55 181 156 144 118 111 25 112 20 172 +230 105 165 186 138 184 223 61 40 47 175 107 6 116 81 114 207 48 53 224 14 81 +73 223 19 21 167 59 11 98 194 61 230 221 146 148 22 88 84 139 178 90 189 47 174 +145 228 190 42 3 51 161 125 196 207 49 15 2 171 120 26 148 64 107 195 97 43 229 +111 140 58 131 57 95 13 87 48 95 170 125 197 169 131 172 41 124 45 144 3 92 145 +154 155 33 77 12 208 200 78 48 21 208 43 40 130 178 16 227 196 17 106 44 34 228 +75 23 123 166 65 217 43 114 165 29 173 35 149 173 151 130 62 35 34 154 113 14 +197 127 112 61 156 28 137 222 214 208 159 94 19 62 151 88 43 155 149 58 205 92 +104 170 126 1 20 57 211 225 49 90 230 31 203 177 54 145 39 209 153 119 147 69 +47 216 164 35 75 138 142 46 23 82 182 36 185 198 ^ +483 1 155 95 50 71 73 123 225 76 28 144 227 126 130 228 114 74 148 192 118 172 +34 87 192 216 193 206 54 36 65 230 31 49 146 44 228 214 180 62 92 47 131 48 58 +162 161 3 142 14 3 107 141 89 207 212 130 193 8 160 15 198 159 223 63 117 14 +173 192 181 87 59 89 107 106 216 60 79 201 1 227 189 213 20 116 222 38 150 205 +29 134 23 21 141 124 80 126 30 122 200 109 219 104 201 64 142 149 215 168 6 12 +125 7 72 133 196 181 185 15 28 9 183 65 32 137 196 46 206 187 163 151 32 37 90 +132 8 25 204 137 61 67 145 89 72 69 95 85 9 220 23 154 35 210 115 197 71 108 +229 139 209 190 103 176 97 100 5 157 10 173 94 160 148 92 12 25 69 158 202 222 +171 44 58 64 205 64 7 170 154 70 83 29 97 67 10 110 11 135 146 177 122 2 47 133 +133 33 160 13 113 184 225 211 7 37 27 49 48 23 56 14 38 213 55 222 136 171 144 +164 211 105 226 199 184 125 105 93 72 98 25 34 52 86 69 60 212 30 87 94 195 21 +6 145 19 28 172 204 4 167 214 45 83 31 14 40 65 95 220 221 48 121 77 186 5 57 +137 26 194 231 189 78 41 55 124 115 232 177 22 129 68 168 204 74 211 42 143 174 +182 210 215 70 218 73 158 98 223 161 138 186 140 101 30 59 52 149 217 20 214 10 +210 117 49 46 106 81 16 18 103 78 76 161 38 15 226 136 36 100 103 178 182 75 3 +9 185 150 7 135 48 156 183 100 138 51 96 40 165 201 134 121 42 80 91 157 208 67 +180 27 219 133 231 54 99 213 190 33 197 36 2 82 6 47 231 154 205 127 155 195 +156 50 206 52 184 90 232 179 172 169 66 20 81 116 124 17 43 5 120 52 51 196 146 +79 101 128 80 224 51 61 102 18 3 205 162 28 109 56 212 165 66 155 60 177 157 +173 194 33 62 57 174 217 83 129 203 212 32 172 69 193 106 116 122 165 3 7 35 +175 9 50 171 179 37 125 5 220 158 198 96 75 38 115 99 50 1 94 62 127 153 45 181 +52 121 175 207 177 24 46 108 164 ^ +499 0 44 4 182 188 53 71 7 148 48 130 108 166 220 35 8 12 198 93 9 63 171 97 +195 194 87 204 14 173 132 203 143 54 231 126 102 125 118 37 43 20 94 60 36 175 +47 90 110 141 23 229 35 184 43 24 153 154 85 173 12 82 214 174 232 117 106 191 +128 77 164 76 117 162 101 25 204 74 142 123 143 234 32 229 211 215 105 31 9 123 +87 88 135 102 65 202 99 50 165 116 62 187 62 67 177 191 8 192 52 196 118 206 +105 91 214 114 27 179 166 100 150 79 79 199 84 13 182 128 137 133 67 57 17 132 +23 53 187 122 36 115 131 152 170 50 45 231 186 18 63 111 181 21 18 179 226 16 +88 19 223 230 82 98 59 161 50 105 200 124 11 207 89 179 106 131 212 139 224 221 +86 164 16 148 224 161 170 226 76 57 10 163 85 113 96 144 38 30 18 119 21 78 148 +164 9 232 50 221 26 12 78 208 80 183 172 141 199 24 44 191 188 46 155 69 208 +140 99 110 81 54 55 42 40 65 26 68 41 105 24 93 185 147 180 157 104 216 89 119 +137 193 219 231 10 223 1 51 36 235 16 28 103 49 1 227 120 61 76 173 72 51 152 +114 87 148 104 40 5 57 77 48 14 229 95 100 34 200 8 132 83 22 178 62 127 93 129 +1 47 30 194 203 83 138 4 186 11 147 120 5 113 40 181 141 139 108 106 15 97 15 +157 220 95 160 186 138 184 223 61 20 27 175 107 6 101 81 114 207 33 33 209 4 66 +73 218 4 6 157 44 11 98 179 46 215 221 146 133 7 88 79 139 168 75 189 37 159 +135 218 180 37 219 51 156 120 181 197 49 5 233 161 110 21 138 64 102 185 87 28 +219 111 125 58 121 52 80 3 82 38 90 170 110 197 169 126 162 41 109 30 134 234 +92 145 149 155 13 62 7 208 200 68 48 21 198 33 40 125 178 6 217 196 2 91 34 24 +213 70 23 113 156 60 212 23 109 150 19 163 25 144 158 151 130 52 20 34 144 98 +235 192 112 112 56 146 13 122 212 199 193 159 79 19 47 146 73 38 150 139 48 190 +77 104 160 126 222 10 47 206 225 29 90 230 26 188 162 34 140 39 194 143 114 147 +64 42 216 149 174 ^ +473 1 75 131 121 18 2 68 161 29 185 203 145 95 40 71 63 113 220 66 8 144 212 +116 115 228 109 59 138 177 108 172 19 82 187 211 188 191 34 36 55 215 11 39 136 +24 223 199 170 52 82 42 131 28 53 162 161 226 142 14 231 97 141 79 192 207 120 +183 236 145 233 198 149 208 48 107 237 173 192 166 77 39 84 102 96 206 40 64 +186 224 227 174 213 10 111 212 23 150 195 9 124 13 6 136 124 65 121 25 117 195 +109 204 218 99 201 44 132 149 215 163 234 230 110 225 62 133 181 176 180 10 18 +9 183 50 22 122 191 41 196 182 163 141 27 32 80 127 8 10 204 132 56 57 130 89 +57 223 54 90 85 227 215 18 154 25 210 115 187 66 108 224 134 209 180 103 176 87 +90 223 147 10 163 89 150 143 87 235 20 69 148 228 202 217 171 39 43 59 190 54 +235 165 149 70 83 29 92 67 233 105 229 130 141 172 112 2 27 118 123 33 160 8 +103 169 210 201 230 17 22 29 33 8 51 9 38 208 55 222 126 166 129 154 211 95 226 +194 174 120 90 78 67 88 25 24 37 76 59 45 212 30 72 84 195 16 1 140 237 28 157 +199 222 167 209 35 68 16 232 25 65 80 220 211 43 111 67 181 228 57 137 11 184 +216 184 78 26 45 119 110 232 177 22 129 68 168 189 74 196 37 128 174 172 205 +205 60 218 58 158 93 218 151 123 171 125 86 10 59 52 134 202 20 214 228 195 102 +44 46 106 71 11 236 93 73 71 156 33 15 211 136 31 100 88 163 182 70 221 232 170 +145 2 120 38 156 178 95 133 36 96 20 155 191 134 116 22 70 76 152 203 52 175 7 +209 128 226 49 94 198 190 13 192 21 235 72 229 37 221 139 205 112 140 185 151 +30 206 47 179 75 217 164 162 154 66 15 66 101 109 7 23 5 115 42 31 186 131 69 +96 113 75 224 41 51 102 3 3 200 157 13 99 56 202 165 56 150 50 167 157 158 179 +23 57 37 169 217 78 119 203 197 17 167 64 193 101 116 122 150 236 7 30 165 4 35 +161 174 27 125 205 153 148 ^ +502 1 89 61 24 101 78 50 213 73 41 127 153 45 167 24 121 168 193 156 3 25 87 +166 28 228 174 188 53 67 239 148 36 118 104 162 208 27 232 4 194 85 1 63 159 97 +191 194 75 196 10 169 132 199 131 50 223 118 94 117 118 37 27 12 94 60 28 171 +47 82 110 137 15 225 23 172 43 12 141 142 81 161 12 74 210 162 228 117 98 187 +124 69 164 76 105 158 101 21 200 70 130 111 143 230 32 221 203 211 101 31 5 123 +83 76 135 90 57 194 95 46 153 112 62 183 54 63 169 179 4 184 40 188 110 194 105 +91 206 102 27 175 154 88 142 71 79 199 84 5 170 128 129 125 55 49 17 120 19 45 +187 114 24 111 123 140 166 38 33 227 178 18 59 99 173 9 10 179 214 12 84 15 215 +218 82 90 47 149 42 93 188 120 239 195 81 171 94 127 200 127 220 217 86 160 16 +144 216 157 162 218 72 45 234 159 77 101 88 132 26 26 6 119 13 70 140 156 233 +220 34 213 26 236 74 200 80 175 164 133 195 24 44 191 184 30 143 57 204 140 99 +106 77 54 43 42 36 61 14 56 25 97 8 81 181 139 180 153 92 212 77 111 133 185 +219 231 238 219 1 43 32 231 8 24 91 33 237 223 108 49 64 165 72 35 152 106 87 +136 96 32 1 53 77 44 238 229 83 96 22 196 124 79 6 166 58 123 93 121 225 43 22 +186 195 71 126 4 174 235 135 120 229 113 28 181 129 135 100 102 7 85 11 145 212 +87 156 186 138 184 223 61 4 11 175 107 6 89 81 114 207 21 17 197 236 54 73 214 +232 234 149 32 11 98 167 34 203 221 146 121 235 88 75 139 160 63 189 29 147 127 +210 172 33 207 51 152 116 169 189 49 237 233 153 102 17 130 64 98 177 79 16 211 +111 113 58 113 48 68 235 78 30 86 170 98 197 169 122 154 41 97 18 126 234 92 +145 145 155 237 50 3 208 200 60 48 21 190 25 40 121 178 238 209 196 230 79 26 +16 201 66 23 105 148 56 208 7 105 138 11 155 17 140 146 151 130 44 8 34 136 86 +227 188 100 112 52 138 1 110 204 187 181 159 67 19 35 142 61 34 146 131 40 178 +65 104 152 126 214 2 39 202 173 ^ +486 1 5 90 230 20 170 144 10 134 39 176 131 108 147 58 36 216 131 35 75 127 109 +2 232 60 149 25 185 195 137 95 32 71 55 105 216 58 234 144 200 108 103 228 105 +47 130 165 100 172 7 78 183 207 184 179 18 36 47 203 237 31 128 8 219 187 162 +44 74 38 131 12 49 162 161 218 142 14 227 89 141 71 180 203 112 175 232 133 221 +198 141 196 36 99 229 173 192 154 69 23 80 98 88 198 24 52 174 216 227 162 213 +2 107 204 11 150 187 235 116 5 236 132 124 53 117 21 113 191 109 192 206 95 201 +28 124 149 215 159 230 218 98 213 54 133 169 172 176 6 10 9 183 38 14 110 187 +37 188 178 163 133 23 28 72 123 8 240 204 128 52 49 118 89 45 215 42 86 85 215 +211 14 154 17 210 115 179 62 108 220 130 209 172 103 176 79 82 211 139 10 155 +85 142 139 83 227 16 69 140 224 202 213 171 35 31 55 178 46 231 161 145 70 83 +29 88 67 225 101 217 126 137 168 104 2 11 106 115 33 160 4 95 157 198 193 222 1 +18 13 21 238 47 5 38 204 55 222 118 162 117 146 211 87 226 190 166 116 78 66 63 +80 25 16 25 68 51 33 212 30 60 76 195 12 239 136 225 28 145 195 210 167 205 27 +56 4 220 13 65 68 220 203 39 103 59 177 220 57 137 241 176 204 180 78 14 37 115 +106 232 177 22 129 68 168 177 74 184 33 116 174 164 201 197 52 218 46 158 89 +214 143 111 159 113 74 236 59 52 122 190 20 214 216 183 90 40 46 106 63 7 224 +85 69 67 152 29 15 199 136 27 100 76 151 182 66 209 224 158 141 240 108 30 156 +174 91 129 24 96 4 147 183 134 112 6 62 64 148 199 40 171 233 201 124 222 45 90 +186 190 239 188 9 235 64 221 29 213 127 205 100 128 177 147 14 206 43 175 63 +205 152 154 142 66 11 54 89 97 241 7 5 111 34 15 178 119 61 92 101 71 224 33 43 +102 233 3 196 153 1 91 56 194 165 48 146 42 159 157 146 167 15 53 21 165 217 74 +111 203 185 5 163 60 193 97 116 122 138 236 7 26 157 23 153 170 184 ^ +505 1 125 238 187 147 165 85 53 16 93 66 50 201 61 29 127 153 45 159 8 121 164 +185 144 235 13 75 166 12 216 166 188 53 63 235 148 24 106 100 158 196 19 220 +240 190 77 237 63 147 97 187 194 63 188 6 165 132 195 119 46 215 110 86 109 118 +37 11 4 94 60 20 167 47 74 110 133 7 221 11 160 43 129 130 77 149 12 66 206 150 +224 117 90 183 120 61 164 76 93 154 101 17 196 66 118 99 143 226 32 213 195 207 +97 31 1 123 79 64 135 78 49 186 91 42 141 108 62 179 46 59 161 167 176 28 180 +102 182 105 91 198 90 27 171 142 76 134 63 79 199 84 241 158 128 121 117 43 41 +17 108 15 37 187 106 12 107 115 128 162 26 21 223 170 18 55 87 165 241 2 179 +202 8 80 11 207 206 82 82 35 137 34 81 176 116 231 183 73 163 82 123 188 115 +216 213 86 156 16 140 208 153 154 210 68 33 222 155 69 89 80 120 14 22 238 119 +5 62 132 148 221 208 18 205 26 224 70 192 80 167 156 125 191 24 44 191 180 14 +131 45 200 140 99 102 73 54 31 42 32 57 2 44 9 89 236 69 177 131 180 149 80 208 +65 103 129 177 219 231 230 215 1 35 28 227 20 79 17 237 219 96 37 52 157 72 19 +152 98 87 124 88 24 241 49 77 40 226 229 71 92 10 192 236 116 75 234 154 54 119 +93 113 213 39 14 178 187 59 114 4 162 223 123 120 217 113 16 181 117 131 92 98 +243 73 7 133 204 79 152 186 138 184 223 61 232 239 175 107 6 77 81 114 207 9 1 +185 232 42 73 210 224 226 141 20 11 98 155 22 191 221 146 109 227 88 71 139 152 +51 189 21 135 119 202 164 29 195 51 148 112 157 181 49 233 233 145 94 13 122 64 +94 169 71 4 203 111 101 58 105 44 56 231 74 22 82 170 86 197 169 118 146 41 85 +6 118 234 92 145 141 155 225 38 243 208 200 52 48 21 182 17 40 117 178 234 201 +196 222 67 18 8 189 62 23 97 140 52 204 235 101 126 3 147 9 136 134 151 130 36 +240 34 128 74 219 184 88 112 48 130 233 98 196 175 169 159 55 19 23 138 49 30 +142 123 32 166 53 104 144 126 206 238 31 198 203 ^ +483 1 235 90 230 16 158 132 240 130 39 164 123 104 147 54 32 216 119 35 75 123 +97 232 224 52 137 21 185 187 129 95 24 71 47 97 212 50 222 144 188 100 91 228 +101 35 122 153 92 172 241 74 179 203 180 167 2 36 39 191 225 23 120 238 215 175 +154 36 66 34 131 242 45 162 161 210 142 14 223 81 141 63 168 199 104 167 228 +121 209 198 133 184 24 91 221 173 192 142 61 7 76 94 80 190 8 40 162 208 227 +150 213 240 103 196 245 150 179 223 108 243 228 128 124 41 113 17 109 187 109 +180 194 91 201 12 116 149 215 155 226 206 86 201 46 133 157 168 172 2 2 9 183 +26 6 98 183 33 180 174 163 125 19 24 64 119 8 232 204 124 48 41 106 89 33 207 +30 82 85 203 207 10 154 9 210 115 171 58 108 216 126 209 164 103 176 71 74 199 +131 10 147 81 134 135 79 219 12 69 132 220 202 209 171 31 19 51 166 38 227 157 +141 70 83 29 84 67 217 97 205 122 133 164 96 2 241 94 107 33 160 87 145 186 185 +214 231 14 243 9 230 43 1 38 200 55 222 110 158 105 138 211 79 226 186 158 112 +66 54 59 72 25 8 13 60 43 21 212 30 48 68 195 8 239 132 213 28 133 191 198 167 +201 19 44 238 208 1 65 56 220 195 35 95 51 173 212 57 137 233 168 192 176 78 2 +29 111 102 232 177 22 129 68 168 165 74 172 29 104 174 156 197 189 44 218 34 +158 85 210 135 99 147 101 62 224 59 52 110 178 20 214 204 171 78 36 46 106 55 3 +212 77 65 63 148 25 15 187 136 23 100 64 139 182 62 197 216 146 137 240 96 22 +156 170 87 125 12 96 234 139 175 134 108 236 54 52 144 195 28 167 221 193 120 +218 41 86 174 190 227 184 243 235 56 213 21 205 115 205 88 116 169 143 244 206 +39 171 51 193 140 146 130 66 7 42 77 85 237 237 5 107 26 245 170 107 53 88 89 +67 224 25 35 102 225 3 192 149 235 83 56 186 165 40 142 34 151 157 134 155 7 49 +5 161 217 70 103 203 173 239 159 56 193 93 116 122 126 236 7 22 149 242 178 ^ +507 1 141 164 7 125 238 175 143 153 81 45 8 85 54 50 189 49 17 127 153 45 151 +240 121 160 177 132 227 1 63 166 244 204 158 188 53 59 231 148 12 94 96 154 184 +11 208 236 186 69 233 63 135 97 183 194 51 180 2 161 132 191 107 42 207 102 78 +101 118 37 243 244 94 60 12 163 47 66 110 129 247 217 247 148 43 236 117 118 73 +137 12 58 202 138 220 117 82 179 116 53 164 76 81 150 101 13 192 62 106 87 143 +222 32 205 187 203 93 31 245 123 75 52 135 66 41 178 87 38 129 104 62 175 38 55 +153 155 244 168 16 172 94 170 105 91 190 78 27 167 130 64 126 55 79 199 84 237 +146 128 113 109 31 33 17 96 11 29 187 98 103 107 116 158 14 9 219 162 18 51 75 +157 233 242 179 190 4 76 7 199 194 82 74 23 125 26 69 164 112 223 171 65 155 70 +119 176 103 212 209 86 152 16 136 200 149 146 202 64 21 210 151 61 77 72 108 2 +18 230 119 245 54 124 140 209 196 2 197 26 212 66 184 80 159 148 117 187 24 44 +191 176 246 119 33 196 140 99 98 69 54 19 42 28 53 238 32 241 81 224 57 173 123 +180 145 68 204 53 95 125 169 219 231 222 211 1 27 24 223 240 16 67 1 237 215 84 +25 40 149 72 3 152 90 87 112 80 16 241 45 77 36 214 229 59 88 246 188 232 108 +71 222 142 50 115 93 105 201 35 6 170 179 47 102 4 150 211 111 120 205 113 4 +181 105 127 84 94 239 61 3 121 196 71 148 186 138 184 223 61 220 227 175 107 6 +65 81 114 207 245 233 173 228 30 73 206 216 218 133 8 11 98 143 10 179 221 146 +97 219 88 67 139 144 39 189 13 123 111 194 156 25 183 51 144 108 145 173 49 229 +233 137 86 9 114 64 90 161 63 240 195 111 89 58 97 40 44 227 70 14 78 170 74 +197 169 114 138 41 73 242 110 234 92 145 137 155 213 26 243 208 200 44 48 21 +174 9 40 113 178 230 193 196 214 55 10 177 58 23 89 132 48 200 223 97 114 243 +139 1 132 122 151 130 28 232 34 120 62 211 180 76 112 44 122 225 86 188 163 157 +159 43 19 11 134 37 26 138 115 24 154 41 104 136 126 198 234 140 ^ +490 1 192 225 223 90 230 12 146 120 228 126 39 152 115 100 147 50 28 216 107 35 +75 119 85 220 216 44 125 17 185 179 121 95 16 71 39 89 208 42 210 144 176 92 79 +228 97 23 114 141 84 172 233 70 175 199 176 155 236 36 31 179 213 15 112 226 +211 163 146 28 58 30 131 230 41 162 161 202 142 14 219 73 141 55 156 195 96 159 +224 109 197 198 125 172 12 83 213 173 192 130 53 241 72 90 72 182 242 28 150 +200 227 138 213 236 99 188 237 150 171 211 100 239 220 124 124 29 109 13 105 +183 109 168 182 87 201 246 108 149 215 151 222 194 74 189 38 133 145 164 168 +248 244 9 183 14 248 86 179 29 172 170 163 117 15 20 56 115 8 224 204 120 44 33 +94 89 21 199 18 78 85 191 203 6 154 1 210 115 163 54 108 212 122 209 156 103 +176 63 66 187 123 10 139 77 126 131 75 211 8 69 124 216 202 205 171 27 7 47 154 +30 223 153 137 70 83 29 80 67 209 93 193 118 129 160 88 2 229 82 99 33 160 246 +79 133 174 177 206 219 10 231 247 222 39 247 38 196 55 222 102 154 93 130 211 +71 226 182 150 108 54 42 55 64 25 1 52 35 9 212 30 36 60 195 4 239 128 201 28 +121 187 186 167 197 11 32 230 196 239 65 44 220 187 31 87 43 169 204 57 137 225 +160 180 172 78 240 21 107 98 232 177 22 129 68 168 153 74 160 25 92 174 148 193 +181 36 218 22 158 81 206 127 87 135 89 50 212 59 52 98 166 20 214 192 159 66 32 +46 106 47 249 200 69 61 59 144 21 15 175 136 19 100 52 127 182 58 185 208 134 +133 240 84 14 156 166 83 121 96 222 131 167 134 104 224 46 40 140 191 16 163 +209 185 116 214 37 82 162 190 215 180 235 235 48 205 13 197 103 205 76 104 161 +139 232 206 35 167 39 181 128 138 118 66 3 30 65 73 233 225 5 103 18 233 162 95 +45 84 77 63 224 17 27 102 217 3 188 145 227 75 56 178 165 32 138 26 143 157 122 +143 249 45 239 157 217 66 95 203 161 231 155 52 193 89 116 122 114 236 7 18 141 +242 249 137 162 3 125 238 69 ^ +514 1 139 141 77 37 77 42 50 177 37 5 127 153 45 143 228 121 156 169 120 219 +241 51 166 232 192 150 188 53 55 227 148 82 92 150 172 3 196 232 182 61 229 63 +123 97 179 194 39 172 250 157 132 187 95 38 199 94 70 93 118 37 231 240 94 60 4 +159 47 58 110 125 243 213 239 136 43 228 105 106 69 125 12 50 198 126 216 117 +74 175 112 45 164 76 69 146 101 9 188 58 94 75 143 218 32 197 179 199 89 31 245 +123 71 40 135 54 33 170 83 34 117 100 62 171 30 51 145 143 244 160 4 164 86 158 +105 91 182 66 27 163 118 52 118 47 79 199 84 233 134 128 105 101 19 25 17 84 7 +21 187 90 240 99 99 104 154 2 249 215 154 18 47 63 149 225 238 179 178 72 3 191 +182 82 66 11 113 18 57 152 108 215 159 57 147 58 115 164 91 208 205 86 148 16 +132 192 145 138 194 60 9 198 147 53 65 64 96 242 14 222 119 241 46 116 132 197 +184 238 189 26 200 62 176 80 151 140 109 183 24 44 191 172 234 107 21 192 140 +99 94 65 54 7 42 24 49 230 20 229 73 212 45 169 115 180 141 56 200 41 87 121 +161 219 231 214 207 1 19 20 219 236 12 55 237 237 211 72 13 28 141 72 239 152 +82 87 100 72 8 241 41 77 32 202 229 47 84 238 184 228 100 67 210 130 46 111 93 +97 189 31 250 162 171 35 90 4 138 199 99 120 193 113 244 181 93 123 76 90 235 +49 251 109 188 63 144 186 138 184 223 61 208 215 175 107 6 53 81 114 207 237 +221 161 224 18 73 202 208 210 125 248 11 98 131 250 167 221 146 85 211 88 63 +139 136 27 189 5 111 103 186 148 21 171 51 140 104 133 165 49 225 233 129 78 5 +106 64 86 153 55 232 187 111 77 58 89 36 32 223 66 6 74 170 62 197 169 110 130 +41 61 234 102 234 92 145 133 155 201 14 243 208 200 36 48 21 166 1 40 109 178 +226 185 196 206 43 2 244 165 54 23 81 124 44 196 211 93 102 239 131 245 128 110 +151 130 20 224 34 112 50 203 176 64 112 40 114 217 74 180 151 145 159 31 19 251 +130 25 22 134 107 16 142 29 104 128 126 190 230 15 190 225 217 90 230 10 140 +114 222 124 39 146 111 217 ^ +510 0 147 46 24 216 95 35 75 115 73 208 208 36 113 13 185 171 113 95 8 71 31 81 +204 34 198 144 164 84 67 228 93 11 106 129 76 172 225 66 171 195 172 143 224 36 +23 167 201 7 104 214 207 151 138 20 50 26 131 218 37 162 161 194 142 14 215 65 +141 47 144 191 88 151 220 97 185 198 117 160 75 205 173 192 118 45 229 68 86 64 +174 230 16 138 192 227 126 213 232 95 180 229 150 163 199 92 235 212 120 124 17 +105 9 101 179 109 156 170 83 201 234 100 149 215 147 218 182 62 177 30 133 133 +160 164 248 240 9 183 2 244 74 175 25 164 166 163 109 11 16 48 111 8 216 204 +116 40 25 82 89 9 191 6 74 85 179 199 2 154 247 210 115 155 50 108 208 118 209 +148 103 176 55 58 175 115 10 131 73 118 127 71 203 4 69 116 212 202 201 171 23 +249 43 142 22 219 149 133 70 83 29 76 67 201 89 181 114 125 156 80 2 217 70 91 +33 160 246 71 121 162 169 198 207 6 219 239 214 35 247 38 192 55 222 94 150 81 +122 211 63 226 178 142 104 42 30 51 56 25 246 243 44 27 251 212 30 24 52 195 +239 124 189 28 109 183 174 167 193 3 20 222 184 231 65 32 220 179 27 79 35 165 +196 57 137 217 152 168 168 78 232 13 103 94 232 177 22 129 68 168 141 74 148 21 +80 174 140 189 173 28 218 10 158 77 202 119 75 123 77 38 200 59 52 86 154 20 +214 180 147 54 28 46 106 39 249 188 61 57 55 140 17 15 163 136 15 100 40 115 +182 54 173 200 122 129 240 72 6 156 162 79 117 242 96 210 123 159 134 100 212 +38 28 136 187 4 159 197 177 112 210 33 78 150 190 203 176 227 235 40 197 5 189 +91 205 64 92 153 135 220 206 31 163 27 169 116 130 106 66 253 18 53 61 229 213 +5 99 10 221 154 83 37 80 65 59 224 9 19 102 209 3 184 141 219 67 56 170 165 24 +134 18 135 157 110 131 245 41 227 153 217 62 87 203 149 223 151 48 193 85 116 +122 102 236 7 14 133 242 241 129 158 249 125 238 157 137 135 75 33 250 73 36 50 +171 31 253 127 153 45 139 222 121 154 165 114 215 237 45 166 226 186 146 188 53 +53 225 148 248 118 ^ +533 0 87 145 157 250 181 227 177 51 224 63 108 97 174 194 24 162 250 152 132 +182 80 33 189 84 60 83 118 37 216 235 94 60 251 154 47 48 110 120 238 208 229 +121 43 218 90 91 64 110 12 40 193 111 211 117 64 170 107 35 164 76 54 141 101 4 +183 53 79 60 143 213 32 187 169 194 84 31 245 123 66 25 135 39 23 160 78 29 102 +95 62 166 20 46 135 128 244 150 246 154 76 143 105 91 172 51 27 158 103 37 108 +37 79 199 84 228 119 128 95 91 4 15 17 69 2 11 187 80 230 94 89 89 149 244 239 +210 144 18 42 48 139 215 233 179 163 252 67 255 181 167 82 56 253 98 8 42 137 +103 205 144 47 137 43 110 149 76 203 200 86 143 16 127 182 140 128 184 55 251 +183 142 43 50 54 81 232 9 212 119 236 36 106 122 182 169 223 179 26 185 57 166 +80 141 130 99 178 24 44 191 167 219 92 6 187 140 99 89 60 54 249 42 19 44 220 5 +214 63 197 30 164 105 180 136 41 195 26 77 116 151 219 231 204 202 1 9 15 214 +231 7 40 222 237 206 57 255 13 131 72 224 152 72 87 85 62 255 241 36 77 27 187 +229 32 79 228 179 223 90 62 195 115 41 106 93 87 174 26 245 152 161 20 75 4 123 +184 84 120 178 113 234 181 78 118 66 85 230 34 251 94 178 53 139 186 138 184 +223 61 193 200 175 107 6 38 81 114 207 227 206 146 219 3 73 197 198 200 115 238 +11 98 116 240 152 221 146 70 201 88 58 139 126 12 189 252 96 93 176 138 16 156 +51 135 99 118 155 49 220 233 119 68 96 64 81 143 45 222 177 111 62 58 79 31 17 +218 61 253 69 170 47 197 169 105 120 41 46 224 92 234 92 145 128 155 186 256 +243 208 200 26 48 21 156 248 40 104 178 221 175 196 196 28 249 239 150 49 23 71 +114 39 191 196 88 87 234 121 240 123 95 151 130 10 214 34 102 35 193 171 49 112 +35 104 207 59 170 136 130 159 16 19 241 125 10 17 129 97 6 127 14 104 118 126 +180 225 5 185 225 202 90 230 5 125 99 207 119 39 131 101 93 147 43 21 216 86 35 +75 112 64 199 202 30 104 10 185 165 107 95 2 71 25 75 201 28 189 144 155 78 58 +228 90 2 100 120 70 172 219 63 168 192 169 134 215 36 17 158 192 1 98 205 137 ^ +522 1 139 130 12 42 22 131 206 33 162 161 186 142 14 211 57 141 39 132 187 80 +143 216 85 173 198 109 148 246 67 197 173 192 106 37 217 64 82 56 166 218 4 126 +184 227 114 213 228 91 172 221 150 155 187 84 231 204 116 124 5 101 5 97 175 +109 144 158 79 201 222 92 149 215 143 214 170 50 165 22 133 121 156 160 248 236 +9 183 248 240 62 171 21 156 162 163 101 7 12 40 107 8 208 204 112 36 17 70 89 +255 183 252 70 85 167 195 256 154 243 210 115 147 46 108 204 114 209 140 103 +176 47 50 163 107 10 123 69 110 123 67 195 69 108 208 202 197 171 19 241 39 130 +14 215 145 129 70 83 29 72 67 193 85 169 110 121 152 72 2 205 58 83 33 160 246 +63 109 150 161 190 195 2 207 231 206 31 247 38 188 55 222 86 146 69 114 211 55 +226 174 134 100 30 18 47 48 25 242 235 36 19 243 212 30 12 44 195 254 239 120 +177 28 97 179 162 167 189 253 8 214 172 223 65 20 220 171 23 71 27 161 188 57 +137 209 144 156 164 78 224 5 99 90 232 177 22 129 68 168 129 74 136 17 68 174 +132 185 165 20 218 256 158 73 198 111 63 111 65 26 188 59 52 74 142 20 214 168 +135 42 24 46 106 31 249 176 53 53 51 136 13 15 151 136 11 100 28 103 182 50 161 +192 110 125 240 60 256 156 158 75 113 234 96 198 115 151 134 96 200 30 16 132 +183 250 155 185 169 108 206 29 74 138 190 191 172 219 235 32 189 255 181 79 205 +52 80 145 131 208 206 27 159 15 157 104 122 94 66 253 6 41 49 225 201 5 95 2 +209 146 71 29 76 53 55 224 1 11 102 201 3 180 137 211 59 56 162 165 16 130 10 +127 157 98 119 241 37 215 149 217 58 79 203 137 215 147 44 193 81 116 122 90 +236 7 10 125 242 233 121 154 245 125 238 145 133 123 71 25 246 65 24 50 159 19 +245 127 153 45 131 210 121 150 157 102 207 229 33 166 214 174 138 188 53 49 221 +148 240 64 86 144 154 249 178 226 176 49 223 63 105 97 173 194 21 160 250 151 +132 181 77 32 187 82 58 81 118 37 213 234 94 60 250 153 47 46 110 119 237 207 +227 118 43 216 87 88 63 107 12 38 192 108 210 117 62 169 106 33 164 76 51 211 ^ +540 0 101 1 180 50 70 51 143 210 32 181 163 191 81 31 245 123 63 16 135 30 17 +154 75 26 93 92 62 163 14 43 129 119 244 144 240 148 70 134 105 91 166 42 27 +155 94 28 102 31 79 199 84 225 110 128 89 85 255 9 17 60 259 5 187 74 224 91 83 +80 146 238 233 207 138 18 39 39 133 209 230 179 154 252 64 255 175 158 82 50 +247 89 2 33 128 100 199 135 41 131 34 107 140 67 200 197 86 140 16 124 176 137 +122 178 52 245 174 139 37 41 48 72 226 6 206 119 233 30 100 116 173 160 214 173 +26 176 54 160 80 135 124 93 175 24 44 191 164 210 83 257 184 140 99 86 57 54 +243 42 16 41 214 256 205 57 188 21 161 99 180 133 32 192 17 71 113 145 219 231 +198 199 1 3 12 211 228 4 31 213 237 203 48 249 4 125 72 215 152 66 87 76 56 252 +241 33 77 24 178 229 23 76 222 176 220 84 59 186 106 38 103 93 81 165 23 242 +146 155 11 66 4 114 175 75 120 169 113 228 181 69 115 60 82 227 25 251 85 172 +47 136 186 138 184 223 61 184 191 175 107 6 29 81 114 207 221 197 137 216 254 +73 194 192 194 109 232 11 98 107 234 143 221 146 61 195 88 55 139 120 3 189 249 +87 87 170 132 13 147 51 132 96 109 149 49 217 233 113 62 257 90 64 78 137 39 +216 171 111 53 58 73 28 8 215 58 250 66 170 38 197 169 102 114 41 37 218 86 234 +92 145 125 155 177 250 243 208 200 20 48 21 150 245 40 101 178 218 169 196 190 +19 246 236 141 46 23 65 108 36 188 187 85 78 231 115 237 120 86 151 130 4 208 +34 96 26 187 168 40 112 32 98 201 50 164 127 121 159 7 19 235 122 1 14 126 91 +118 5 104 112 126 174 222 259 182 225 193 90 230 2 116 90 198 116 39 122 95 90 +147 40 18 216 77 35 75 109 55 190 196 24 95 7 185 159 101 95 256 71 19 69 198 +22 180 144 146 72 49 228 87 253 94 111 64 172 213 60 165 189 166 125 206 36 11 +149 183 255 92 196 201 133 126 8 38 20 131 200 31 162 161 182 142 14 209 53 141 +35 126 185 76 139 214 79 167 198 105 142 242 63 193 173 192 100 33 211 62 80 52 +162 212 258 120 180 227 108 213 226 89 168 217 150 151 181 80 229 200 114 124 +259 99 3 95 173 109 138 152 77 201 129 ^ +555 0 84 149 215 139 210 158 38 153 14 133 109 152 156 248 232 9 183 240 236 50 +167 17 148 158 163 93 3 8 32 103 8 200 204 108 32 9 58 89 247 175 244 66 85 155 +191 256 154 239 210 115 139 42 108 200 110 209 132 103 176 39 42 151 99 10 115 +65 102 119 63 187 258 69 100 204 202 193 171 15 233 35 118 6 211 141 125 70 83 +29 68 67 185 81 157 106 117 148 64 2 193 46 75 33 160 246 55 97 138 153 182 183 +260 195 223 198 27 247 38 184 55 222 78 142 57 106 211 47 226 170 126 96 18 6 +43 40 25 238 227 28 11 235 212 30 36 195 254 239 116 165 28 85 175 150 167 185 +249 258 206 160 215 65 8 220 163 19 63 19 157 180 57 137 201 136 144 160 78 216 +259 95 86 232 177 22 129 68 168 117 74 124 13 56 174 124 181 157 12 218 248 158 +69 194 103 51 99 53 14 176 59 52 62 130 20 214 156 123 30 20 46 106 23 249 164 +45 49 47 132 9 15 139 136 7 100 16 91 182 46 149 184 98 121 240 48 252 156 154 +71 109 226 96 186 107 143 134 92 188 22 4 128 179 242 151 173 161 104 202 25 70 +126 190 179 168 211 235 24 181 251 173 67 205 40 68 137 127 196 206 23 155 3 +145 92 114 82 66 253 256 29 37 221 189 5 91 256 197 138 59 21 72 41 51 224 255 +3 102 193 3 176 133 203 51 56 154 165 8 126 2 119 157 86 107 237 33 203 145 217 +54 71 203 125 207 143 40 193 77 116 122 78 236 7 6 117 242 225 113 150 241 125 +238 133 129 111 67 17 242 57 12 50 147 7 237 127 153 45 123 198 121 146 149 90 +199 221 21 166 202 162 130 188 53 45 217 148 232 52 82 140 142 245 166 222 172 +41 219 63 93 97 169 194 9 152 250 147 132 177 65 28 179 74 50 73 118 37 201 230 +94 60 246 149 47 38 110 115 233 203 219 106 43 208 75 76 59 95 12 30 188 96 206 +117 54 165 102 25 164 76 39 136 101 261 178 48 64 45 143 208 32 177 159 189 79 +31 245 123 61 10 135 24 13 150 73 24 87 90 62 161 10 41 125 113 244 140 236 144 +66 128 105 91 162 36 27 153 88 22 98 27 79 199 84 223 104 128 85 81 251 5 17 54 +259 1 187 70 220 89 79 74 144 234 229 205 134 18 37 33 129 205 228 179 148 252 +62 255 171 152 82 46 243 83 260 27 122 98 195 129 37 127 28 105 134 207 ^ +545 1 196 193 86 136 16 120 168 133 114 170 48 237 162 135 29 29 40 60 218 2 +198 119 229 22 92 108 161 148 202 165 26 164 50 152 80 127 116 85 171 24 44 191 +160 198 71 249 180 140 99 82 53 54 235 42 12 37 206 248 193 49 176 9 157 91 180 +129 20 188 5 63 109 137 219 231 190 195 1 259 8 207 224 19 201 237 199 36 241 +256 117 72 203 152 58 87 64 48 248 241 29 77 20 166 229 11 72 214 172 216 76 55 +174 94 34 99 93 73 153 19 238 138 147 263 54 4 102 163 63 120 157 113 220 181 +57 111 52 78 223 13 251 73 164 39 132 186 138 184 223 61 172 179 175 107 6 17 +81 114 207 213 185 125 212 246 73 190 184 186 101 224 11 98 95 226 131 221 146 +49 187 88 51 139 112 255 189 245 75 79 162 124 9 135 51 128 92 97 141 49 213 +233 105 54 257 82 64 74 129 31 208 163 111 41 58 65 24 260 211 54 246 62 170 26 +197 169 98 106 41 25 210 78 234 92 145 121 155 165 242 243 208 200 12 48 21 142 +241 40 97 178 214 161 196 182 7 242 232 129 42 23 57 100 32 184 175 81 66 227 +107 233 116 74 151 130 260 200 34 88 14 179 164 28 112 28 90 193 38 156 115 109 +159 259 19 227 118 253 10 122 83 256 106 257 104 104 126 166 218 255 178 225 +181 90 230 262 104 78 186 112 39 110 87 86 147 36 14 216 65 35 75 105 43 178 +188 16 83 3 185 151 93 95 252 71 11 61 194 14 168 144 134 64 37 228 83 245 86 +99 56 172 205 56 161 185 162 113 194 36 3 137 171 251 84 184 197 121 118 30 16 +131 188 27 162 161 174 142 14 205 45 141 27 114 181 68 131 210 67 155 198 97 +130 234 55 185 173 192 88 25 199 58 76 44 154 200 250 108 172 227 96 213 222 85 +160 209 150 143 169 72 225 192 110 124 251 95 263 91 169 109 126 140 73 201 204 +80 149 215 137 208 152 32 147 10 133 103 150 154 248 230 9 183 236 234 44 165 +15 144 156 163 89 1 6 28 101 8 196 204 106 30 5 52 89 243 171 240 64 85 149 189 +256 154 237 210 115 135 40 108 198 108 209 128 103 176 35 38 145 95 10 111 63 +98 117 61 183 258 69 96 202 202 191 171 13 229 33 112 2 209 139 123 70 83 29 66 +67 181 79 151 104 115 146 60 2 187 40 71 33 160 246 51 91 132 178 ^ +563 1 174 171 260 183 215 190 23 247 38 180 55 222 70 138 45 98 211 39 226 166 +118 92 6 260 39 32 25 234 219 20 3 227 212 30 254 28 195 254 239 112 153 28 73 +171 138 167 181 245 250 198 148 207 65 262 220 155 15 55 11 153 172 57 137 193 +128 132 156 78 208 255 91 82 232 177 22 129 68 168 105 74 112 9 44 174 116 177 +149 4 218 240 158 65 190 95 39 87 41 2 164 59 52 50 118 20 214 144 111 18 16 46 +106 15 249 152 37 45 43 128 5 15 127 136 3 100 4 79 182 42 137 176 86 117 240 +36 248 156 150 67 105 218 96 174 99 135 134 88 176 14 258 124 175 234 147 161 +153 100 198 21 66 114 190 167 164 203 235 16 173 247 165 55 205 28 56 129 123 +184 206 19 151 257 133 80 106 70 66 253 248 17 25 217 177 5 87 252 185 130 47 +13 68 29 47 224 251 261 102 185 3 172 129 195 43 56 146 165 122 260 111 157 74 +95 233 29 191 141 217 50 63 203 113 199 139 36 193 73 116 122 66 236 7 2 109 +242 217 105 146 237 125 238 121 125 99 63 9 238 49 50 135 261 229 127 153 45 +115 186 121 142 141 78 191 213 9 166 190 150 122 188 53 41 213 148 224 40 78 +136 130 241 154 218 168 33 215 63 81 97 165 194 263 144 250 143 132 173 53 24 +171 66 42 65 118 37 189 226 94 60 242 145 47 30 110 111 229 199 211 94 43 200 +63 64 55 83 12 22 184 84 202 117 46 161 98 17 164 76 27 132 101 261 174 44 52 +33 143 204 32 169 151 185 75 31 245 123 57 264 135 12 5 142 69 20 75 86 62 157 +2 37 117 101 244 132 228 136 58 116 105 91 154 24 27 149 76 10 90 19 79 199 84 +219 92 128 77 73 243 263 17 42 259 259 187 62 212 85 71 62 140 226 221 201 126 +18 33 21 121 197 224 179 136 252 58 255 163 140 82 38 235 71 256 15 110 94 187 +117 29 119 16 101 122 49 194 191 86 134 16 118 164 131 110 166 46 233 156 133 +25 23 36 54 214 194 119 227 18 88 104 155 142 196 161 26 158 48 148 80 123 112 +81 169 24 44 191 158 192 65 245 178 140 99 80 51 54 231 42 10 35 202 244 187 45 +170 3 155 87 180 127 14 186 265 59 107 133 219 231 186 193 1 257 6 205 222 264 +13 195 237 197 30 237 252 113 72 197 152 54 87 58 44 246 241 27 77 18 160 229 5 +70 210 170 214 72 53 168 88 32 97 93 69 261 ^ +563 1 15 234 130 139 255 42 4 90 151 51 120 145 113 212 181 45 107 44 74 219 1 +251 61 156 31 128 186 138 184 223 61 160 167 175 107 6 5 81 114 207 205 173 113 +208 238 73 186 176 178 93 216 11 98 83 218 119 221 146 37 179 88 47 139 104 247 +189 241 63 71 154 116 5 123 51 124 88 85 133 49 209 233 97 46 257 74 64 70 121 +23 200 155 111 29 58 57 20 252 207 50 242 58 170 14 197 169 94 98 41 13 202 70 +234 92 145 117 155 153 234 243 208 200 4 48 21 134 237 40 93 178 210 153 196 +174 263 238 228 117 38 23 49 92 28 180 163 77 54 223 99 229 112 62 151 130 256 +192 34 80 2 171 160 16 112 24 82 185 26 148 103 97 159 251 19 219 114 245 6 118 +75 252 94 249 104 96 126 158 214 251 174 225 169 90 230 262 92 66 174 108 39 98 +79 82 147 32 10 216 53 35 75 101 31 166 180 8 71 267 185 143 85 95 248 71 3 53 +190 6 156 144 122 56 25 228 79 237 78 87 48 172 197 52 157 181 158 101 182 36 +263 125 159 247 76 172 193 109 110 260 22 12 131 176 23 162 161 166 142 14 201 +37 141 19 102 177 60 123 206 55 143 198 89 118 226 47 177 173 192 76 17 187 54 +72 36 146 188 242 96 164 227 84 213 218 81 152 201 150 135 157 64 221 184 106 +124 243 91 263 87 165 109 114 128 69 201 192 72 149 215 133 204 140 20 135 2 +133 91 146 150 248 226 9 183 228 230 32 161 11 136 152 163 81 265 2 20 97 8 188 +204 102 26 265 40 89 235 163 232 60 85 137 185 256 154 233 210 115 127 36 108 +194 104 209 120 103 176 27 30 133 87 10 103 59 90 113 57 175 258 69 88 198 202 +187 171 9 221 29 100 262 205 135 119 70 83 29 62 67 173 75 139 100 111 142 52 2 +175 28 63 33 160 246 43 79 120 141 170 165 260 177 211 186 21 247 38 178 55 222 +66 136 39 94 211 35 226 164 114 90 256 37 28 25 232 215 16 267 223 212 30 250 +24 195 254 239 110 147 28 67 169 132 167 179 243 246 194 142 203 65 258 220 151 +13 51 7 151 168 57 137 189 124 126 154 78 204 253 89 80 232 177 22 129 68 168 +99 74 106 7 38 174 112 175 145 218 236 158 63 188 91 33 81 35 264 158 59 52 44 +112 20 214 138 105 12 14 46 106 11 249 146 33 43 41 126 3 15 121 136 1 100 266 +73 182 40 131 172 80 115 240 30 246 186 ^ +573 0 146 63 101 210 96 162 91 127 134 84 164 6 250 120 171 226 143 149 145 96 +194 17 62 102 190 155 160 195 235 8 165 243 157 43 205 16 44 121 119 172 206 15 +147 249 121 68 98 58 66 253 240 5 13 213 165 5 83 248 173 122 35 5 64 17 43 224 +247 257 102 177 3 168 125 187 35 56 138 165 262 118 256 103 157 62 83 229 25 +179 137 217 46 55 203 101 191 135 32 193 69 116 122 54 236 7 268 101 242 209 97 +142 233 125 238 109 121 87 59 1 234 41 258 50 123 253 221 127 153 45 107 174 +121 138 133 66 183 205 267 166 178 138 114 188 53 37 209 148 216 28 74 132 118 +237 142 214 164 25 211 63 69 97 161 194 255 136 250 139 132 169 41 20 163 58 34 +57 118 37 177 222 94 60 238 141 47 22 110 107 225 195 203 82 43 192 51 52 51 71 +12 14 180 72 198 117 38 157 94 9 164 76 15 128 101 261 170 40 40 21 143 200 32 +161 143 181 71 31 245 123 53 256 135 267 134 65 16 63 82 62 153 264 33 109 89 +244 124 220 128 50 104 105 91 146 12 27 145 64 268 82 11 79 199 84 215 80 128 +69 65 235 259 17 30 259 255 187 54 204 81 63 50 136 218 213 197 118 18 29 9 113 +189 220 179 124 252 54 255 155 128 82 30 227 59 252 3 98 90 179 105 21 111 4 97 +110 37 190 187 86 130 16 114 156 127 102 158 42 225 144 129 17 11 28 42 206 266 +186 119 223 10 80 96 143 130 184 153 26 146 44 140 80 115 104 73 165 24 44 191 +154 180 53 237 174 140 99 76 47 54 223 42 6 31 194 236 175 37 158 261 151 79 +180 123 2 182 257 51 103 125 219 231 178 189 1 253 2 201 218 264 1 183 237 193 +18 229 244 105 72 185 152 46 87 46 36 242 241 23 77 14 148 229 263 66 202 166 +210 64 49 156 76 28 93 93 61 135 13 232 126 135 251 36 4 84 145 45 120 139 113 +208 181 39 105 40 72 217 265 251 55 152 27 126 186 138 184 223 61 154 161 175 +107 6 269 81 114 207 201 167 107 206 234 73 184 172 174 89 212 11 98 77 214 113 +221 146 31 175 88 45 139 100 243 189 239 57 67 150 112 3 117 51 122 86 79 129 +49 207 233 93 42 257 70 64 68 117 19 196 151 111 23 58 53 18 248 205 48 240 56 +170 8 197 169 92 94 41 7 198 66 234 92 145 115 155 147 230 243 208 200 48 21 +130 235 40 91 178 208 149 196 170 259 236 226 111 36 23 45 88 26 178 157 207 ^ +566 1 42 219 91 225 108 50 151 130 252 184 34 72 262 163 156 4 112 20 74 177 14 +140 91 85 159 243 19 211 110 237 2 114 67 248 82 241 104 88 126 150 210 247 170 +225 157 90 230 262 80 54 162 104 39 86 71 78 147 28 6 216 41 35 75 97 19 154 +172 59 267 185 135 77 95 244 71 267 45 186 270 144 144 110 48 13 228 75 229 70 +75 40 172 189 48 153 177 154 89 170 36 259 113 147 243 68 160 189 97 102 256 14 +8 131 164 19 162 161 158 142 14 197 29 141 11 90 173 52 115 202 43 131 198 81 +106 218 39 169 173 192 64 9 175 50 68 28 138 176 234 84 156 227 72 213 214 77 +144 193 150 127 145 56 217 176 102 124 235 87 263 83 161 109 102 116 65 201 180 +64 149 215 129 200 128 8 123 266 133 79 142 146 248 222 9 183 220 226 20 157 7 +128 148 163 73 265 270 12 93 8 180 204 98 22 261 28 89 227 155 224 56 85 125 +181 256 154 229 210 115 119 32 108 190 100 209 112 103 176 19 22 121 79 10 95 +55 82 109 53 167 258 69 80 194 202 183 171 5 213 25 88 258 201 131 115 70 83 29 +58 67 165 71 127 96 107 138 44 2 163 16 55 33 160 246 35 67 108 133 162 153 260 +165 203 178 17 247 38 174 55 222 58 132 27 86 211 27 226 160 106 86 260 248 33 +20 25 228 207 8 263 215 212 30 242 16 195 254 239 106 135 28 55 165 120 167 175 +239 238 186 130 195 65 250 220 143 9 43 271 147 160 57 137 181 116 114 150 78 +196 249 85 76 232 177 22 129 68 168 87 74 94 3 26 174 104 171 137 264 218 228 +158 59 184 83 21 69 23 256 146 59 52 32 100 20 214 126 93 10 46 106 3 249 134 +25 39 37 122 271 15 109 136 269 100 258 61 182 36 119 164 68 111 240 18 242 156 +144 61 99 206 96 156 87 123 134 82 158 2 246 118 169 222 141 143 141 94 192 15 +60 96 190 149 158 191 235 4 161 241 153 37 205 10 38 117 117 166 206 13 145 245 +115 62 94 52 66 253 236 271 7 211 159 5 81 246 167 118 29 1 62 11 41 224 245 +255 102 173 3 166 123 183 31 56 134 165 260 116 254 99 157 56 77 227 23 173 135 +217 44 51 203 95 187 133 30 193 67 116 122 48 236 7 268 97 242 205 93 140 231 +125 238 103 119 81 57 269 232 37 254 50 117 249 217 127 153 45 103 168 121 136 +129 60 179 201 263 166 172 132 110 188 53 35 207 148 212 262 ^ +589 0 70 128 106 233 130 210 160 17 207 63 57 97 157 194 247 128 250 135 132 +165 29 16 155 50 26 49 118 37 165 218 94 60 234 137 47 14 110 103 221 191 195 +70 43 184 39 40 47 59 12 6 176 60 194 117 30 153 90 1 164 76 3 124 101 261 166 +36 28 9 143 196 32 153 135 177 67 31 245 123 49 248 135 262 263 126 61 12 51 78 +62 149 260 29 101 77 244 116 212 120 42 92 105 91 138 27 141 52 260 74 3 79 199 +84 211 68 128 61 57 227 255 17 18 259 251 187 46 196 77 55 38 132 210 205 193 +110 18 25 271 105 181 216 179 112 252 50 255 147 116 82 22 219 47 248 265 86 86 +171 93 13 103 266 93 98 25 186 183 86 126 16 110 148 123 94 150 38 217 132 125 +9 273 20 30 198 266 178 119 219 2 72 88 131 118 172 145 26 134 40 132 80 107 96 +65 161 24 44 191 150 168 41 229 170 140 99 72 43 54 215 42 2 27 186 228 163 29 +146 253 147 71 180 119 264 178 249 43 99 117 219 231 170 185 1 249 272 197 214 +264 263 171 237 189 6 221 236 97 72 173 152 38 87 34 28 238 241 19 77 10 136 +229 255 62 194 162 206 56 45 144 64 24 89 93 53 123 9 228 118 127 243 24 4 72 +133 33 120 127 113 200 181 27 101 32 68 213 257 251 43 144 19 122 186 138 184 +223 61 142 149 175 107 6 261 81 114 207 193 155 95 202 226 73 180 164 166 81 +204 11 98 65 206 101 221 146 19 167 88 41 139 92 235 189 235 45 59 142 104 273 +105 51 118 82 67 121 49 203 233 85 34 257 62 64 64 109 11 188 143 111 11 58 45 +14 240 201 44 236 52 170 270 197 169 88 86 41 269 190 58 234 92 145 111 155 135 +222 243 208 200 266 48 21 122 231 40 87 178 204 141 196 162 251 232 222 99 32 +23 37 80 22 174 145 71 36 217 87 223 106 44 151 130 250 180 34 68 258 159 154 +272 112 18 70 173 8 136 85 79 159 239 19 207 108 233 112 63 246 76 237 104 84 +126 146 208 245 168 225 151 90 230 262 74 48 156 102 39 80 67 76 147 26 4 216 +35 35 75 95 13 148 168 270 53 267 185 131 73 95 242 71 265 41 184 268 138 144 +104 44 7 228 73 225 66 69 36 172 185 46 151 175 152 83 164 36 257 107 141 241 +64 154 187 91 98 254 10 6 131 158 17 162 161 154 142 14 195 25 141 7 84 171 48 +111 200 37 125 198 77 100 214 35 165 173 192 58 5 169 48 66 24 134 170 230 78 +152 227 66 213 212 75 140 189 150 123 139 52 215 172 124 ^ +584 0 124 227 83 263 79 157 109 90 104 61 201 168 56 149 215 125 196 116 272 +111 262 133 67 138 142 248 218 9 183 212 222 8 153 3 120 144 163 65 265 270 4 +89 8 172 204 94 18 257 16 89 219 147 216 52 85 113 177 256 154 225 210 115 111 +28 108 186 96 209 104 103 176 11 14 109 71 10 87 51 74 105 49 159 258 69 72 190 +202 179 171 1 205 21 76 254 197 127 111 70 83 29 54 67 157 67 115 92 103 134 36 +2 151 4 47 33 160 246 27 55 96 125 154 141 260 153 195 170 13 247 38 170 55 222 +50 128 15 78 211 19 226 156 98 82 252 240 29 12 25 224 199 259 207 212 30 234 8 +195 254 239 102 123 28 43 161 108 167 171 235 230 178 118 187 65 242 220 135 5 +35 267 143 152 57 137 173 108 102 146 78 188 245 81 72 232 177 22 129 68 168 75 +74 82 275 14 174 96 167 129 260 218 220 158 55 180 75 9 57 11 248 134 59 52 20 +88 20 214 114 81 264 6 46 106 271 249 122 17 35 33 118 271 15 97 136 269 100 +250 49 182 32 107 156 56 107 240 6 238 156 140 57 95 198 96 144 79 115 134 78 +146 270 238 114 165 214 137 131 133 90 188 11 56 84 190 137 154 183 235 272 153 +237 145 25 205 274 26 109 113 154 206 9 141 237 103 50 86 40 66 253 228 263 271 +207 147 5 77 242 155 110 17 269 58 275 37 224 241 251 102 165 3 162 119 175 23 +56 126 165 256 112 250 91 157 44 65 223 19 161 131 217 40 43 203 83 179 129 26 +193 63 116 122 36 236 7 268 89 242 197 85 136 227 125 238 91 115 69 53 265 228 +29 246 50 105 241 209 127 153 45 95 156 121 132 121 48 171 193 255 166 160 120 +102 188 53 31 203 148 204 10 68 126 100 231 124 208 158 13 205 63 51 97 155 194 +243 124 250 133 132 163 23 14 151 46 22 45 118 37 159 216 94 60 232 135 47 10 +110 101 219 189 191 64 43 180 33 34 45 53 12 2 174 54 192 117 26 151 88 273 164 +76 273 122 101 261 164 34 22 3 143 194 32 149 131 175 65 31 245 123 47 244 135 +258 261 122 59 10 45 76 62 147 258 27 97 71 244 112 208 116 38 86 105 91 134 +270 27 139 46 256 70 275 79 199 84 209 62 128 57 53 223 253 17 12 259 249 187 +42 192 75 51 32 130 206 201 191 106 18 23 267 101 177 214 179 106 252 48 255 +143 110 82 18 215 41 246 261 80 84 167 87 9 99 262 91 92 19 184 181 86 124 16 +108 144 121 90 146 36 213 126 123 5 269 230 ^ +587 0 18 190 266 170 119 215 272 64 80 119 106 160 137 26 122 36 124 80 99 88 +57 157 24 44 191 146 156 29 221 166 140 99 68 39 54 207 42 276 23 178 220 151 +21 134 245 143 63 180 115 256 174 241 35 95 109 219 231 162 181 1 245 272 193 +210 264 255 159 237 185 272 213 228 89 72 161 152 30 87 22 20 234 241 15 77 6 +124 229 247 58 186 158 202 48 41 132 52 20 85 93 45 111 5 224 110 119 235 12 4 +60 121 21 120 115 113 192 181 15 97 24 64 209 249 251 31 136 11 118 186 138 184 +223 61 130 137 175 107 6 253 81 114 207 185 143 83 198 218 73 176 156 158 73 +196 11 98 53 198 89 221 146 7 159 88 37 139 84 227 189 231 33 51 134 96 273 93 +51 114 78 55 113 49 199 233 77 26 257 54 64 60 101 3 180 135 111 277 58 37 10 +232 197 40 232 48 170 262 197 169 84 78 41 261 182 50 234 92 145 107 155 123 +214 243 208 200 262 48 21 114 227 40 83 178 200 133 196 154 243 228 218 87 28 +23 29 72 18 170 133 67 24 213 79 219 102 32 151 130 246 172 34 60 250 151 150 +264 112 14 62 165 274 128 73 67 159 231 19 199 104 225 274 108 55 242 64 229 +104 76 126 138 204 241 164 225 139 90 230 262 62 36 144 98 39 68 59 72 147 22 +216 23 35 75 91 1 136 160 266 41 267 185 123 65 95 238 71 261 33 180 264 126 +144 92 36 273 228 69 217 58 57 28 172 177 42 147 171 148 71 152 36 253 95 129 +237 56 142 183 79 90 250 2 2 131 146 13 162 161 146 142 14 191 17 141 277 72 +167 40 103 196 25 113 198 69 88 206 27 157 173 192 46 275 157 44 62 16 126 158 +222 66 144 227 54 213 208 71 132 181 150 115 127 44 211 164 96 124 223 81 263 +77 155 109 84 98 59 201 162 52 149 215 123 194 110 268 105 260 133 61 136 140 +248 216 9 183 208 220 2 151 1 116 142 163 61 265 270 87 8 168 204 92 16 255 10 +89 215 143 212 50 85 107 175 256 154 223 210 115 107 26 108 184 94 209 100 103 +176 7 10 103 67 10 83 49 70 103 47 155 258 69 68 188 202 177 171 277 201 19 70 +252 195 125 109 70 83 29 52 67 153 65 109 90 101 132 32 2 145 276 43 33 160 246 +23 49 90 121 150 135 260 147 191 166 11 247 38 168 55 222 46 126 9 74 211 15 +226 154 94 80 248 236 27 8 25 222 195 274 257 203 212 30 230 4 195 254 239 100 +117 28 37 159 102 167 169 233 226 174 112 183 65 238 220 131 3 31 270 ^ +609 1 140 146 57 137 167 102 93 143 78 182 242 78 69 232 177 22 129 68 168 66 +74 73 275 5 174 90 164 123 257 218 214 158 52 177 69 48 2 242 125 59 52 11 79 +20 214 105 72 258 3 46 106 268 249 113 11 32 30 115 271 15 88 136 269 100 244 +40 182 29 98 150 47 104 240 276 235 156 137 54 92 192 96 135 73 109 134 75 137 +267 232 111 162 208 134 122 127 87 185 8 53 75 190 128 151 177 235 269 147 234 +139 16 205 268 17 103 110 145 206 6 138 231 94 41 80 31 66 253 222 257 265 204 +138 5 74 239 146 104 8 266 55 269 34 224 238 248 102 159 3 159 116 169 17 56 +120 165 253 109 247 85 157 35 56 220 16 152 128 217 37 37 203 74 173 126 23 193 +60 116 122 27 236 7 268 83 242 191 79 133 224 125 238 82 112 60 50 262 225 23 +240 50 96 235 203 127 153 45 89 147 121 129 115 39 165 187 249 166 151 111 96 +188 53 28 200 148 198 1 65 123 91 228 115 205 155 7 202 63 42 97 152 194 237 +118 250 130 132 160 14 11 145 40 16 39 118 37 150 213 94 60 229 132 47 4 110 98 +216 186 185 55 43 174 24 25 42 44 12 275 171 45 189 117 20 148 85 270 164 76 +267 119 101 261 161 31 13 273 143 191 32 143 125 172 62 31 245 123 44 238 135 +252 258 116 56 7 36 73 62 144 255 24 91 62 244 106 202 110 32 77 105 91 128 264 +27 136 37 250 64 272 79 199 84 206 53 128 51 47 217 250 17 3 259 246 187 36 186 +72 45 23 127 200 195 188 100 18 20 261 95 171 211 179 97 252 45 255 137 101 82 +12 209 32 243 255 71 81 161 78 3 93 256 88 83 10 181 178 86 121 16 105 138 118 +84 140 33 207 117 120 278 263 10 15 188 266 168 119 214 271 62 78 116 103 157 +135 26 119 35 122 80 97 86 55 156 24 44 191 145 153 26 219 165 140 99 67 38 54 +205 42 276 22 176 218 148 19 131 243 142 61 180 114 254 173 239 33 94 107 219 +231 160 180 1 244 272 192 209 264 253 156 237 184 270 211 226 87 72 158 152 28 +87 19 18 233 241 14 77 5 121 229 245 57 184 157 201 46 40 129 49 19 84 93 43 +108 4 223 108 117 233 9 4 57 118 18 120 112 113 190 181 12 96 22 63 208 247 251 +28 134 9 117 186 138 184 223 61 127 134 175 107 6 251 81 114 207 183 140 80 197 +216 73 175 154 156 71 194 11 98 50 196 86 221 146 4 157 88 36 139 82 225 189 +230 30 49 132 94 273 90 51 113 77 52 111 49 198 233 75 24 257 52 64 59 99 1 178 +133 111 275 58 35 9 230 196 39 231 47 170 216 ^ +589 0 197 169 81 72 41 255 176 44 234 92 145 104 155 114 208 243 208 200 259 48 +21 108 224 40 80 178 197 127 196 148 237 225 215 78 25 23 23 66 15 167 124 64 +15 210 73 216 99 23 151 130 243 166 34 54 244 145 147 258 112 11 56 159 268 122 +64 58 159 225 19 193 101 219 274 105 49 239 55 223 104 70 126 132 201 238 161 +225 130 90 230 262 53 27 135 95 39 59 53 69 147 19 278 216 14 35 75 88 273 127 +154 263 32 267 185 117 59 95 235 71 258 27 177 261 117 144 83 30 267 228 66 211 +52 48 22 172 171 39 144 168 145 62 143 36 250 86 120 234 50 133 180 70 84 247 +277 280 131 137 10 162 161 140 142 14 188 11 141 274 63 164 34 97 193 16 104 +198 63 79 200 21 151 173 192 37 272 148 41 59 10 120 149 216 57 138 227 45 213 +205 68 126 175 150 109 118 38 208 158 93 124 217 78 263 74 152 109 75 89 56 201 +153 46 149 215 120 191 101 262 96 257 133 52 133 137 248 213 9 183 202 217 274 +148 279 110 139 163 55 265 270 275 84 8 162 204 89 13 252 1 89 209 137 206 47 +85 98 172 256 154 220 210 115 101 23 108 181 91 209 94 103 176 1 4 94 61 10 77 +46 64 100 44 149 258 69 62 185 202 174 171 277 195 16 61 249 192 122 106 70 83 +29 49 67 147 62 100 87 98 129 26 2 136 270 37 33 160 246 17 40 81 115 144 126 +260 138 185 160 8 247 38 165 55 222 40 123 68 211 9 226 151 88 77 242 230 24 2 +25 219 189 271 254 197 212 30 224 279 195 254 239 97 108 28 28 156 93 167 166 +230 220 168 103 177 65 232 220 125 25 262 138 142 57 137 163 98 87 141 78 178 +240 76 67 232 177 22 129 68 168 60 74 67 275 280 174 86 162 119 255 218 210 158 +50 175 65 275 42 277 238 119 59 52 5 73 20 214 99 66 254 1 46 106 266 249 107 7 +30 28 113 271 15 82 136 269 100 240 34 182 27 92 146 41 102 240 272 233 156 135 +52 90 188 96 129 69 105 134 73 131 265 228 109 160 204 132 116 123 85 183 6 51 +69 190 122 149 173 235 267 143 232 135 10 205 264 11 99 108 139 206 4 136 227 +88 35 76 25 66 253 218 253 261 202 132 5 72 237 140 100 2 264 53 265 32 224 236 +246 102 155 3 157 114 165 13 56 116 165 251 107 245 81 157 29 50 218 14 146 126 +217 35 33 203 68 169 124 21 193 58 116 122 21 236 7 268 79 242 187 75 131 222 +125 238 76 110 54 48 260 223 19 236 50 90 231 199 127 153 45 270 ^ +623 1 135 121 125 107 27 157 179 241 166 139 99 88 188 53 24 196 148 190 272 61 +119 79 224 103 201 151 282 198 63 30 97 148 194 229 110 250 126 132 156 2 7 137 +32 8 31 118 37 138 209 94 60 225 128 47 279 110 94 212 182 177 43 43 166 12 13 +38 32 12 271 167 33 185 117 12 144 81 266 164 76 259 115 101 261 157 27 1 265 +143 187 32 135 117 168 58 31 245 123 40 230 135 244 254 108 52 3 24 69 62 140 +251 20 83 50 244 98 194 102 24 65 105 91 120 256 27 132 25 242 56 268 79 199 84 +202 41 128 43 39 209 246 17 274 259 242 187 28 178 68 37 11 123 192 187 184 92 +18 16 253 87 163 207 179 85 252 41 255 129 89 82 4 201 20 239 247 59 77 153 66 +278 85 248 84 71 281 177 174 86 117 16 101 130 114 76 132 29 199 105 116 274 +255 2 3 180 266 160 119 210 267 54 70 104 91 145 127 26 107 31 114 80 89 78 47 +152 24 44 191 141 141 14 211 161 140 99 63 34 54 197 42 276 18 168 210 136 11 +119 235 138 53 180 110 246 169 231 25 90 99 219 231 152 176 1 240 272 188 205 +264 245 144 237 180 262 203 218 79 72 146 152 20 87 7 10 229 241 10 77 1 109 +229 237 53 176 153 197 38 36 117 37 15 80 93 35 96 219 100 109 225 280 4 45 106 +6 120 100 113 182 181 92 14 59 204 239 251 16 126 1 113 186 138 184 223 61 115 +122 175 107 6 243 81 114 207 175 128 68 193 208 73 171 146 148 63 186 11 98 38 +188 74 221 146 275 149 88 32 139 74 217 189 226 18 41 124 86 273 78 51 109 73 +40 103 49 194 233 67 16 257 44 64 55 91 276 170 125 111 267 58 27 5 222 192 35 +227 43 170 252 197 169 79 68 41 251 172 40 234 92 145 102 155 108 204 243 208 +200 257 48 21 104 222 40 78 178 195 123 196 144 233 223 213 72 23 23 19 62 13 +165 118 62 9 208 69 214 97 17 151 130 241 162 34 50 240 141 145 254 112 9 52 +155 264 118 58 52 159 221 19 189 99 215 274 103 45 237 49 219 104 66 126 128 +199 236 159 225 124 90 230 262 47 21 129 93 39 53 49 67 147 17 278 216 8 35 75 +86 269 121 150 261 26 267 185 113 55 95 233 71 256 23 175 259 111 144 77 26 263 +228 64 207 48 42 18 172 167 37 142 166 143 56 137 36 248 80 114 232 46 127 178 +64 80 245 275 280 131 131 8 162 161 136 142 14 186 7 141 272 57 162 30 93 191 +10 98 198 59 73 196 17 147 173 192 31 270 142 39 57 6 116 143 212 51 134 227 39 +213 203 66 122 171 150 105 112 34 206 154 91 124 213 76 263 72 150 109 69 83 54 +201 147 42 149 202 ^ +602 1 116 187 89 254 84 253 133 40 129 133 248 209 9 183 194 213 266 144 279 +102 135 163 47 265 270 271 80 8 154 204 85 9 248 274 89 201 129 198 43 85 86 +168 256 154 216 210 115 93 19 108 177 87 209 86 103 176 278 281 82 53 10 69 42 +56 96 40 141 258 69 54 181 202 170 171 277 187 12 49 245 188 118 102 70 83 29 +45 67 139 58 88 83 94 125 18 2 124 262 29 33 160 246 9 28 69 107 136 114 260 +126 177 152 4 247 38 161 55 222 32 119 273 60 211 1 226 147 80 73 234 222 20 +279 25 215 181 267 250 189 212 30 216 275 195 254 239 93 96 28 16 152 81 167 +162 226 212 160 91 169 65 224 220 117 281 17 258 134 134 57 137 155 90 75 137 +78 170 236 72 63 232 177 22 129 68 168 48 74 55 275 272 174 78 158 111 251 218 +202 158 46 171 57 267 30 269 230 107 59 52 278 61 20 214 87 54 246 282 46 106 +262 249 95 284 26 24 109 271 15 70 136 269 100 232 22 182 23 80 138 29 98 240 +264 229 156 131 48 86 180 96 117 61 97 134 69 119 261 220 105 156 196 128 104 +115 81 179 2 47 57 190 110 145 165 235 263 135 228 127 283 205 256 284 91 104 +127 206 132 219 76 23 68 13 66 253 210 245 253 198 120 5 68 233 128 92 275 260 +49 257 28 224 232 242 102 147 3 153 110 157 5 56 108 165 247 103 241 73 157 17 +38 214 10 134 122 217 31 25 203 56 161 120 17 193 54 116 122 9 236 7 268 71 242 +179 67 127 218 125 238 64 106 42 44 256 219 11 228 50 78 223 191 127 153 45 77 +129 121 123 103 21 153 175 237 166 133 93 84 188 53 22 194 148 186 268 59 117 +73 222 97 199 149 280 196 63 24 97 146 194 225 106 250 124 132 154 281 5 133 28 +4 27 118 37 132 207 94 60 223 126 47 277 110 92 210 180 173 37 43 162 6 7 36 26 +12 269 165 27 183 117 8 142 79 264 164 76 255 113 101 261 155 25 280 261 143 +185 32 131 113 166 56 31 245 123 38 226 135 240 252 104 50 1 18 67 62 138 249 +18 79 44 244 94 190 98 20 59 105 91 116 252 27 130 19 238 52 266 79 199 84 200 +35 128 39 35 205 244 17 270 259 240 187 24 174 66 33 5 121 188 183 182 88 18 14 +249 83 159 205 179 79 252 39 255 125 83 82 197 14 237 243 53 75 149 60 276 81 +244 82 65 277 175 172 86 115 16 99 126 112 72 128 27 195 99 114 272 251 283 282 +176 266 156 119 208 265 50 66 98 85 139 123 26 101 29 110 80 85 74 43 150 24 44 +191 139 135 8 207 159 140 99 61 248 ^ +609 1 54 189 42 276 14 160 202 124 3 107 227 134 45 180 106 238 165 223 17 86 +91 219 231 144 172 1 236 272 184 201 264 237 132 237 176 254 195 210 71 72 134 +152 12 87 282 2 225 241 6 77 284 97 229 229 49 168 149 193 30 32 105 25 11 76 +93 27 84 283 215 92 101 217 272 4 33 94 281 120 88 113 174 181 275 88 6 55 200 +231 251 4 118 280 109 186 138 184 223 61 103 110 175 107 6 235 81 114 207 167 +116 56 189 200 73 167 138 140 55 178 11 98 26 180 62 221 146 267 141 88 28 139 +66 209 189 222 6 33 116 78 273 66 51 105 69 28 95 49 190 233 59 8 257 36 64 51 +83 272 162 117 111 259 58 19 1 214 188 31 223 39 170 244 197 169 75 60 41 243 +164 32 234 92 145 98 155 96 196 243 208 200 253 48 21 96 218 40 74 178 191 115 +196 136 225 219 209 60 19 23 11 54 9 161 106 58 284 204 61 210 93 5 151 130 237 +154 34 42 232 133 141 246 112 5 44 147 256 110 46 40 159 213 19 181 95 207 274 +99 37 233 37 211 104 58 126 120 195 232 155 225 112 90 230 262 35 9 117 89 39 +41 41 63 147 13 278 216 283 35 75 82 261 109 142 257 14 267 185 105 47 95 229 +71 252 15 171 255 99 144 65 18 255 228 60 199 40 30 10 172 159 33 138 162 139 +44 125 36 244 68 102 228 38 115 174 52 72 241 271 280 131 119 4 162 161 128 142 +14 182 286 141 268 45 158 22 85 187 285 86 198 51 61 188 9 139 173 192 19 266 +130 35 53 285 108 131 204 39 126 227 27 213 199 62 114 163 150 97 100 26 202 +146 87 124 205 72 263 68 146 109 57 71 50 201 135 34 149 215 114 185 83 250 78 +251 133 34 127 131 248 207 9 183 190 211 262 142 279 98 133 163 43 265 270 269 +78 8 150 204 83 7 246 270 89 197 125 194 41 85 80 166 256 154 214 210 115 89 17 +108 175 85 209 82 103 176 276 279 76 49 10 65 40 52 94 38 137 258 69 50 179 202 +168 171 277 183 10 43 243 186 116 100 70 83 29 43 67 135 56 82 81 92 123 14 2 +118 258 25 33 160 246 5 22 63 103 132 108 260 120 173 148 2 247 38 159 55 222 +28 117 269 56 211 284 226 145 76 71 230 218 18 277 25 213 177 265 248 185 212 +30 212 273 195 254 239 91 90 28 10 150 75 167 160 224 208 156 85 165 65 220 220 +113 281 13 256 132 130 57 137 151 86 69 135 78 166 234 70 61 232 177 22 129 68 +168 42 74 49 275 268 174 74 156 107 249 218 198 158 44 169 53 263 24 265 226 +101 59 52 274 55 20 214 81 48 242 282 46 106 260 145 ^ +614 1 83 280 22 20 105 271 15 58 136 269 100 224 10 182 19 68 130 17 94 240 256 +225 156 127 44 82 172 96 105 53 89 134 65 107 257 212 101 152 188 124 92 107 77 +175 287 43 45 190 98 141 157 235 259 127 224 119 275 205 248 276 83 100 115 206 +285 128 211 64 11 60 1 66 253 202 237 245 194 108 5 64 229 116 84 267 256 45 +249 24 224 228 238 102 139 3 149 106 149 286 56 100 165 243 99 237 65 157 5 26 +210 6 122 118 217 27 17 203 44 153 116 13 193 50 116 122 286 236 7 268 63 242 +171 59 123 214 125 238 52 102 30 40 252 215 3 220 50 66 215 183 127 153 45 69 +117 121 119 95 9 145 167 229 166 121 81 76 188 53 18 190 148 178 260 55 113 61 +218 85 195 145 276 192 63 12 97 142 194 217 98 250 120 132 150 273 1 125 20 285 +19 118 37 120 203 94 60 219 122 47 273 110 88 206 176 165 25 43 154 283 284 32 +14 12 265 161 15 179 117 138 75 260 164 76 247 109 101 261 151 21 272 253 143 +181 32 123 105 162 52 31 245 123 34 218 135 232 248 96 46 286 6 63 62 134 245 +14 71 32 244 86 182 90 12 47 105 91 108 244 27 126 7 230 44 262 79 199 84 196 +23 128 31 27 197 240 17 262 259 236 187 16 166 62 25 282 117 180 175 178 80 18 +10 241 75 151 201 179 67 252 35 255 117 71 82 281 189 2 233 235 41 71 141 48 +272 73 236 78 53 269 171 168 86 111 16 95 118 108 64 120 23 187 87 110 268 243 +279 274 168 266 148 119 204 261 42 58 86 73 127 115 26 89 25 102 80 77 66 35 +146 24 44 191 135 123 285 199 155 140 99 57 28 54 185 42 276 12 156 198 118 288 +101 223 132 41 180 104 234 163 219 13 84 87 219 231 140 170 1 234 272 182 199 +264 233 126 237 174 250 191 206 67 72 128 152 8 87 278 287 223 241 4 77 284 91 +229 225 47 164 147 191 26 30 99 19 9 74 93 23 78 283 213 88 97 213 268 4 27 88 +277 120 82 113 170 181 271 86 2 53 198 227 251 287 114 278 107 186 138 184 223 +61 97 104 175 107 6 231 81 114 207 163 110 50 187 196 73 165 134 136 51 174 11 +98 20 176 56 221 146 263 137 88 26 139 62 205 189 220 29 112 74 273 60 51 103 +67 22 91 49 188 233 55 4 257 32 64 49 79 270 158 113 111 255 58 15 288 210 186 +29 221 37 170 240 197 169 73 56 41 239 160 28 234 92 145 96 155 90 192 243 208 +200 251 48 21 92 216 40 72 178 189 111 196 132 221 217 207 54 17 23 7 50 7 159 +100 56 280 202 57 208 91 288 151 130 235 150 34 38 228 129 139 242 112 226 ^ +619 0 38 141 250 104 37 31 159 207 19 175 92 201 274 96 31 230 28 205 104 52 +126 114 192 229 152 225 103 90 230 262 26 108 86 39 32 35 60 147 10 278 216 277 +35 75 79 255 100 136 254 5 267 185 99 41 95 226 71 249 9 168 252 90 144 56 12 +249 228 57 193 34 21 4 172 153 30 135 159 136 35 116 36 241 59 93 225 32 106 +171 43 66 238 268 280 131 110 1 162 161 122 142 14 179 283 141 265 36 155 16 79 +184 279 77 198 45 52 182 3 133 173 192 10 263 121 32 50 282 102 122 198 30 120 +227 18 213 196 59 108 157 150 91 91 20 199 140 84 124 199 69 263 65 143 109 48 +62 47 201 126 28 149 215 111 182 74 244 69 248 133 25 124 128 248 204 9 183 184 +208 256 139 279 92 130 163 37 265 270 266 75 8 144 204 80 4 243 264 89 191 119 +188 38 85 71 163 256 154 211 210 115 83 14 108 172 82 209 76 103 176 273 276 67 +43 10 59 37 46 91 35 131 258 69 44 176 202 165 171 277 177 7 34 240 183 113 97 +70 83 29 40 67 129 53 73 78 89 120 8 2 109 252 19 33 160 246 289 13 54 97 126 +99 260 111 167 142 289 247 38 156 55 222 22 114 263 50 211 281 226 142 70 68 +224 212 15 274 25 210 171 262 245 179 212 30 206 270 195 254 239 88 81 28 1 147 +66 167 157 221 202 150 76 159 65 214 220 107 281 7 253 129 124 57 137 145 80 60 +132 78 160 231 67 58 232 177 22 129 68 168 33 74 40 275 262 174 68 153 101 246 +218 192 158 41 166 47 257 15 259 220 92 59 52 268 46 20 214 72 39 236 282 46 +106 257 249 80 279 21 19 104 271 15 55 136 269 100 222 7 182 18 65 128 14 93 +240 254 224 156 126 43 81 170 96 102 51 87 134 64 104 256 210 100 151 186 123 +89 105 76 174 287 42 42 190 95 140 155 235 258 125 223 117 273 205 246 274 81 +99 112 206 285 127 209 61 8 58 288 66 253 200 235 243 193 105 5 63 228 113 82 +265 255 44 247 23 224 227 237 102 137 3 148 105 147 285 56 98 165 242 98 236 63 +157 2 23 209 5 119 117 217 26 15 203 41 151 115 12 193 49 116 122 284 236 7 268 +61 242 169 57 122 213 125 238 49 101 27 39 251 214 1 218 50 63 213 181 127 153 +45 67 114 121 118 93 6 143 165 227 166 118 78 74 188 53 17 189 148 176 258 54 +112 58 217 82 194 144 275 191 63 9 97 141 194 215 96 250 119 132 149 271 123 18 +284 17 118 37 117 202 94 60 218 121 47 272 110 87 205 175 163 22 43 152 281 282 +31 11 12 264 160 12 178 117 288 137 74 259 164 76 245 108 101 261 150 20 270 +251 143 180 264 ^ +639 0 117 99 159 49 31 245 123 31 212 135 226 245 90 43 286 289 60 62 131 242 +11 65 23 244 80 176 84 6 38 105 91 102 238 27 123 290 224 38 259 79 199 84 193 +14 128 25 21 191 237 17 256 259 233 187 10 160 59 19 276 114 174 169 175 74 18 +7 235 69 145 198 179 58 252 32 255 111 62 82 278 183 285 230 229 32 68 135 39 +269 67 230 75 44 263 168 165 86 108 16 92 112 105 58 114 20 181 78 107 265 237 +276 268 162 266 142 119 201 258 36 52 77 64 118 109 26 80 22 96 80 71 60 29 143 +24 44 191 132 114 279 193 152 140 99 54 25 54 179 42 276 9 150 192 109 285 92 +217 129 35 180 101 228 160 213 7 81 81 219 231 134 167 1 231 272 179 196 264 +227 117 237 171 244 185 200 61 72 119 152 2 87 272 284 220 241 1 77 284 82 229 +219 44 158 144 188 20 27 90 10 6 71 93 17 69 283 210 82 91 207 262 4 18 79 271 +120 73 113 164 181 265 83 288 50 195 221 251 281 108 275 104 186 138 184 223 61 +88 95 175 107 6 225 81 114 207 157 101 41 184 190 73 162 128 130 45 168 11 98 +11 170 47 221 146 257 131 88 23 139 56 199 189 217 283 23 106 68 273 51 51 100 +64 13 85 49 185 233 49 290 257 26 64 46 73 267 152 107 111 249 58 9 288 204 183 +26 218 34 170 234 197 169 70 50 41 233 154 22 234 92 145 93 155 81 186 243 208 +200 248 48 21 86 213 40 69 178 186 105 196 126 215 214 204 45 14 23 1 44 4 156 +91 53 274 199 51 205 88 282 151 130 232 144 34 32 222 123 136 236 112 34 137 +246 100 31 25 159 203 19 171 90 197 274 94 27 228 22 201 104 48 126 110 190 227 +150 225 97 90 230 262 20 286 102 84 39 26 31 58 147 8 278 216 273 35 75 77 251 +94 132 252 291 267 185 95 37 95 224 71 247 5 166 250 84 144 50 8 245 228 55 189 +30 15 172 149 28 133 157 134 29 110 36 239 53 87 223 28 100 169 37 62 236 266 +280 131 104 291 162 161 118 142 14 177 281 141 263 30 153 12 75 182 275 71 198 +41 46 178 291 129 173 192 4 261 115 30 48 280 98 116 194 24 116 227 12 213 194 +57 104 153 150 87 85 16 197 136 82 124 195 67 263 63 141 109 42 56 45 201 120 +24 149 215 109 180 68 240 63 246 133 19 122 126 248 202 9 183 180 206 252 137 +279 88 128 163 33 265 270 264 73 8 140 204 78 2 241 260 89 187 115 184 36 85 65 +161 256 154 209 210 115 79 12 108 170 80 209 72 103 176 271 274 61 39 10 55 35 +42 89 33 127 258 69 40 174 202 163 171 277 173 5 28 238 181 111 95 70 83 29 38 +67 125 51 67 76 87 118 4 2 103 248 15 33 160 246 287 7 48 93 283 ^ +611 0 87 260 99 159 134 289 247 38 152 55 222 14 110 255 42 211 277 226 138 62 +64 216 204 11 270 25 206 163 258 241 171 212 30 198 266 195 254 239 84 69 28 +283 143 54 167 153 217 194 142 64 151 65 206 220 99 281 293 249 125 116 57 137 +137 72 48 128 78 152 227 63 54 232 177 22 129 68 168 21 74 28 275 254 174 60 +149 93 242 218 184 158 37 162 39 249 3 251 212 80 59 52 260 34 20 214 60 27 228 +282 46 106 253 249 68 275 17 15 100 271 15 43 136 269 100 214 289 182 14 53 120 +2 89 240 246 220 156 122 39 77 162 96 90 43 79 134 60 92 252 202 96 147 178 119 +77 97 72 170 287 38 30 190 83 136 147 235 254 117 219 109 265 205 238 266 73 95 +100 206 285 123 201 49 290 50 280 66 253 192 227 235 189 93 5 59 224 101 74 257 +251 40 239 19 224 223 233 102 129 3 144 101 139 281 56 90 165 238 94 232 55 157 +284 11 205 1 107 113 217 22 7 203 29 143 111 8 193 45 116 122 276 236 7 268 53 +242 161 49 118 209 125 238 37 97 15 35 247 210 287 210 50 51 205 173 127 153 45 +59 102 121 114 85 288 135 157 219 166 106 66 66 188 53 13 185 148 168 250 50 +108 46 213 70 190 140 271 187 63 291 97 137 194 207 88 250 115 132 145 263 290 +115 10 280 9 118 37 105 198 94 60 214 117 47 268 110 83 201 171 155 10 43 144 +273 274 27 293 12 260 156 174 117 284 133 70 255 164 76 237 104 101 261 146 16 +262 243 143 176 32 113 95 157 47 31 245 123 29 208 135 222 243 86 41 286 285 58 +62 129 240 9 61 17 244 76 172 80 2 32 105 91 98 234 27 121 286 220 34 257 79 +199 84 191 8 128 21 17 187 235 17 252 259 231 187 6 156 57 15 272 112 170 165 +173 70 18 5 231 65 141 196 179 52 252 30 255 107 56 82 276 179 281 228 225 26 +66 131 33 267 63 226 73 38 259 166 163 86 106 16 90 108 103 54 110 18 177 72 +105 263 233 274 264 158 266 138 119 199 256 32 48 71 58 112 105 26 74 20 92 80 +67 56 25 141 24 44 191 130 108 275 189 150 140 99 52 23 54 175 42 276 7 146 188 +103 283 86 213 127 31 180 99 224 158 209 3 79 77 219 231 130 165 1 229 272 177 +194 264 223 111 237 169 240 181 196 57 72 113 152 292 87 268 282 218 241 293 77 +284 76 229 215 42 154 142 186 16 25 84 4 4 69 93 13 63 283 208 78 87 203 258 4 +12 73 267 120 67 113 160 181 261 81 286 48 193 217 251 277 104 273 102 186 138 +184 223 61 82 89 175 107 6 221 81 114 207 153 95 35 182 186 73 275 ^ +634 0 120 122 37 160 11 98 295 162 35 221 146 249 123 88 19 139 48 191 189 213 +275 15 98 60 273 39 51 96 60 1 77 49 181 233 41 286 257 18 64 42 65 263 144 99 +111 241 58 1 288 196 179 22 214 30 170 226 197 169 66 42 41 225 146 14 234 92 +145 89 155 69 178 243 208 200 244 48 21 78 209 40 65 178 182 97 196 118 207 210 +200 33 10 23 289 36 152 79 49 266 195 43 201 84 274 151 130 228 136 34 24 214 +115 132 228 112 292 26 129 238 92 19 13 159 195 19 163 86 189 274 90 19 224 10 +193 104 40 126 102 186 223 146 225 85 90 230 262 8 278 90 80 39 14 23 54 147 4 +278 216 265 35 75 73 243 82 124 248 283 267 185 87 29 95 220 71 243 293 162 246 +72 144 38 237 228 51 181 22 3 288 172 141 24 129 153 130 17 98 36 235 41 75 219 +20 88 165 25 54 232 262 280 131 92 291 162 161 110 142 14 173 277 141 259 18 +149 4 67 178 267 59 198 33 34 170 287 121 173 192 288 257 103 26 44 276 90 104 +186 12 108 227 213 190 53 96 145 150 79 73 8 193 128 78 124 187 63 263 59 137 +109 30 44 41 201 108 16 149 215 105 176 56 232 51 242 133 7 118 122 248 198 9 +183 172 202 244 133 279 80 124 163 25 265 270 260 69 8 132 204 74 294 237 252 +89 179 107 176 32 85 53 157 256 154 205 210 115 71 8 108 166 76 209 64 103 176 +267 270 49 31 10 47 31 34 85 29 119 258 69 32 170 202 159 171 277 165 1 16 234 +177 107 91 70 83 29 34 67 117 47 55 72 83 114 292 2 91 240 7 33 160 246 283 291 +36 85 114 81 260 93 155 130 289 247 38 150 55 222 10 108 251 38 211 275 226 136 +58 62 212 200 9 268 25 204 159 256 239 167 212 30 194 264 195 254 239 82 63 28 +279 141 48 167 151 215 190 138 58 147 65 202 220 95 281 291 247 123 112 57 137 +133 68 42 126 78 148 225 61 52 232 177 22 129 68 168 15 74 22 275 250 174 56 +147 89 240 218 180 158 35 160 35 245 293 247 208 74 59 52 256 28 20 214 54 21 +224 282 46 106 251 249 62 273 15 13 98 271 15 37 136 269 100 210 285 182 12 47 +116 292 87 240 242 218 156 120 37 75 158 96 84 39 75 134 58 86 250 198 94 145 +174 117 71 93 70 168 287 36 24 190 77 134 143 235 252 113 217 105 261 205 234 +262 69 93 94 206 285 121 197 43 286 46 276 66 253 188 223 231 187 87 5 57 222 +95 70 253 249 38 235 17 224 221 231 102 125 3 142 99 135 279 56 86 165 236 92 +230 51 157 280 5 203 295 101 111 217 20 3 203 23 139 109 6 193 43 116 122 272 +236 7 268 49 242 157 45 116 207 125 238 31 95 9 33 245 220 ^ +638 0 284 204 50 42 199 167 127 153 45 53 93 121 111 79 282 129 151 213 166 97 +57 60 188 53 10 182 148 162 244 47 105 37 210 61 187 137 268 184 63 285 97 134 +194 201 82 250 112 132 142 257 290 109 4 277 3 118 37 96 195 94 60 211 114 47 +265 110 80 198 168 149 1 43 138 267 268 24 287 12 257 153 288 171 117 281 130 +67 252 164 76 231 101 101 261 143 13 256 237 143 173 32 107 89 154 44 31 245 +123 26 202 135 216 240 80 38 286 279 55 62 126 237 6 55 8 244 70 166 74 293 23 +105 91 92 228 27 118 280 214 28 254 79 199 84 188 296 128 15 11 181 232 17 246 +259 228 187 150 54 9 266 109 164 159 170 64 18 2 225 59 135 193 179 43 252 27 +255 101 47 82 273 173 275 225 219 17 63 125 24 264 57 220 70 29 253 163 160 86 +103 16 87 102 100 48 104 15 171 63 102 260 227 271 258 152 266 132 119 196 253 +26 42 62 49 103 99 26 65 17 86 80 61 50 19 138 24 44 191 127 99 269 183 147 140 +99 49 20 54 169 42 276 4 140 182 94 280 77 207 124 25 180 96 218 155 203 294 76 +71 219 231 124 162 1 226 272 174 191 264 217 102 237 166 234 175 190 51 72 104 +152 289 87 262 279 215 241 293 77 284 67 229 209 39 148 139 183 10 22 75 292 1 +66 93 7 54 283 205 72 81 197 252 4 3 64 261 120 58 113 154 181 255 78 283 45 +190 211 251 271 98 270 99 186 138 184 223 61 73 80 175 107 6 215 81 114 207 147 +86 26 179 180 73 157 118 120 35 158 11 98 293 160 32 221 146 247 121 88 18 139 +46 189 189 212 273 13 96 58 273 36 51 95 59 295 75 49 180 233 39 285 257 16 64 +41 63 262 142 97 111 239 58 296 288 194 178 21 213 29 170 224 197 169 65 40 41 +223 144 12 234 92 145 88 155 66 176 243 208 200 243 48 21 76 208 40 64 178 181 +95 196 116 205 209 199 30 9 23 288 34 296 151 76 48 264 194 41 200 83 272 151 +130 227 134 34 22 212 113 131 226 112 292 24 127 236 90 16 10 159 193 19 161 85 +187 274 89 17 223 7 191 104 38 126 100 185 222 145 225 82 90 230 262 5 276 87 +79 39 11 21 53 147 3 278 216 263 35 75 72 241 79 122 247 281 267 185 85 27 95 +219 71 242 292 161 245 69 144 35 295 235 228 50 179 20 287 172 139 23 128 152 +129 14 95 36 234 38 72 218 18 85 164 22 52 231 261 280 131 89 291 162 161 108 +142 14 172 276 141 258 15 148 2 65 177 265 56 198 31 31 168 286 119 173 192 286 +256 100 25 43 275 88 101 184 9 106 227 294 213 189 52 94 143 150 77 70 6 192 +126 77 124 185 62 263 58 136 109 27 41 40 201 105 14 149 215 104 175 53 230 219 +^ +635 1 239 133 297 115 119 248 195 9 183 166 199 238 130 279 74 121 163 19 265 +270 257 66 8 126 204 71 294 234 246 89 173 101 170 29 85 44 154 256 154 202 210 +115 65 5 108 163 73 209 58 103 176 264 267 40 25 10 41 28 28 82 26 113 258 69 +26 167 202 156 171 277 159 297 7 231 174 104 88 70 83 29 31 67 111 44 46 69 80 +111 289 2 82 234 1 33 160 246 280 285 27 79 108 72 260 84 149 124 289 247 38 +147 55 222 4 105 245 32 211 272 226 133 52 59 206 194 6 265 25 201 153 253 236 +161 212 30 188 261 195 254 239 79 54 28 273 138 39 167 148 212 184 132 49 141 +65 196 220 89 281 288 244 120 106 57 137 127 62 33 123 78 142 222 58 49 232 177 +22 129 68 168 6 74 13 275 244 174 50 144 83 237 218 174 158 32 157 29 239 287 +241 202 65 59 52 250 19 20 214 45 12 218 282 46 106 248 249 53 270 12 10 95 271 +15 28 136 269 100 204 279 182 9 38 110 286 84 240 236 215 156 117 34 72 152 96 +75 33 69 134 55 77 247 192 91 142 168 114 62 87 67 165 287 33 15 190 68 131 137 +235 249 107 214 99 255 205 228 256 63 90 85 206 285 118 191 34 280 40 270 66 +253 182 217 225 184 78 5 54 219 86 64 247 246 35 229 14 224 218 228 102 119 3 +139 96 129 276 56 80 165 233 89 227 45 157 274 295 200 295 92 108 217 17 296 +203 14 133 106 3 193 40 116 122 266 236 7 268 43 242 151 39 113 204 125 238 22 +92 30 242 205 282 200 50 36 195 163 127 153 45 49 87 121 109 75 278 125 147 209 +166 91 51 56 188 53 8 180 148 158 240 45 103 31 208 55 185 135 266 182 63 281 +97 132 194 197 78 250 110 132 140 253 290 105 275 298 118 37 90 193 94 60 209 +112 47 263 110 78 196 166 145 294 43 134 263 264 22 283 12 255 151 284 169 117 +279 128 65 250 164 76 227 99 101 261 141 11 252 233 143 171 32 103 85 152 42 31 +245 123 24 198 135 212 238 76 36 286 275 53 62 124 235 4 51 2 244 66 162 70 291 +17 105 91 88 224 27 116 276 210 24 252 79 199 84 186 292 128 11 7 177 230 17 +242 259 226 187 295 146 52 5 262 107 160 155 168 60 18 221 55 131 191 179 37 +252 25 255 97 41 82 271 169 271 223 215 11 61 121 18 262 53 216 68 23 249 161 +158 86 101 16 85 98 98 44 100 13 167 57 100 258 223 269 254 148 266 128 119 194 +251 22 38 56 43 97 95 26 59 15 82 80 57 46 15 136 24 44 191 125 93 265 179 145 +140 99 47 18 54 165 42 276 2 136 178 88 278 71 203 122 21 180 94 214 153 199 +292 74 67 219 231 120 160 1 224 272 172 189 264 213 96 237 164 230 171 186 153 ^ +638 1 72 92 152 285 87 254 275 211 241 293 77 284 55 229 201 35 140 135 179 2 +18 63 284 298 62 93 300 42 283 201 64 73 189 244 4 292 52 253 120 46 113 146 +181 247 74 279 41 186 203 251 263 90 266 95 186 138 184 223 61 61 68 175 107 6 +207 81 114 207 139 74 14 175 172 73 153 110 112 27 150 11 98 285 152 20 221 146 +239 113 88 14 139 38 181 189 208 265 5 88 50 273 24 51 91 55 287 67 49 176 233 +31 281 257 8 64 37 55 258 134 89 111 231 58 292 288 186 174 17 209 25 170 216 +197 169 61 32 41 215 136 4 234 92 145 84 155 54 168 243 208 200 239 48 21 68 +204 40 60 178 177 87 196 108 197 205 195 18 5 23 284 26 296 147 64 44 256 190 +33 196 79 264 151 130 223 126 34 14 204 105 127 218 112 292 16 119 228 82 4 299 +159 185 19 153 81 179 274 85 9 219 296 183 104 30 126 92 181 218 141 225 70 90 +230 262 294 268 75 75 39 300 13 49 147 300 278 216 255 35 75 68 233 67 114 243 +273 267 185 77 19 95 215 71 238 288 157 241 57 144 23 291 227 228 46 171 12 289 +283 172 131 19 124 148 125 2 83 36 230 26 60 214 10 73 160 10 44 227 257 280 +131 77 291 162 161 100 142 14 168 272 141 254 3 144 295 57 173 257 44 198 23 19 +160 282 111 173 192 278 252 88 21 39 271 80 89 176 298 98 227 286 213 185 48 86 +135 150 69 58 299 188 118 73 124 177 58 263 54 132 109 15 29 36 201 93 6 149 +215 100 171 41 222 36 237 133 293 113 117 248 193 9 183 162 197 234 128 279 70 +119 163 15 265 270 255 64 8 122 204 69 294 232 242 89 169 97 166 27 85 38 152 +256 154 200 210 115 61 3 108 161 71 209 54 103 176 262 265 34 21 10 37 26 24 80 +24 109 258 69 22 165 202 154 171 277 155 297 1 229 172 102 86 70 83 29 29 67 +107 42 40 67 78 109 287 2 76 230 298 33 160 246 278 281 21 75 104 66 260 78 145 +120 289 247 38 145 55 222 103 241 28 211 270 226 131 48 57 202 190 4 263 25 199 +149 251 234 157 212 30 184 259 195 254 239 77 48 28 269 136 33 167 146 210 180 +128 43 137 65 192 220 85 281 286 242 118 102 57 137 123 58 27 121 78 138 220 56 +47 232 177 22 129 68 168 74 7 275 240 174 46 142 79 235 218 170 158 30 155 25 +235 283 237 198 59 59 52 246 13 20 214 39 6 214 282 46 106 246 249 47 268 10 8 +93 271 15 22 136 269 100 200 275 182 7 32 106 282 82 240 232 213 156 115 32 70 +148 96 69 29 65 134 53 71 245 188 89 140 164 112 56 83 65 163 287 31 9 190 62 +129 133 235 247 103 212 95 251 205 224 252 59 88 79 206 285 116 187 28 276 263 ^ +640 0 264 66 253 176 211 219 181 69 5 51 216 77 58 241 243 32 223 11 224 215 +225 102 113 3 136 93 123 273 56 74 165 230 86 224 39 157 268 289 197 295 83 105 +217 14 293 203 5 127 103 193 37 116 122 260 236 7 268 37 242 145 33 110 201 125 +238 13 89 293 27 239 202 279 194 50 27 189 157 127 153 45 43 78 121 106 69 272 +119 141 203 166 82 42 50 188 53 5 177 148 152 234 42 100 22 205 46 182 132 263 +179 63 275 97 129 194 191 72 250 107 132 137 247 290 99 296 272 295 118 37 81 +190 94 60 206 109 47 260 110 75 193 163 139 288 43 128 257 258 19 277 12 252 +148 278 166 117 276 125 62 247 164 76 221 96 101 261 138 8 246 227 143 168 32 +97 79 149 39 31 245 123 21 192 135 206 235 70 33 286 269 50 62 121 232 1 45 295 +244 60 156 64 288 8 105 91 82 218 27 113 270 204 18 249 79 199 84 183 286 128 5 +1 171 227 17 236 259 223 187 292 140 49 301 256 104 154 149 165 54 18 299 215 +49 125 188 179 28 252 22 255 91 32 82 268 163 265 220 209 2 58 115 9 259 47 210 +65 14 243 158 155 86 98 16 82 92 95 38 94 10 161 48 97 255 217 266 248 142 266 +122 119 191 248 16 32 47 34 88 89 26 50 12 76 80 51 40 9 133 24 44 191 122 84 +259 173 142 140 99 44 15 54 159 42 276 301 130 172 79 275 62 197 119 15 180 91 +208 150 193 289 71 61 219 231 114 157 1 221 272 169 186 264 207 87 237 161 224 +165 180 41 72 89 152 284 87 252 274 210 241 293 77 284 52 229 199 34 138 134 +178 17 60 282 298 61 93 299 39 283 200 62 71 187 242 4 290 49 251 120 43 113 +144 181 245 73 278 40 185 201 251 261 88 265 94 186 138 184 223 61 58 65 175 +107 6 205 81 114 207 137 71 11 174 170 73 152 108 110 25 148 11 98 283 150 17 +221 146 237 111 88 13 139 36 179 189 207 263 3 86 48 273 21 51 90 54 285 65 49 +175 233 29 280 257 6 64 36 53 257 132 87 111 229 58 291 288 184 173 16 208 24 +170 214 197 169 60 30 41 213 134 2 234 92 145 83 155 51 166 243 208 200 238 48 +21 66 203 40 59 178 176 85 196 106 195 204 194 15 4 23 283 24 296 146 61 43 254 +189 31 195 78 262 151 130 222 124 34 12 202 103 126 216 112 292 14 117 226 80 1 +297 159 183 19 151 80 177 274 84 7 218 294 181 104 28 126 90 180 217 140 225 67 +90 230 262 292 266 72 74 39 298 11 48 147 300 278 216 253 35 75 67 231 64 112 +242 271 267 185 75 17 95 214 71 237 287 156 240 54 144 20 290 225 228 45 169 10 +287 282 172 129 18 123 147 124 301 80 36 229 23 57 213 8 70 159 7 42 226 256 +280 131 213 ^ +640 0 291 162 161 94 142 14 165 269 141 251 298 141 292 51 170 251 35 198 17 10 +154 279 105 173 192 272 249 79 18 36 268 74 80 170 292 92 227 280 213 182 45 80 +129 150 63 49 296 185 112 70 124 171 55 263 51 129 109 6 20 33 201 84 149 215 +97 168 32 216 27 234 133 287 110 114 248 190 9 183 156 194 228 125 279 64 116 +163 9 265 270 252 61 8 116 204 66 294 229 236 89 163 91 160 24 85 29 149 256 +154 197 210 115 55 108 158 68 209 48 103 176 259 262 25 15 10 31 23 18 77 21 +103 258 69 16 162 202 151 171 277 149 297 296 226 169 99 83 70 83 29 26 67 101 +39 31 64 75 106 284 2 67 224 295 33 160 246 275 275 12 69 98 57 260 69 139 114 +289 247 38 142 55 222 298 100 235 22 211 267 226 128 42 54 196 184 1 260 25 196 +143 248 231 151 212 30 178 256 195 254 239 74 39 28 263 133 24 167 143 207 174 +122 34 131 65 186 220 79 281 283 239 115 96 57 137 117 52 18 118 78 132 217 53 +44 232 177 22 129 68 168 295 74 302 275 234 174 40 139 73 232 218 164 158 27 +152 19 229 277 231 192 50 59 52 240 4 20 214 30 301 208 282 46 106 243 249 38 +265 7 5 90 271 15 13 136 269 100 194 269 182 4 23 100 276 79 240 226 210 156 +112 29 67 142 96 60 23 59 134 50 62 242 182 86 137 158 109 47 77 62 160 287 28 +190 53 126 127 235 244 97 209 89 245 205 218 246 53 85 70 206 285 113 181 19 +270 30 260 66 253 172 207 215 179 63 5 49 214 71 54 237 241 30 219 9 224 213 +223 102 109 3 134 91 119 271 56 70 165 228 84 222 35 157 264 285 195 295 77 103 +217 12 291 203 303 123 101 302 193 35 116 122 256 236 7 268 33 242 141 29 108 +199 125 238 7 87 289 25 237 200 277 190 50 21 185 153 127 153 45 39 72 121 104 +65 268 115 137 199 166 76 36 46 188 53 3 175 148 148 230 40 98 16 203 40 180 +130 261 177 63 271 97 127 194 187 68 250 105 132 135 243 290 95 294 270 293 118 +37 75 188 94 60 204 107 47 258 110 73 191 161 135 284 43 124 253 254 17 273 12 +250 146 274 164 117 274 123 60 245 164 76 217 94 101 261 136 6 242 223 143 166 +32 93 75 147 37 31 245 123 19 188 135 202 233 66 31 286 265 48 62 119 230 303 +41 291 244 56 152 60 286 2 105 91 78 214 27 111 266 200 14 247 79 199 84 181 +282 128 1 301 167 225 17 232 259 221 187 290 136 47 299 252 102 150 145 163 50 +18 299 211 45 121 186 179 22 252 20 255 87 26 82 266 159 261 218 205 300 56 111 +3 257 43 206 63 8 239 156 153 86 96 16 80 88 93 34 90 8 157 42 95 253 213 264 +244 138 266 118 119 189 246 79 ^ +650 0 24 35 22 76 81 26 38 8 68 80 43 32 1 129 24 44 191 118 72 251 165 138 140 +99 40 11 54 151 42 276 301 122 164 67 271 50 189 115 7 180 87 200 146 185 285 +67 53 219 231 106 153 1 217 272 165 182 264 199 75 237 157 216 157 172 33 72 77 +152 280 87 244 270 206 241 293 77 284 40 229 191 30 130 130 174 298 13 48 274 +298 57 93 295 27 283 196 54 63 179 234 4 282 37 243 120 31 113 136 181 237 69 +274 36 181 193 251 253 80 261 90 186 138 184 223 61 46 53 175 107 6 197 81 114 +207 129 59 305 170 162 73 148 100 102 17 140 11 98 275 142 5 221 146 229 103 88 +9 139 28 171 189 203 255 301 78 40 273 9 51 86 50 277 57 49 171 233 21 276 257 +304 64 32 45 253 124 79 111 221 58 287 288 176 169 12 204 20 170 206 197 169 56 +22 41 205 126 300 234 92 145 79 155 39 158 243 208 200 234 48 21 58 199 40 55 +178 172 77 196 98 187 200 190 3 23 279 16 296 142 49 39 246 185 23 191 74 254 +151 130 218 116 34 4 194 95 122 208 112 292 6 109 218 72 295 289 159 175 19 143 +76 169 274 80 305 214 286 173 104 20 126 82 176 213 136 225 55 90 230 262 284 +258 60 70 39 290 3 44 147 300 278 216 245 35 75 63 223 52 104 238 263 267 185 +67 9 95 210 71 233 283 152 236 42 144 8 286 217 228 41 161 2 279 278 172 121 14 +119 143 120 293 68 36 225 11 45 209 58 155 301 34 222 252 280 131 62 291 162 +161 90 142 14 163 267 141 249 294 139 290 47 168 247 29 198 13 4 150 277 101 +173 192 268 247 73 16 34 266 70 74 166 288 88 227 276 213 180 43 76 125 150 59 +43 294 183 108 68 124 167 53 263 49 127 109 14 31 201 78 302 149 215 95 166 26 +212 21 232 133 283 108 112 248 188 9 183 152 192 224 123 279 60 114 163 5 265 +270 250 59 8 112 204 64 294 227 232 89 159 87 156 22 85 23 147 256 154 195 210 +115 51 304 108 156 66 209 44 103 176 257 260 19 11 10 27 21 14 75 19 99 258 69 +12 160 202 149 171 277 145 297 292 224 167 97 81 70 83 29 24 67 97 37 25 62 73 +104 282 2 61 220 293 33 160 246 273 271 6 65 94 51 260 63 135 110 289 247 38 +140 55 222 296 98 231 18 211 265 226 126 38 52 192 180 305 258 25 194 139 246 +229 147 212 30 174 254 195 254 239 72 33 28 259 131 18 167 141 205 170 118 28 +127 65 182 220 75 281 281 237 113 92 57 137 113 48 12 116 78 128 215 51 42 232 +177 22 129 68 168 291 74 298 275 230 174 36 137 69 230 218 160 158 25 150 15 +225 273 227 188 44 59 52 236 304 20 214 24 297 204 282 46 106 241 249 32 263 5 +3 88 271 15 7 136 269 100 190 265 182 2 17 96 283 ^ +649 0 76 240 220 207 156 109 26 64 136 96 51 17 53 134 47 53 239 176 83 134 152 +106 38 71 59 157 287 25 298 190 44 123 121 235 241 91 206 83 239 205 212 240 47 +82 61 206 285 110 175 10 264 24 254 66 253 166 201 209 176 54 5 46 211 62 48 +231 238 27 213 6 224 210 220 102 103 3 131 88 113 268 56 64 165 225 81 219 29 +157 258 279 192 295 68 100 217 9 288 203 297 117 98 302 193 32 116 122 250 236 +7 268 27 242 135 23 105 196 125 238 305 84 283 22 234 197 274 184 50 12 179 147 +127 153 45 33 63 121 101 59 262 109 131 193 166 67 27 40 188 53 172 148 142 224 +37 95 7 200 31 177 127 258 174 63 265 97 124 194 181 62 250 102 132 132 237 290 +89 291 267 290 118 37 66 185 94 60 201 104 47 255 110 70 188 158 129 278 43 118 +247 248 14 267 12 247 143 268 161 117 271 120 57 242 164 76 211 91 101 261 133 +3 236 217 143 163 32 87 69 144 34 31 245 123 16 182 135 196 230 60 28 286 259 +45 62 116 227 303 35 285 244 50 146 54 283 300 105 91 72 208 27 108 260 194 8 +244 79 199 84 178 276 128 302 298 161 222 17 226 259 218 187 287 130 44 296 246 +99 144 139 160 44 18 299 205 39 115 183 179 13 252 17 255 81 17 82 263 153 255 +215 199 294 53 105 301 254 37 200 60 306 233 153 150 86 93 16 77 82 90 28 84 5 +151 33 92 250 207 261 238 132 266 112 119 186 243 6 22 32 19 73 79 26 35 7 66 +80 41 30 306 128 24 44 191 117 69 249 163 137 140 99 39 10 54 149 42 276 301 +120 162 64 270 47 187 114 5 180 86 198 145 183 284 66 51 219 231 104 152 1 216 +272 164 181 264 197 72 237 156 214 155 170 31 72 74 152 279 87 242 269 205 241 +293 77 284 37 229 189 29 128 129 173 297 12 45 272 298 56 93 294 24 283 195 52 +61 177 232 4 280 34 241 120 28 113 134 181 235 68 273 35 180 191 251 251 78 260 +89 186 138 184 223 61 43 50 175 107 6 195 81 114 207 127 56 303 169 160 73 147 +98 100 15 138 11 98 273 140 2 221 146 227 101 88 8 139 26 169 189 202 253 300 +76 38 273 6 51 85 49 275 55 49 170 233 19 275 257 303 64 31 43 252 122 77 111 +219 58 286 288 174 168 11 203 19 170 204 197 169 55 20 41 203 124 299 234 92 +145 78 155 36 156 243 208 200 233 48 21 56 198 40 54 178 171 75 196 96 185 199 +189 306 23 278 14 296 141 46 38 244 184 21 190 73 252 151 130 217 114 34 2 192 +93 121 206 112 292 4 107 216 70 293 287 159 173 19 141 75 167 274 79 304 213 +284 171 104 18 126 80 175 212 135 225 52 90 230 262 282 256 57 69 39 288 1 43 +147 300 278 216 243 35 75 62 221 49 102 237 261 267 140 ^ +649 1 61 3 95 207 71 230 280 149 233 33 144 308 283 211 228 38 155 305 273 275 +172 115 11 116 140 117 287 59 36 222 2 36 206 303 49 152 295 28 219 249 280 131 +53 291 162 161 84 142 14 160 264 141 246 288 136 287 41 165 241 20 198 7 304 +144 274 95 173 192 262 244 64 13 31 263 64 65 160 282 82 227 270 213 177 40 70 +119 150 53 34 291 180 102 65 124 161 50 263 46 124 109 300 5 28 201 69 299 149 +215 92 163 17 206 12 229 133 277 105 109 248 185 9 183 146 189 218 120 279 54 +111 163 308 265 270 247 56 8 106 204 61 294 224 226 89 153 81 150 19 85 14 144 +256 154 192 210 115 45 304 108 153 63 209 38 103 176 254 257 10 5 10 21 18 8 72 +16 93 258 69 6 157 202 146 171 277 139 297 286 221 164 94 78 70 83 29 21 67 91 +34 16 59 70 101 279 2 52 214 290 33 160 246 270 265 306 59 88 42 260 54 129 104 +289 247 38 137 55 222 293 95 225 12 211 262 226 123 32 49 186 174 305 255 25 +191 133 243 226 141 212 30 168 251 195 254 239 69 24 28 253 128 9 167 138 202 +164 112 19 121 65 176 220 69 281 278 234 110 86 57 137 107 42 3 113 78 122 212 +48 39 232 177 22 129 68 168 285 74 292 275 224 174 30 134 63 227 218 154 158 22 +147 9 219 267 221 182 35 59 52 230 298 20 214 15 291 198 282 46 106 238 249 23 +260 2 85 271 15 307 136 269 100 184 259 182 308 8 90 266 74 240 216 205 156 107 +24 62 132 96 45 13 49 134 45 47 237 172 81 132 148 104 32 67 57 155 287 23 294 +190 38 121 117 235 239 87 204 79 235 205 208 236 43 80 55 206 285 108 171 4 260 +20 250 66 253 162 197 205 174 48 5 44 209 56 44 227 236 25 209 4 224 208 218 +102 99 3 129 86 109 266 56 60 165 223 79 217 25 157 254 275 190 295 62 98 217 7 +286 203 293 113 96 302 193 30 116 122 246 236 7 268 23 242 131 19 103 194 125 +238 301 82 279 20 232 195 272 180 50 6 175 143 127 153 45 29 57 121 99 55 258 +105 127 189 166 61 21 36 188 53 307 170 148 138 220 35 93 1 198 25 175 125 256 +172 63 261 97 122 194 177 58 250 100 132 130 233 290 85 289 265 288 118 37 60 +183 94 60 199 102 47 253 110 68 186 156 125 274 43 114 243 244 12 263 12 245 +141 264 159 117 269 118 55 240 164 76 207 89 101 261 131 1 232 213 143 161 32 +83 65 142 32 31 245 123 14 178 135 192 228 56 26 286 255 43 62 114 225 303 31 +281 244 46 142 50 281 296 105 91 68 204 27 106 256 190 4 242 79 199 84 176 272 +128 300 296 157 220 17 222 259 216 187 285 126 42 294 242 97 140 135 158 40 18 +299 201 35 111 181 179 7 252 15 255 77 11 82 261 149 251 69 ^ +655 0 191 286 49 97 293 250 29 192 56 298 225 149 146 86 89 16 73 74 86 20 76 1 +143 21 88 246 199 257 230 124 266 104 119 182 239 309 14 20 7 61 71 26 23 3 58 +80 33 22 302 124 24 44 191 113 57 241 155 133 140 99 35 6 54 141 42 276 301 112 +154 52 266 35 179 110 308 180 82 190 141 175 280 62 43 219 231 96 148 1 212 272 +160 177 264 189 60 237 152 206 147 162 23 72 62 152 275 87 234 265 201 241 293 +77 284 25 229 181 25 120 125 169 293 8 33 264 298 52 93 290 12 283 191 44 53 +169 224 4 272 22 233 120 16 113 126 181 227 64 269 31 176 183 251 243 70 256 85 +186 138 184 223 61 31 38 175 107 6 187 81 114 207 119 44 295 165 152 73 143 90 +92 7 130 11 98 265 132 301 221 146 219 93 88 4 139 18 161 189 198 245 296 68 30 +273 305 51 81 45 267 47 49 166 233 11 271 257 299 64 27 35 248 114 69 111 211 +58 282 288 166 164 7 199 15 170 196 197 169 51 12 41 195 116 295 234 92 145 74 +155 24 148 243 208 200 229 48 21 48 194 40 50 178 167 67 196 88 177 195 185 299 +306 23 274 6 296 137 34 34 236 180 13 186 69 244 151 130 213 106 34 305 184 85 +117 198 112 292 307 99 208 62 285 279 159 165 19 133 71 159 274 75 300 209 276 +163 104 10 126 72 171 208 131 225 40 90 230 262 274 248 45 65 39 280 304 39 147 +300 278 216 235 35 75 58 213 37 94 233 253 267 185 57 310 95 205 71 228 278 147 +231 27 144 304 281 207 228 36 151 303 269 273 172 111 9 114 138 115 283 53 36 +220 307 30 204 301 43 150 291 24 217 247 280 131 47 291 162 161 80 142 14 158 +262 141 244 284 134 285 37 163 237 14 198 3 300 140 272 91 173 192 258 242 58 +11 29 261 60 59 156 278 78 227 266 213 175 38 66 115 150 49 28 289 178 98 63 +124 157 48 263 44 122 109 296 310 26 201 63 297 149 215 90 161 11 202 6 227 133 +273 103 107 248 183 9 183 142 187 214 118 279 50 109 163 306 265 270 245 54 8 +102 204 59 294 222 222 89 149 77 146 17 85 8 142 256 154 190 210 115 41 304 108 +151 61 209 34 103 176 252 255 4 1 10 17 16 4 70 14 89 258 69 2 155 202 144 171 +277 135 297 282 219 162 92 76 70 83 29 19 67 87 32 10 57 68 99 277 2 46 210 288 +33 160 246 268 261 302 55 84 36 260 48 125 100 289 247 38 135 55 222 291 93 221 +8 211 260 226 121 28 47 182 170 305 253 25 189 129 241 224 137 212 30 164 249 +195 254 239 67 18 28 249 126 3 167 136 200 160 108 13 117 65 172 220 65 281 276 +232 108 82 57 137 103 38 308 111 78 118 210 46 37 232 177 22 129 68 168 281 74 +288 275 220 174 26 132 59 225 218 150 158 20 145 5 215 263 100 ^ +661 1 176 26 59 52 224 292 20 214 6 285 192 282 46 106 235 249 14 257 311 309 +82 271 15 301 136 269 100 178 253 182 308 311 84 260 71 240 210 202 156 104 21 +59 126 96 36 7 43 134 42 38 234 166 78 129 142 101 23 61 54 152 287 20 288 190 +29 118 111 235 236 81 201 73 229 205 202 230 37 77 46 206 285 105 165 307 254 +14 244 66 253 156 191 199 171 39 5 41 206 47 38 221 233 22 203 1 224 205 215 +102 93 3 126 83 103 263 56 54 165 220 76 214 19 157 248 269 187 295 53 95 217 4 +283 203 287 107 93 302 193 27 116 122 240 236 7 268 17 242 125 13 100 191 125 +238 295 79 273 17 229 192 269 174 50 309 169 137 127 153 45 23 48 121 96 49 252 +99 121 183 166 52 12 30 188 53 307 167 148 132 214 32 90 304 195 16 172 122 253 +169 63 255 97 119 194 171 52 250 97 132 127 227 290 79 286 262 285 118 37 51 +180 94 60 196 99 47 250 110 65 183 153 119 268 43 108 237 238 9 257 12 242 138 +258 156 117 266 115 52 237 164 76 201 86 101 261 128 310 226 207 143 158 32 77 +59 139 29 31 245 123 11 172 135 186 225 50 23 286 249 40 62 111 222 303 25 275 +244 40 136 44 278 290 105 91 62 198 27 103 250 184 310 239 79 199 84 173 266 +128 297 293 151 217 17 216 259 213 187 282 120 39 291 236 94 134 129 155 34 18 +299 195 29 105 178 179 310 252 12 255 71 2 82 258 143 245 210 189 284 48 95 291 +249 27 190 55 296 223 148 145 86 88 16 72 72 85 18 74 141 18 87 245 197 256 228 +122 266 102 119 181 238 308 12 17 4 58 69 26 20 2 56 80 31 20 301 123 24 44 191 +112 54 239 153 132 140 99 34 5 54 139 42 276 301 110 152 49 265 32 177 109 307 +180 81 188 140 173 279 61 41 219 231 94 147 1 211 272 159 176 264 187 57 237 +151 204 145 160 21 72 59 152 274 87 232 264 200 241 293 77 284 22 229 179 24 +118 124 168 292 7 30 262 298 51 93 289 9 283 190 42 51 167 222 4 270 19 231 120 +13 113 124 181 225 63 268 30 175 181 251 241 68 255 84 186 138 184 223 61 28 35 +175 107 6 185 81 114 207 117 41 293 164 150 73 142 88 90 5 128 11 98 263 130 +299 221 146 217 91 88 3 139 16 159 189 197 243 295 66 28 273 303 51 80 44 265 +45 49 165 233 9 270 257 298 64 26 33 247 112 67 111 209 58 281 288 164 163 6 +198 14 170 194 197 169 50 10 41 193 114 294 234 92 145 73 155 21 146 243 208 +200 228 48 21 46 193 40 49 178 166 65 196 86 175 194 184 297 306 23 273 4 296 +136 31 33 234 179 11 185 68 242 151 130 212 104 34 304 182 83 116 196 112 292 +306 97 206 60 283 277 159 163 19 131 70 157 274 74 299 208 274 161 104 8 126 70 +170 207 130 225 37 90 230 194 ^ +643 0 268 242 36 62 39 274 301 36 147 300 278 216 229 35 75 55 207 28 88 230 +247 267 185 51 307 95 202 71 225 275 144 228 18 144 298 278 201 228 33 145 300 +263 270 172 105 6 111 135 112 277 44 36 217 301 21 201 298 34 147 285 18 214 +244 280 131 38 291 162 161 74 142 14 155 259 141 241 278 131 282 31 160 231 5 +198 311 294 134 269 85 173 192 252 239 49 8 26 258 54 50 150 272 72 227 260 213 +172 35 60 109 150 43 19 286 175 92 60 124 151 45 263 41 119 109 290 304 23 201 +54 294 149 215 87 158 2 196 311 224 133 267 100 104 248 180 9 183 136 184 208 +115 279 44 106 163 303 265 270 242 51 8 96 204 56 294 219 216 89 143 71 140 14 +85 313 139 256 154 187 210 115 35 304 108 148 58 209 28 103 176 249 252 309 309 +10 11 13 312 67 11 83 258 69 310 152 202 141 171 277 129 297 276 216 159 89 73 +70 83 29 16 67 81 29 1 54 65 96 274 2 37 204 285 33 160 246 265 255 296 49 78 +27 260 39 119 94 289 247 38 132 55 222 288 90 215 2 211 257 226 118 22 44 176 +164 305 250 25 186 123 238 221 131 212 30 158 246 195 254 239 64 9 28 243 123 +308 167 133 197 154 102 4 111 65 166 220 59 281 273 229 105 76 57 137 97 32 302 +108 78 112 207 43 34 232 177 22 129 68 168 275 74 282 275 214 174 20 129 53 222 +218 144 158 17 142 313 209 257 211 172 20 59 52 220 288 20 214 281 188 282 46 +106 233 249 8 255 311 309 80 271 15 297 136 269 100 174 249 182 308 307 80 256 +69 240 206 200 156 102 19 57 122 96 30 3 39 134 40 32 232 162 76 127 138 99 17 +57 52 150 287 18 284 190 23 116 107 235 234 77 199 69 225 205 198 226 33 75 40 +206 285 103 161 303 250 10 240 66 253 152 187 195 169 33 5 39 204 41 34 217 231 +20 199 313 224 203 213 102 89 3 124 81 99 261 56 50 165 218 74 212 15 157 244 +265 185 295 47 93 217 2 281 203 283 103 91 302 193 25 116 122 236 236 7 268 13 +242 121 9 98 189 125 238 291 77 269 15 227 190 267 170 50 305 165 133 127 153 +45 19 42 121 94 45 248 95 117 179 166 46 6 26 188 53 307 165 148 128 210 30 88 +300 193 10 170 120 251 167 63 251 97 117 194 167 48 250 95 132 125 223 290 75 +284 260 283 118 37 45 178 94 60 194 97 47 248 110 63 181 151 115 264 43 104 233 +234 7 253 12 240 136 254 154 117 264 113 50 235 164 76 197 84 101 261 126 310 +222 203 143 156 32 73 55 137 27 31 245 123 9 168 135 182 223 46 21 286 245 38 +62 109 220 303 21 271 244 36 132 40 276 286 105 91 58 194 27 101 246 180 308 +237 79 199 84 171 262 128 295 291 147 215 17 212 259 219 ^ +652 1 187 278 112 35 287 228 90 126 121 151 26 18 299 187 21 97 174 179 302 252 +8 255 63 306 82 254 135 237 206 181 276 44 87 283 245 19 182 51 288 215 144 141 +86 84 16 68 64 81 10 66 312 133 6 83 241 189 252 220 114 266 94 119 177 234 304 +4 5 308 46 61 26 8 314 48 80 23 12 297 119 24 44 191 108 42 231 145 128 140 99 +30 1 54 131 42 276 301 102 144 37 261 20 169 105 303 180 77 180 136 165 275 57 +33 219 231 86 143 1 207 272 155 172 264 179 45 237 147 196 137 152 13 72 47 152 +270 87 224 260 196 241 293 77 284 10 229 171 20 110 120 164 288 3 18 254 298 47 +93 285 313 283 186 34 43 159 214 4 262 7 223 120 1 113 116 181 217 59 264 26 +171 173 251 233 60 251 80 186 138 184 223 61 16 23 175 107 6 177 81 114 207 109 +29 285 160 142 73 138 80 82 313 120 11 98 255 122 291 221 146 209 83 88 315 139 +8 151 189 193 235 291 58 20 273 295 51 76 40 257 37 49 161 233 1 266 257 294 64 +22 25 243 104 59 111 201 58 277 288 156 159 2 194 10 170 186 197 169 46 2 41 +185 106 290 234 92 145 69 155 9 138 243 208 200 224 48 21 38 189 40 45 178 162 +57 196 78 167 190 180 289 306 23 269 312 296 132 19 29 226 175 3 181 64 234 151 +130 208 96 34 300 174 75 112 188 112 292 302 89 198 52 275 269 159 155 19 123 +66 149 274 70 295 204 266 153 104 126 62 166 203 126 225 25 90 230 262 264 238 +30 60 39 270 299 34 147 300 278 216 225 35 75 53 203 22 84 228 243 267 185 47 +305 95 200 71 223 273 142 226 12 144 294 276 197 228 31 141 298 259 268 172 101 +4 109 133 110 273 38 36 215 297 15 199 296 28 145 281 14 212 242 280 131 32 291 +162 161 70 142 14 153 257 141 239 274 129 280 27 158 227 315 198 309 290 130 +267 81 173 192 248 237 43 6 24 256 50 44 146 268 68 227 256 213 170 33 56 105 +150 39 13 284 173 88 58 124 147 43 263 39 117 109 286 300 21 201 48 292 149 215 +85 156 312 192 307 222 133 263 98 102 248 178 9 183 132 182 204 113 279 40 104 +163 301 265 270 240 49 8 92 204 54 294 217 212 89 139 67 136 12 85 309 137 256 +154 185 210 115 31 304 108 146 56 209 24 103 176 247 250 305 307 10 7 11 310 65 +9 79 258 69 308 150 202 139 171 277 125 297 272 214 157 87 71 70 83 29 14 67 77 +27 311 52 63 94 272 2 31 200 283 33 160 246 263 251 292 45 74 21 260 33 115 90 +289 247 38 130 55 222 286 88 211 314 211 255 226 116 18 42 172 160 305 248 25 +184 119 236 219 127 212 30 154 244 195 254 239 62 3 28 239 121 304 167 131 195 +150 98 314 107 65 162 220 55 281 271 227 103 72 57 137 93 28 308 ^ +670 0 105 78 106 204 40 31 232 177 22 129 68 168 269 74 276 275 208 174 14 126 +47 219 218 138 158 14 139 310 203 251 205 166 11 59 52 214 282 20 214 308 275 +182 282 46 106 230 249 316 252 311 309 77 271 15 291 136 269 100 168 243 182 +308 301 74 250 66 240 200 197 156 99 16 54 116 96 21 314 33 134 37 23 229 156 +73 124 132 96 8 51 49 147 287 15 278 190 14 113 101 235 231 71 196 63 219 205 +192 220 27 72 31 206 285 100 155 297 244 4 234 66 253 146 181 189 166 24 5 36 +201 32 28 211 228 17 193 313 224 200 210 102 83 3 121 78 93 258 56 44 165 215 +71 209 9 157 238 259 182 295 38 90 217 316 278 203 277 97 88 302 193 22 116 122 +230 236 7 268 7 242 115 3 95 186 125 238 285 74 263 12 224 187 264 164 50 299 +159 127 127 153 45 13 33 121 91 39 242 89 111 173 166 37 314 20 188 53 307 162 +148 122 204 27 85 294 190 1 167 117 248 164 63 245 97 114 194 161 42 250 92 132 +122 217 290 69 281 257 280 118 37 36 175 94 60 191 94 47 245 110 60 178 148 109 +258 43 98 227 228 4 247 12 237 133 248 151 117 261 110 47 232 164 76 191 81 101 +261 123 310 216 197 143 153 32 67 49 134 24 31 245 123 6 162 135 176 220 40 18 +286 239 35 62 106 217 303 15 265 244 30 126 34 273 280 105 91 52 188 27 98 240 +174 305 234 79 199 84 168 256 128 292 288 141 212 17 206 259 208 187 277 110 34 +286 226 89 124 119 150 24 18 299 185 19 95 173 179 300 252 7 255 61 304 82 253 +133 235 205 179 274 43 85 281 244 17 180 50 286 213 143 140 86 83 16 67 62 80 8 +64 312 131 3 82 240 187 251 218 112 266 92 119 176 233 303 2 2 306 43 59 26 5 +314 46 80 21 10 296 118 24 44 191 107 39 229 143 127 140 99 29 54 129 42 276 +301 100 142 34 260 17 167 104 302 180 76 178 135 163 274 56 31 219 231 84 142 1 +206 272 154 171 264 177 42 237 146 194 135 150 11 72 44 152 269 87 222 259 195 +241 293 77 284 7 229 169 19 108 119 163 287 2 15 252 298 46 93 284 311 283 185 +32 41 157 212 4 260 4 221 120 315 113 114 181 215 58 263 25 170 171 251 231 58 +250 79 186 138 184 223 61 13 20 175 107 6 175 81 114 207 107 26 283 159 140 73 +137 78 80 312 118 11 98 253 120 289 221 146 207 81 88 315 139 6 149 189 192 233 +290 56 18 273 293 51 75 39 255 35 49 160 233 316 265 257 293 64 21 23 242 102 +57 111 199 58 276 288 154 158 1 193 9 170 184 197 169 45 41 183 104 289 234 92 +145 68 155 6 136 243 208 200 223 48 21 36 188 40 44 178 161 55 196 76 165 189 +179 287 306 23 268 311 296 131 16 28 224 174 1 180 63 232 151 130 207 94 34 299 +172 73 111 186 112 292 301 87 196 50 273 267 159 153 235 ^ +658 1 117 63 143 274 67 292 201 260 147 104 313 126 56 163 200 123 225 16 90 +230 262 258 232 21 57 39 264 296 31 147 300 278 216 219 35 75 50 197 13 78 225 +237 267 185 41 302 95 197 71 220 270 139 223 3 144 288 273 191 228 28 135 295 +253 265 172 95 1 106 130 107 267 29 36 212 291 6 196 293 19 142 275 8 209 239 +280 131 23 291 162 161 64 142 14 150 254 141 236 268 126 277 21 155 221 309 198 +306 284 124 264 75 173 192 242 234 34 3 21 253 44 35 140 262 62 227 250 213 167 +30 50 99 150 33 4 281 170 82 55 124 141 40 263 36 114 109 280 294 18 201 39 289 +149 215 82 153 306 186 301 219 133 257 95 99 248 175 9 183 126 179 198 110 279 +34 101 163 298 265 270 237 46 8 86 204 51 294 214 206 89 133 61 130 9 85 303 +134 256 154 182 210 115 25 304 108 143 53 209 18 103 176 244 247 299 304 10 1 8 +307 62 6 73 258 69 305 147 202 136 171 277 119 297 266 211 154 84 68 70 83 29 +11 67 71 24 305 49 60 91 269 2 22 194 280 33 160 246 260 245 286 39 68 12 260 +24 109 84 289 247 38 127 55 222 283 85 205 311 211 252 226 113 12 39 166 154 +305 245 25 181 113 233 216 121 212 30 148 241 195 254 239 59 313 28 233 118 298 +167 128 192 144 92 308 101 65 156 220 49 281 268 224 100 66 57 137 87 22 292 +103 78 102 202 38 29 232 177 22 129 68 168 265 74 272 275 204 174 10 124 43 217 +218 134 158 12 137 308 199 247 201 162 5 59 52 210 278 20 214 304 271 178 282 +46 106 228 249 312 250 311 309 75 271 15 287 136 269 100 164 239 182 308 297 70 +246 64 240 196 195 156 97 14 52 112 96 15 312 29 134 35 17 227 152 71 122 128 +94 2 47 47 145 287 13 274 190 8 111 97 235 229 67 194 59 215 205 188 216 23 70 +25 206 285 98 151 293 240 230 66 253 142 177 185 164 18 5 34 199 26 24 207 226 +15 189 313 224 198 208 102 79 3 119 76 89 256 56 40 165 213 69 207 5 157 234 +255 180 295 32 88 217 316 276 203 273 93 86 302 193 20 116 122 226 236 7 268 3 +242 111 318 93 184 125 238 281 72 259 10 222 185 262 160 50 295 155 123 127 153 +45 9 27 121 89 35 238 85 107 169 166 31 310 16 188 53 307 160 148 118 200 25 83 +290 188 314 165 115 246 162 63 241 97 112 194 157 38 250 90 132 120 213 290 65 +279 255 278 118 37 30 173 94 60 189 92 47 243 110 58 176 146 105 254 43 94 223 +224 2 243 12 235 131 244 149 117 259 108 45 230 164 76 187 79 101 261 121 310 +212 193 143 151 32 63 45 132 22 31 245 123 4 158 135 172 218 36 16 286 235 33 +62 104 215 303 11 261 244 26 122 30 271 276 105 91 48 184 27 96 236 170 303 232 +79 199 84 166 252 128 290 283 ^ +649 1 133 208 17 198 259 204 187 273 102 30 282 218 85 116 111 146 16 18 299 +177 11 87 169 179 292 252 3 255 53 296 82 249 125 227 201 171 266 39 77 273 240 +9 172 46 278 205 139 136 86 79 16 63 54 76 56 312 123 312 78 236 179 247 210 +104 266 84 119 172 229 299 315 311 298 31 51 26 314 314 38 80 13 2 292 114 24 +44 191 103 27 221 135 123 140 99 25 317 54 121 42 276 301 92 134 22 256 5 159 +100 298 180 72 170 131 155 270 52 23 219 231 76 138 1 202 272 150 167 264 169 +30 237 142 186 127 142 3 72 32 152 265 87 214 255 191 241 293 77 284 316 229 +161 15 100 115 159 283 319 3 244 298 42 93 280 303 283 181 24 33 149 204 4 252 +313 213 120 307 113 106 181 207 54 259 21 166 163 251 223 50 246 75 186 138 184 +223 61 1 8 175 107 6 167 81 114 207 99 14 275 155 132 73 133 70 72 308 110 11 +98 245 112 281 221 146 199 73 88 315 139 319 141 189 188 225 286 48 10 273 285 +51 71 35 247 27 49 156 233 312 261 257 289 64 17 15 238 94 49 111 191 58 272 +288 146 154 318 189 5 170 176 197 169 41 313 41 175 96 285 234 92 145 64 155 +315 128 243 208 200 219 48 21 28 184 40 40 178 157 47 196 68 157 185 175 279 +306 23 264 307 296 127 4 24 216 170 314 176 59 224 151 130 203 86 34 295 164 65 +107 178 112 292 297 79 188 42 265 259 159 145 19 113 61 139 274 65 290 199 256 +143 104 311 126 52 161 198 121 225 10 90 230 262 254 228 15 55 39 260 294 29 +147 300 278 216 215 35 75 48 193 7 74 223 233 267 185 37 300 95 195 71 218 268 +137 221 318 144 284 271 187 228 26 131 293 249 263 172 91 320 104 128 105 263 +23 36 210 287 194 291 13 140 271 4 207 237 280 131 17 291 162 161 60 142 14 148 +252 141 234 264 124 275 17 153 217 305 198 304 280 120 262 71 173 192 238 232 +28 1 19 251 40 29 136 258 58 227 246 213 165 28 46 95 150 29 319 279 168 78 53 +124 137 38 263 34 112 109 276 290 16 201 33 287 149 215 80 151 302 182 297 217 +133 253 93 97 248 173 9 183 122 177 194 108 279 30 99 163 296 265 270 235 44 8 +82 204 49 294 212 202 89 129 57 126 7 85 299 132 256 154 180 210 115 21 304 108 +141 51 209 14 103 176 242 245 295 302 10 318 6 305 60 4 69 258 69 303 145 202 +134 171 277 115 297 262 209 152 82 66 70 83 29 9 67 67 22 301 47 58 89 267 2 16 +190 278 33 160 246 258 241 282 35 64 6 260 18 105 80 289 247 38 125 55 222 281 +83 201 309 211 250 226 111 8 37 162 150 305 243 25 179 109 231 214 117 212 30 +144 239 195 254 239 57 309 28 229 116 294 167 126 190 140 88 304 97 65 152 220 +45 281 178 ^ +SHS Type 3 Strings +40 1 18 20 11 15 11 11 9 6 2 15 5 17 12 1 9 1 3 5 11 7 2 2 6 18 2 9 11 8 16 11 +16 15 18 18 3 20 2 17 17 16 ^ +SHS Type 1 Hashes +DA39A3EE5E6B4B0D3255BFEF95601890AFD80709 ^ +3CDF2936DA2FC556BFA533AB1EB59CE710AC80E5 ^ +19C1E2048FA7393CFBF2D310AD8209EC11D996E5 ^ +CA775D8C80FAA6F87FA62BECA6CA6089D63B56E5 ^ +71AC973D0E4B50AE9E5043FF4D615381120A25A0 ^ +A6B5B9F854CFB76701C3BDDBF374B3094EA49CBA ^ +D87A0EE74E4B9AD72E6847C87BDEEB3D07844380 ^ +1976B8DD509FE66BF09C9A8D33534D4EF4F63BFD ^ +5A78F439B6DB845BB8A558E4CEB106CD7B7FF783 ^ +F871BCE62436C1E280357416695EE2EF9B83695C ^ +62B243D1B780E1D31CF1BA2DE3F01C72AEEA0E47 ^ +1698994A273404848E56E7FDA4457B5900DE1342 ^ +056F4CDC02791DA7ED1EB2303314F7667518DEEF ^ +9FE2DA967BD8441EEA1C32DF68DDAA9DC1FC8E4B ^ +73A31777B4ACE9384EFA8BBEAD45C51A71ABA6DD ^ +3F9D7C4E2384EDDABFF5DD8A31E23DE3D03F42AC ^ +4814908F72B93FFD011135BEE347DE9A08DA838F ^ +0978374B67A412A3102C5AA0B10E1A6596FC68EB ^ +44AD6CB618BD935460D46D3F921D87B99AB91C1E ^ +02DC989AF265B09CF8485640842128DCF95E9F39 ^ +67507B8D497B35D6E99FC01976D73F54AECA75CF ^ +1EAE0373C1317CB60C36A42A867B716039D441F5 ^ +9C3834589E5BFFAC9F50950E0199B3EC2620BEC8 ^ +209F7ABC7F3B878EE46CDF3A1FBB9C21C3474F32 ^ +05FC054B00D97753A9B3E2DA8FBBA3EE808CEF22 ^ +0C4980EA3A46C757DFBFC5BAA38AC6C8E72DDCE7 ^ +96A460D2972D276928B69864445BEA353BDCFFD2 ^ +F3EF04D8FA8C6FA9850F394A4554C080956FA64B ^ +F2A31D875D1D7B30874D416C4D2EA6BAF0FFBAFE ^ +F4942D3B9E9588DCFDC6312A84DF75D05F111C20 ^ +310207DF35B014E4676D30806FA34424813734DD ^ +4DA1955B2FA7C7E74E3F47D7360CE530BBF57CA3 ^ +74C4BC5B26FB4A08602D40CCEC6C6161B6C11478 ^ +0B103CE297338DFC7395F7715EE47539B556DDB6 ^ +EFC72D99E3D2311CE14190C0B726BDC68F4B0821 ^ +660EDAC0A8F4CE33DA0D8DBAE597650E97687250 ^ +FE0A55A988B3B93946A63EB36B23785A5E6EFC3E ^ +0CBDF2A5781C59F907513147A0DE3CC774B54BF3 ^ +663E40FEE5A44BFCB1C99EA5935A6B5BC9F583B0 ^ +00162134256952DD9AE6B51EFB159B35C3C138C7 ^ +CEB88E4736E354416E2010FC1061B3B53B81664B ^ +A6A2C4B6BCC41DDC67278F3DF4D8D0B9DD7784EF ^ +C23D083CD8820B57800A869F5F261D45E02DC55D ^ +E8AC31927B78DDEC41A31CA7A44EB7177165E7AB ^ +E864EC5DBAB0F9FF6984AB6AD43A8C9B81CC9F9C ^ +CFED6269069417A84D6DE2347220F4B858BCD530 ^ +D9217BFB46C96348722C3783D29D4B1A3FEDA38C ^ +DEC24E5554F79697218D317315FA986229CE3350 ^ +83A099DF7071437BA5495A5B0BFBFEFE1C0EF7F3 ^ +AA3198E30891A83E33CE3BFA0587D86A197D4F80 ^ +9B6ACBEB4989CBEE7015C7D515A75672FFDE3442 ^ +B021EB08A436B02658EAA7BA3C88D49F1219C035 ^ +CAE36DAB8AEA29F62E0855D9CB3CD8E7D39094B1 ^ +02DE8BA699F3C1B0CB5AD89A01F2346E630459D7 ^ +88021458847DD39B4495368F7254941859FAD44B ^ +91A165295C666FE85C2ADBC5A10329DAF0CB81A0 ^ +4B31312EAF8B506811151A9DBD162961F7548C4B ^ +3FE70971B20558F7E9BAC303ED2BC14BDE659A62 ^ +93FB769D5BF49D6C563685954E2AECC024DC02D6 ^ +BC8827C3E614D515E83DEA503989DEA4FDA6EA13 ^ +E83868DBE4A389AB48E61CFC4ED894F32AE112AC ^ +55C95459CDE4B33791B4B2BCAAF840930AF3F3BD ^ +36BB0E2BA438A3E03214D9ED2B28A4D5C578FCAA ^ +3ACBF874199763EBA20F3789DFC59572ACA4CF33 ^ +86BE037C4D509C9202020767D860DAB039CADACE ^ +51B57D7080A87394EEC3EB2E0B242E553F2827C9 ^ +1EFBFA78866315CE6A71E457F3A750A38FACAB41 ^ +57D6CB41AEEC20236F365B3A490C61D0CFA39611 ^ +C532CB64B4BA826372BCCF2B4B5793D5B88BB715 ^ +15833B5631032663E783686A209C6A2B47A1080E ^ +D04F2043C96E10CD83B574B1E1C217052CD4A6B2 ^ +E8882627C64DB743F7DB8B4413DD033FC63BEB20 ^ +CD2D32286B8867BC124A0AF2236FC74BE3622199 ^ +019B70D745375091ED5C7B218445EC986D0F5A82 ^ +E5FF5FEC1DADBAED02BF2DAD4026BE6A96B3F2AF ^ +6F4E23B3F2E2C068D13921FE4E5E053FFED4E146 ^ +25E179602A575C915067566FBA6DA930E97F8678 ^ +67DED0E68E235C8A523E051E86108EEB757EFBFD ^ +AF78536EA83C822796745556D62A3EE82C7BE098 ^ +64D7AC52E47834BE72455F6C64325F9C358B610D ^ +9D4866BAA3639C13E541F250FFA3D8BC157A491F ^ +2E258811961D3EB876F30E7019241A01F9517BEC ^ +8E0EBC487146F83BC9077A1630E0FB3AB3C89E63 ^ +CE8953741FFF3425D2311FBBF4AB481B669DEF70 ^ +789D1D2DAB52086BD90C0E137E2515ED9C6B59B5 ^ +B76CE7472700DD68D6328B7AA8437FB051D15745 ^ +F218669B596C5FFB0B1C14BD03C467FC873230A0 ^ +1FF3BDBE0D504CB0CDFAB17E6C37ABA6B3CFFDED ^ +2F3CBACBB14405A4652ED52793C1814FD8C4FCE0 ^ +982C8AB6CE164F481915AF59AAED9FFF2A391752 ^ +5CD92012D488A07ECE0E47901D0E083B6BD93E3F ^ +69603FEC02920851D4B3B8782E07B92BB2963009 ^ +3E90F76437B1EA44CF98A08D83EA24CECF6E6191 ^ +34C09F107C42D990EB4881D4BF2DDDCAB01563AE ^ +474BE0E5892EB2382109BFC5E3C8249A9283B03D ^ +A04B4F75051786682483252438F6A75BF4705EC6 ^ +BE88A6716083EB50ED9416719D6A247661299383 ^ +C67E38717FEE1A5F65EC6C7C7C42AFC00CD37F04 ^ +959AC4082388E19E9BE5DE571C047EF10C174A8D ^ +BAA7AA7B7753FA0ABDC4A541842B5D238D949F0A ^ +351394DCEBC08155D100FCD488578E6AE71D0E9C ^ +AB8BE94C5AF60D9477EF1252D604E58E27B2A9EE ^ +3429EC74A695FDD3228F152564952308AFE0680A ^ +907FA46C029BC67EAA8E4F46E3C2A232F85BD122 ^ +2644C87D1FBBBC0FC8D65F64BCA2492DA15BAAE4 ^ +110A3EEB408756E2E81ABAF4C5DCD4D4C6AFCF6D ^ +CD4FDC35FAC7E1ADB5DE40F47F256EF74D584959 ^ +8E6E273208AC256F9ECCF296F3F5A37BC8A0F9F7 ^ +FE0606100BDBC268DB39B503E0FDFE3766185828 ^ +6C63C3E58047BCDB35A17F74EEBA4E9B14420809 ^ +BCC2BD305F0BCDA8CF2D478EF9FE080486CB265F ^ +CE5223FD3DD920A3B666481D5625B16457DCB5E8 ^ +948886776E42E4F5FAE1B2D0C906AC3759E3F8B0 ^ +4C12A51FCFE242F832E3D7329304B11B75161EFB ^ +C54BDD2050504D92F551D378AD5FC72C9ED03932 ^ +8F53E8FA79EA09FD1B682AF5ED1515ECA965604C ^ +2D7E17F6294524CE78B33EAB72CDD08E5FF6E313 ^ +64582B4B57F782C9302BFE7D07F74AA176627A3A ^ +6D88795B71D3E386BBD1EB830FB9F161BA98869F ^ +86AD34A6463F12CEE6DE9596ABA72F0DF1397FD1 ^ +7EB46685A57C0D466152DC339C8122548C757ED1 ^ +E7A98FB0692684054407CC221ABC60C199D6F52A ^ +34DF1306662206FD0A5FC2969A4BEEC4EB0197F7 ^ +56CF7EBF08D10F0CB9FE7EE3B63A5C3A02BCB450 ^ +3BAE5CB8226642088DA760A6F78B0CF8EDDEA9F1 ^ +6475DF681E061FA506672C27CBABFA9AA6DDFF62 ^ +79D81991FA4E4957C8062753439DBFD47BBB277D ^ +BAE224477B20302E881F5249F52EC6C34DA8ECEF ^ +EDE4DEB4293CFE4138C2C056B7C46FF821CC0ACC ^ +SHS Type 2 Hashes +A771FA5C812BD0C9596D869EC99E4F4AC988B13F ^ +E99D566212BBBCEEE903946F6100C9C96039A8F4 ^ +B48CE6B1D13903E3925AE0C88CB931388C013F9C ^ +E647D5BAF670D4BF3AFC0A6B72A2424B0C64F194 ^ +65C1CD932A06B05CD0B43AFB3BC7891F6BCEF45C ^ +70FFAE353A5CD0F8A65A8B2746D0F16281B25EC7 ^ +CC8221F2B829B8CF39646BF46888317C3EB378EA ^ +26ACCC2D6D51FF7BF3E5895588907765111BB69B ^ +01072915B8E868D9B28E759CF2BC1AEA4BB92165 ^ +3016115711D74236ADF0C371E47992F87A428598 ^ +BF30417999C1368F008C1F19FECA4D18A5E1C3C9 ^ +62BA49087185F2742C26E1C1F4844112178BF673 ^ +E1F6B9536F384DD3098285BBFD495A474140DC5A ^ +B522DAE1D67726EBA7C4136D4E2F6D6D645AC43E ^ +E9A021C3EB0B9F2C710554D4BF21B19F78E09478 ^ +DF13573188F3BF705E697A3E1F580145F2183377 ^ +188835CFE52ECFA0C4135C2825F245DC29973970 ^ +41B615A34EE2CEC9D84A91B141CFAB115821950B ^ +AB3DD6221D2AFE6613B815DA1C389EEC74AA0337 ^ +0706D414B4AA7FB4A9051AA70D6856A7264054FB ^ +3CBF8151F3A00B1D5A809CBB8C4F3135055A6BD1 ^ +DA5D6A0319272BBCCEA63ACFA6799756FFDA6840 ^ +FB4429C95F6277B346D3B389413758DFFFEEDC98 ^ +2C6E30D9C895B42DCCCFC84C906EC88C09B20DE1 ^ +3DE3189A5E19F225CDCE254DFF23DACD22C61363 ^ +93530A9BC9A817F6922518A73A1505C411D05DA2 ^ +E31354345F832D31E05C1B842D405D4BD4588EC8 ^ +3FF76957E80B60CF74D015AD431FCA147B3AF232 ^ +34AE3B806BE143A84DCE82E4B830EB7D3D2BAC69 ^ +D7447E53D66BB5E4C26E8B41F83EFD107BF4ADDA ^ +77DD2A4482705BC2E9DC96EC0A13395771AC850C ^ +EAA1465DB1F59DE3F25EB8629602B568E693BB57 ^ +9329D5B40E0DC43AA25FED69A0FA9C211A948411 ^ +E94C0B6AA62AA08C625FAF817DDF8F51EC645273 ^ +7FF02B909D82AD668E31E547E0FB66CB8E213771 ^ +5BB3570858FA1744123BAC2873B0BB9810F53FA1 ^ +905F43940B3591CE39D1145ACB1ECA80AB5E43CD ^ +336C79FBD82F33E490C577E3F791C3CBFE842AFF ^ +5C6D07A6B44F7A75A64F6CE592F3BAE91E022210 ^ +7E0D3E9D33127F4A30EB8D9C134A58409FA8695B ^ +9A5F50DFCFB19286206C229019F0ABF25283028C ^ +DCA737E269F9D8626D488988C996E06B352C0708 ^ +B8FFC1D4972FCE63241E0E77850AC46DDE75DBFA ^ +E9C9BF41C8549354151B977003CE1D830BE667DB ^ +0942908960B54F96CB43452E583F4F9CB66E398A ^ +FCE34051C34D4B81B85DDC4B543CDE8007E284B3 ^ +61E8916532503627F4024D13884640A46F1D61D4 ^ +F008D5D7853B6A17B7466CD9E18BD135E520FAF4 ^ +BD8D2E873CF659B5C77AAC1616827EF8A3B1A3B3 ^ +B25A04DD425302ED211A1C2412D2410FA10C63B6 ^ +A404E21588123E0893718B4B44E91414A785B91F ^ +A1E13BC55BF6DAD83CF3AABDA3287AD68681EA64 ^ +D5FD35FFABED6733C92365929DF0FB4CAE864D15 ^ +C12E9C280EE9C079E0506FF89F9B20536E0A83EF ^ +E22769DC00748A9BBD6C05BBC8E81F2CD1DC4E2D ^ +F29835A93475740E888E8C14318F3CA45A3C8606 ^ +1A1D77C6D0F97C4B620FAA90F3F8644408E4B13D ^ +4EC84870E9BDD25F523C6DFB6EDD605052CA4EAA ^ +D689513FED08B80C39B67371959BC4E3FECB0537 ^ +C4FED58F209FC3C34AD19F86A6DACADC86C04D33 ^ +051888C6D00029C176DE792B84DECE2DC1C74B00 ^ +1A3540BEE05518505827954F58B751C475AEECE0 ^ +DFA19180359D5A7A38E842F172359CAF4208FC05 ^ +7B0FA84EBBCFF7D7F4500F73D79660C4A3431B67 ^ +9E886081C9ACAAD0F97B10810D1DE6FCDCE6B5F4 ^ +A4D46E4BA0AE4B012F75B1B50D0534D578AE9CB6 ^ +6342B199EE64C7B2C9CBCD4F2DCB65ACEF51516F ^ +AABFD63688EB678357869130083E1B52F6EA861D ^ +F732B7372DAF44801F81EFFE3108726239837936 ^ +5E9347FE4574CDCB80281ED092191199BADD7B42 ^ +D5776B7DFFF75C1358ABDBBB3F27A20BB6CA7C55 ^ +022B7ADA472FB7A9DA9219621C9C5F563D3792F6 ^ +7F1DE4ECA20362DA624653D225A5B3F7964A9FF2 ^ +CA0F2B1BFB4469C11ED006A994734F0F2F5EFD17 ^ +833D63F5C2EA0CD43EC15F2B9DD97FF12B030479 ^ +14FD356190416C00592B86FF7CA50B622F85593A ^ +4AB6B57EDDEF1CE935622F935C1619AE7C1667D6 ^ +B456A6A968ACD66CAA974F96A9A916E700AA3C5D ^ +FD1C257FE046B2A27E2F0CD55ED2DECA845F01D7 ^ +66E0D01780F1063E2929EAAD74826BC64060E38C ^ +A8478DF406F179FD4EF97F4574D7F99EA1CE9EB8 ^ +248E58CF09A372114FC2F93B09C5FC14F3D0059E ^ +F15767DE91796A6816977EFA4FCED4B7FD9B8A57 ^ +36A6BC5E680E15675D9696338C88B36248BBBAF4 ^ +4DEA6251B2A6DF017A8093AB066EE3863A4EC369 ^ +D30E70E357D57E3D82CA554B8A3D58DFF528FA94 ^ +70CA84D827F7FD61446233F88CF2F990B0F3E2AA ^ +8D500C9CFDE0288530A2106B70BED39326C52C3C ^ +F3D4D139EDFC24596377BC97A96FB7621F27FFC7 ^ +5509BAFFAC6D507860CEFC5AB5832CB63CD4B687 ^ +0C0AEA0C2FD7A620C77866B1A177481E26B4F592 ^ +149176007FEE58A591E3F00F8DB658B605F8390C ^ +17C0D7B0256159F3626786FFDB20237AE154FA84 ^ +741A58618ABEB1D983D67AFDCBC49AA397A3B8E0 ^ +B738D6B3409EB9ED2F1719B84D13F7C36169CDEC ^ +3D33DE31F64055D3B128AC9A6AA3F92DFD4F5330 ^ +B6925F4DF94949B8844C867428BA3DEDF4CF2B51 ^ +CF5E7256292ABEC431D8E8B9CBEAF22AF072377E ^ +975DCE94902923977F129C0E4ACF40AD28DDB9AA ^ +333B0259B18CE64D6B52CF563DD3041E5F63A516 ^ +SHS Type 3 Hashes +80E044703A880C20EC41F645120A8A5B5D194ECE ^ +E142829CA08FC9787F17AA16CE727396169B2713 ^ +6A2BAF62469D311F9257A0727F52C7EAA87CCEB4 ^ +362E3E7136CA611D7FBF687D3BBDC54CDA64843F ^ +F5900ADC6223A5D24A7526ABFC60FA8E2D59A5AB ^ +AD0CAC6A21D5B10833DDE7FA85927D74EDA142A9 ^ +47AD337EAFFDC177AAF7CBD035BE6F398B9D0536 ^ +9CF58595DF80872535BCC7C056E223546F0BB4EE ^ +7151CEB1918278CED2902B1D663D596F8D1B986F ^ +ADDC9F09AA4026EF6C4B7F1A84D3A13B4CDC65B3 ^ +921FE78A863A317B1FA1FB3CA3BE1948DE7EF754 ^ +64BE10732D71D52CE8A486DA23E6B453DF7C6FBD ^ +4A450659470DD759ABFAE1D73972A6D2E63AC16C ^ +0D665E4BBF30B7EAB955BDE84759E185EECAB4CB ^ +0C1B8EE94D61CDD0837EAED9FE33DE4A8334B596 ^ +D93BFE2A6227A4BF9B7C61EBCE4A8CDE131593FE ^ +BDA883F804B470C90BD6AC490DFC34EBC27F9648 ^ +46A0969373552213632591C52030C38E5DBDC49E ^ +4781289E48B910C550DC23CA7D3AF5324C03532D ^ +693A34CFCDDED0F3AC72E7197FCE9BB66A8E3981 ^ +AE088AF1D8865140963B3ABFB63E32E04CD1506F ^ +ADF0F8F1D85CA97586F5DC6DC5FD11FA39270F55 ^ +E484F5AD86C5F4D09E366ADF6E0DE73449F97B28 ^ +81C49842BA3D7072FB42288E03CE737A2672C091 ^ +F6CC71AD897C23A16835490DED289BFD45500AB0 ^ +23E71AED62FE8E28F34F58E7FE5594EC5EB0486C ^ +92BA7934AA5867EE52960F4E0EDFB90AA7B69305 ^ +C3D1CC8CBD1B6FFEE0D90CE962CD9C09AB1548AA ^ +3CE37A583B71A6A77BE325066A0F00C5D11DFC3E ^ +76EF5D236E1042D356A3234A422C092F86003064 ^ +8C3F703436C6C882E60263540A8E4C3E5646DC15 ^ +6138F9F3AB43B988DD3857422CCB304352459F40 ^ +B812DE98775B4690B4FC2ECFCAB61C73C7271DC7 ^ +06660985CD80D48E7B9F88455B4233924C3B64BB ^ +76AB4B6378D6F63499A94EB67EB1CB31AFF8D775 ^ +F31F6B0BE7AB059A1F59A46481967E88392979E6 ^ +0C1638498FBB7DB9600B98B4B22EF85E0FE245FB ^ +5607C6AF600939736795AC523FA43B736F41A118 ^ +8A03244866BDD21B9D8A82E98436C894FAD86ECC ^ +8A75BFD911AF87303B9B8FB7A1A47CCA52D3D98A ^ +16F0F3B5D37411236A1E3D6B1EDAB74CDA25ED4B ^ +AC72BF45477481F58A302628DC5299FFA32E7C9F ^ +74CFFD5881F75AC20726E1447DCF7F47024380EF ^ +5BFBECEECBC27DA05729C4D1AC8C1286EA6DCEC9 ^ +012AACBC0579FA4CB4F107E9A9AD1A86AD2F6A4D ^ +F7D552CBC5EF90F1A579388B5A8A9EC71EB67681 ^ +10C70115C4C34753274BFED477DF01440A67A361 ^ +078D2FACD293B6B6219D89899C16AA1AA8E3DE82 ^ +83C6BF9FB0D3091ADF374EBFA0A69916F17E6D26 ^ +2CDB1924DA62AB64C007C6505FF657E4ADDEA9C1 ^ +E95D209BCB9864B076FF4DFCA8F8BD75D62D1B48 ^ +632824CF5025F8F90AD2923BDDF449550D64C0F5 ^ +02B1C0B41FC27EC5A32E586F1AC480BF0061E56A ^ +28156BC6769AE390BF32C6512C46169181E1536D ^ +F730E6E287D992E7F3E013B6F1E088F0B9C41598 ^ +B056A6A832FA5FE964EF77FF3E0BE1C32E0D58C0 ^ +D5B3D19AFBB48FB56BA6D44A82DE6BD08DB208DE ^ +0215AD79BD6B8023C05FD2F8966211897DF6337A ^ +EC4CF38C244EB6526A44F70570925247145DA8CA ^ +C0D931262ECE93DA5A6ABC89CD6AD3162EA6B09E ^ +6BB48FAC26AA2B4859BBDEFCFB53AE4D1D9A0340 ^ +58611D43741E67A7F0DA9CB337A59DCD1EBE758E ^ +7C2AEC216AF231509E47B7EED06BB17859812B7E ^ +F60EE5DBF4A7A676EC98B3DDB1CDD6CDF3CDA33B ^ +0492E59B1F4C94E97F29A26C3EE7D57E1B0FDD72 ^ +4FCF549D902D9BE1101A756DB9E45415FB61BCD2 ^ +95C71D26AD6B38CC771376B4A4F962F12E1E3D4F ^ +F6A2449E773C72FB886B3C43E2B30EC2A1B7454A ^ +CDE86695E00AEC9A5DB6FDDB5D5A5934448D58E0 ^ +502318A758FABFF6AC53844E9E2BCD159C678510 ^ +589D295148F95F75DAE964DD743FE981FA236D4E ^ +7973DD33AE3599A556BACC77E8656E782E029EFF ^ +9F5BE43AADD43C6DB3883C9DA4B52E1A50257AEE ^ +454289D8FFB237A56D5214EAE88F0A9D328FEA1A ^ +7E686B36595BEB4C0D4528FF960EDB55088A028D ^ +F9789D1EF19A0084AC0E9F43A4BC0EE0478939EF ^ +2F32B0E7CC8BE19C325545C816E77056D7BBE70F ^ +6B1617746F073CFCD2CEBCAFBBE6FD0E28ED2D56 ^ +CF8D2EA3888AD76761799383E5A15979F6DB7A88 ^ +557AF6D9D5947203C60E98C9A79B92B8BD085E2B ^ +C61A217423DE68ED6CD34C91756C8DD3A650A2A2 ^ +73F3F79C151B6C1BD9369EDB26B932C2362B0593 ^ +364141E5FBCDE83F210C5BBBEB6810F6299DE14B ^ +F806BECD025D264FD59E93D9E3606A674C40F216 ^ +E0C761A57F00CBFB07D49BCB034C36A7122F4C5B ^ +5D3831044B9E0032FBE3C3425FFD13698F413B33 ^ +7EB1AB41E9997753C5D530DF118E71E72D7B86FC ^ +CC053EA1556269D7E8BCBA30B208FCBF0EE2EE64 ^ +A57739B1DD41E7DC0C40D6B6159A7E73CE2748AA ^ +90DA527C9DB9ACC2FD530D560A2F1191A80D0567 ^ +6AC1F2A0B8CA0E5ABC9FDF1ADCE588FBDF5CC53E ^ +43C1A0A0EE4163EC929726989F92B03639B233AB ^ +8927F299462413AC29A74080E54D8EE2DB7165E7 ^ +0C8D7E22226D91B423E781B508F31517EAAB607B ^ +7286E20D7F08D18A893254FBD3CC833F7973DCAF ^ +0CB8C235928B8E936C43B8F29EF3758B9FD54A7B ^ +F67C24CC23E440CA3F206CEEB5504ECA54CD5CA3 ^ +D78A25DEAA1E7ADADDB3C145ED0E5263BA4F2910 ^ +00AA68174D29492C578AC853FFCD55908292D41A ^ +D5570EEDB09A62A5948F7F311F7ED5EF247F9AD9 ^ +SHS Type 1 Strings +0 1 ^ +5 0 2 1 2 1 2 ^ +5 0 1 3 4 4 4 ^ +7 0 4 3 4 4 1 4 4 ^ +10 0 4 1 5 3 4 4 3 1 3 4 ^ +10 0 3 1 6 5 5 1 3 6 6 4 ^ +13 1 3 2 5 3 3 3 4 6 6 1 4 6 2 ^ +16 1 3 5 5 1 2 1 3 3 6 3 5 2 3 5 7 2 ^ +15 1 8 1 5 3 2 7 4 5 6 7 3 3 1 6 3 ^ +15 1 4 6 8 2 1 4 2 5 1 6 8 8 6 4 7 ^ +18 1 1 2 7 3 8 6 7 5 4 3 4 3 5 3 3 2 6 8 ^ +16 0 9 8 1 8 1 7 6 7 7 1 2 6 9 5 4 7 ^ +18 0 7 1 7 3 9 4 7 7 5 2 8 1 7 8 2 7 2 9 ^ +19 1 2 3 1 8 8 6 9 10 3 10 8 9 2 4 1 5 1 5 9 ^ +19 1 8 5 4 8 1 3 9 5 7 7 2 7 2 7 8 7 4 8 10 ^ +20 1 1 9 7 4 1 4 5 1 10 8 6 4 4 9 9 9 8 2 9 10 ^ +19 1 11 6 7 7 2 6 2 6 10 6 9 10 5 11 1 6 8 11 4 ^ +22 0 10 5 10 3 7 8 9 9 1 1 1 10 2 1 5 10 2 9 9 9 7 8 ^ +21 0 1 10 1 6 9 4 2 5 2 11 8 12 12 9 8 1 3 10 7 11 12 ^ +24 1 3 9 5 12 3 4 2 9 12 11 6 6 1 1 9 5 9 1 4 9 4 10 8 9 ^ +25 1 3 2 3 11 1 12 5 6 2 7 8 4 8 8 9 9 8 4 9 1 4 8 10 9 9 ^ +23 0 11 10 7 10 10 6 10 9 4 5 10 5 8 4 1 10 12 4 6 1 8 11 6 ^ +22 0 12 8 10 4 3 8 5 5 7 11 13 11 12 11 4 12 3 6 5 11 10 5 ^ +26 1 10 9 6 9 7 2 10 4 4 5 5 2 12 13 5 3 1 10 1 4 7 8 13 13 12 9 ^ +31 0 2 6 5 4 7 3 10 6 13 6 3 9 6 2 10 5 3 8 4 1 11 3 5 3 7 11 1 12 9 12 5 ^ +27 1 14 5 1 3 7 2 3 9 3 4 14 4 4 10 8 5 14 1 11 12 12 10 4 13 7 11 9 ^ +30 1 4 9 5 5 8 9 5 10 4 2 4 7 9 9 6 3 5 1 8 3 2 13 3 14 9 8 9 10 14 10 ^ +27 0 12 9 5 8 7 2 14 12 3 8 14 6 6 4 7 5 7 10 7 11 10 1 9 6 7 12 14 ^ +24 0 12 9 9 2 11 13 12 11 11 6 14 13 10 5 6 8 10 4 3 11 11 14 5 14 ^ +24 0 15 4 5 3 8 12 15 8 14 15 9 12 12 3 10 13 6 11 10 4 13 14 8 8 ^ +28 1 1 8 1 5 11 4 9 12 4 13 15 5 9 11 7 14 11 1 11 7 8 8 11 1 13 15 12 13 ^ +32 1 5 8 3 8 10 7 8 1 5 13 12 14 5 3 6 4 12 15 6 6 10 11 13 9 1 11 6 10 3 7 14 +2 ^ +31 0 10 3 5 1 14 11 11 16 1 2 2 11 6 13 15 12 6 5 16 2 14 2 10 12 2 5 5 6 10 13 +15 ^ +34 0 3 10 8 16 9 5 12 15 4 11 13 3 6 5 10 8 1 3 9 3 11 1 2 16 12 10 6 1 9 1 16 +5 6 14 ^ +30 1 1 12 4 4 2 15 13 15 11 15 5 11 9 7 15 16 6 16 12 3 2 10 16 5 5 7 1 7 11 16 +^ +34 0 7 9 11 2 5 5 5 4 13 13 14 4 7 12 6 4 8 2 9 9 13 13 3 3 6 7 16 7 6 15 5 8 +15 14 ^ +36 1 4 6 16 15 11 14 14 4 7 10 3 4 10 3 6 7 14 4 6 6 5 2 7 8 16 2 12 16 10 14 3 +2 3 7 14 3 ^ +32 0 15 10 9 1 14 10 14 6 6 16 3 2 3 8 3 12 8 11 17 3 9 7 16 14 4 11 15 5 13 9 +5 17 ^ +30 0 17 17 13 8 2 6 8 16 1 12 5 17 2 9 8 10 13 14 11 17 12 5 14 9 11 9 11 4 11 +12 ^ +30 1 16 6 10 5 8 3 17 16 14 1 15 15 15 6 13 2 11 6 13 11 13 4 6 7 11 11 12 16 +13 16 ^ +33 1 16 16 14 16 2 4 16 11 6 15 7 4 17 6 5 7 6 3 14 16 5 17 11 13 1 1 14 13 3 6 +14 5 16 ^ +39 1 2 16 13 7 8 6 2 15 1 9 12 4 4 11 13 7 2 11 9 18 4 5 4 8 2 14 9 9 1 8 13 11 +15 8 5 9 10 16 7 ^ +34 0 2 7 1 1 17 13 6 11 10 8 5 12 15 6 15 10 12 4 18 1 2 8 11 12 16 10 12 18 11 +16 12 11 17 6 ^ +34 1 4 7 13 7 10 7 10 6 1 12 7 18 11 18 2 10 15 10 14 8 18 9 9 12 12 3 13 12 6 +4 9 17 13 17 ^ +40 0 5 7 3 2 1 17 14 4 16 6 13 1 13 6 6 10 1 3 18 3 11 7 9 5 7 11 17 1 9 16 5 +15 10 17 3 8 15 17 8 12 ^ +40 0 11 3 15 17 11 1 1 4 3 14 18 4 2 18 8 15 6 4 6 3 15 11 16 10 17 17 9 6 3 2 +6 16 4 9 12 6 8 1 11 17 ^ +37 1 2 19 12 8 16 14 2 9 16 2 6 6 7 9 10 9 11 9 14 11 15 5 16 9 2 17 2 8 15 8 4 +3 14 14 16 16 12 ^ +37 1 11 10 16 12 11 7 14 14 14 6 10 10 1 6 13 19 5 6 4 7 12 12 10 5 10 15 15 8 +5 13 17 13 5 6 14 1 19 ^ +38 1 2 6 5 17 9 11 18 18 8 6 13 15 3 3 15 5 13 18 3 2 5 5 14 7 13 4 17 7 2 17 3 +18 15 7 15 16 18 11 ^ +38 1 12 8 6 3 17 12 13 19 15 9 7 17 16 15 3 11 11 5 2 13 19 16 2 4 16 7 8 1 2 9 +17 12 3 5 18 19 11 9 ^ +39 1 14 16 14 8 9 16 5 1 6 3 17 18 16 9 1 15 9 10 9 19 1 3 3 20 11 13 17 1 19 8 +3 4 3 7 1 14 19 19 19 ^ +37 1 18 13 11 5 18 4 19 10 6 19 11 17 10 10 7 9 13 16 9 10 18 4 12 5 16 5 20 12 +3 8 10 1 18 1 6 20 14 ^ +36 0 8 9 6 12 11 7 7 3 17 13 6 20 17 9 20 16 10 12 17 8 11 8 11 10 5 10 14 18 8 +19 9 12 12 2 20 19 ^ +39 0 12 16 20 3 9 9 19 17 13 13 4 17 2 11 7 14 3 6 16 13 10 13 5 16 10 2 8 2 17 +19 4 17 7 19 6 9 15 15 6 ^ +43 0 7 2 18 5 7 18 5 2 15 7 11 10 9 3 2 14 19 3 11 8 18 15 5 3 5 12 15 16 10 17 +7 19 16 2 1 16 6 3 19 12 5 18 16 ^ +49 1 9 11 2 1 12 11 14 12 14 10 4 11 6 8 16 7 5 11 20 8 17 4 14 4 15 3 2 2 4 3 +2 3 14 15 10 2 12 7 3 7 20 20 19 10 2 3 1 10 20 ^ +36 0 19 20 12 5 19 21 5 21 11 14 19 1 17 8 9 4 19 3 17 1 14 21 14 7 6 5 20 14 +21 20 4 6 21 7 11 12 ^ +41 0 12 9 11 6 16 18 18 10 11 20 6 12 11 5 7 21 19 18 6 15 21 10 4 14 9 19 10 3 +3 5 13 1 8 12 3 13 9 7 10 17 14 ^ +45 0 10 6 8 3 17 18 3 21 19 6 17 15 4 9 15 9 15 14 4 7 14 8 10 13 4 11 10 7 6 +21 1 14 5 11 7 7 2 13 13 3 9 13 8 14 20 ^ +39 1 3 7 18 4 9 9 5 15 13 17 10 15 16 20 8 19 9 10 9 1 19 14 21 2 18 13 10 4 18 +16 4 21 15 10 18 19 3 12 18 ^ +41 0 14 4 13 11 1 11 1 10 2 12 4 21 10 21 18 9 2 16 7 20 6 7 12 19 20 1 13 12 +10 8 21 15 7 19 13 6 8 19 20 18 19 ^ +37 0 11 18 1 17 14 15 20 16 20 8 2 17 10 4 21 5 19 19 14 22 21 18 13 14 1 3 12 +11 11 4 22 13 5 18 7 21 21 ^ +48 0 9 22 19 12 8 16 5 17 5 9 1 2 9 6 12 6 1 7 4 3 15 1 14 1 12 3 10 2 10 14 21 +13 17 6 6 17 1 21 2 14 16 17 9 11 20 21 11 18 ^ +50 1 12 8 20 13 2 9 20 9 14 10 1 16 2 22 6 4 16 14 15 1 12 4 14 9 21 3 3 9 8 21 +15 14 8 4 14 4 2 3 8 12 8 6 1 2 18 20 15 3 19 10 ^ +44 0 10 20 14 6 3 4 21 1 12 4 18 2 6 7 6 9 20 14 10 10 19 17 21 12 15 17 7 10 +11 8 10 12 1 19 19 9 18 21 4 18 11 9 22 5 ^ +47 0 15 8 15 3 5 6 2 19 12 17 4 20 8 11 20 2 18 4 16 20 12 9 9 6 16 21 16 3 16 +18 3 19 5 16 2 4 2 12 11 15 11 14 17 2 10 18 8 ^ +48 1 5 13 3 21 5 3 6 18 18 10 1 21 21 7 1 13 12 19 1 14 6 8 21 19 21 11 19 13 2 +13 4 1 10 22 16 4 9 4 10 16 3 7 15 11 9 13 17 12 ^ +45 0 14 7 6 2 20 3 6 19 19 10 2 22 12 17 12 1 20 7 7 15 20 6 18 8 3 14 23 18 15 +4 7 5 23 15 7 14 10 10 19 17 2 4 15 17 21 ^ +45 1 15 11 8 9 17 5 12 18 14 6 20 17 21 12 16 9 22 9 20 15 2 22 11 2 6 11 9 8 2 +4 14 19 3 21 21 23 8 2 11 4 8 4 20 22 11 ^ +38 0 21 18 22 10 19 9 14 17 23 21 10 7 15 13 16 5 4 10 13 14 20 23 12 20 23 18 +10 12 8 21 11 6 12 7 19 14 18 17 ^ +40 0 18 22 6 9 22 5 23 13 6 8 23 20 22 5 22 15 19 20 9 9 1 13 13 10 14 13 5 22 +14 21 9 21 19 14 14 4 18 13 12 14 ^ +48 1 7 3 15 5 17 14 23 14 5 17 22 11 1 8 13 23 6 21 3 6 11 7 23 8 6 21 4 4 22 +19 13 8 5 19 7 5 23 1 4 19 11 23 11 21 14 1 3 21 ^ +43 0 22 14 11 7 18 16 17 24 12 12 3 13 19 16 22 4 16 4 6 23 8 18 11 2 3 20 22 9 +21 8 23 1 23 20 7 16 13 23 4 13 3 7 22 ^ +47 1 23 6 13 19 2 3 7 2 9 9 15 6 13 4 22 6 19 20 1 9 7 14 1 15 3 23 24 22 18 12 +12 17 19 10 8 11 22 12 10 2 20 15 18 17 18 7 19 ^ +47 1 12 21 6 12 4 7 18 17 3 2 14 24 14 1 23 1 11 15 10 6 18 20 7 1 8 1 16 6 20 +23 23 21 10 10 12 24 10 11 23 2 12 23 9 3 24 24 10 ^ +52 0 14 10 18 15 14 5 16 11 22 2 15 24 8 22 1 4 24 9 10 15 3 9 5 4 17 15 9 12 +19 19 1 3 10 6 8 3 17 8 18 24 19 3 4 15 4 9 2 24 5 20 13 13 ^ +42 0 20 17 19 22 13 8 10 19 15 11 1 14 17 20 22 10 7 11 16 9 21 22 17 23 12 15 +4 24 7 21 18 2 21 16 1 19 18 20 11 3 15 17 ^ +50 0 18 1 6 14 5 5 5 19 13 10 24 19 16 24 15 13 2 19 15 24 21 17 4 13 17 1 1 9 +1 10 2 18 1 21 19 5 18 12 2 22 16 23 15 19 6 18 9 1 23 5 ^ +51 0 21 13 14 11 18 12 13 3 19 9 20 22 20 2 11 12 6 1 12 16 18 2 9 8 4 3 11 17 +11 5 4 19 16 11 23 13 18 1 20 8 2 16 16 21 4 19 5 5 20 24 16 ^ +53 1 20 25 17 11 8 4 19 25 17 7 16 21 6 4 8 2 15 9 2 9 19 3 6 3 3 10 25 13 15 7 +8 20 21 12 10 12 5 24 11 20 3 13 13 16 9 13 10 3 9 16 3 7 25 ^ +49 1 9 9 14 2 13 17 25 2 18 5 19 23 9 25 9 10 23 12 12 7 13 8 15 7 1 6 21 2 8 7 +6 16 14 14 12 15 13 24 10 15 11 10 8 14 15 21 25 21 25 ^ +47 0 9 18 20 22 21 20 11 14 23 22 10 13 14 8 19 12 2 11 20 23 13 4 10 6 5 7 23 +11 3 16 8 21 4 8 18 5 12 14 8 6 20 19 24 8 23 17 23 ^ +48 1 7 19 1 18 1 14 22 13 14 5 8 22 18 14 25 17 11 12 22 2 12 12 16 12 13 18 17 +12 17 14 18 8 25 9 23 5 3 8 14 24 17 7 3 3 23 17 22 19 ^ +51 1 19 17 16 22 24 14 16 20 23 20 9 19 16 7 12 16 5 8 9 7 10 21 24 10 11 19 1 +21 14 14 19 3 22 8 12 20 1 18 5 6 5 12 14 1 1 11 9 22 3 24 4 ^ +52 1 6 1 11 16 1 12 8 11 11 17 10 22 7 3 10 2 6 4 24 16 24 19 4 5 18 11 12 9 20 +21 25 2 21 18 10 20 25 21 3 17 17 5 8 22 25 19 8 10 19 7 11 18 ^ +44 0 26 14 21 25 25 4 9 13 5 8 9 21 8 12 26 24 9 24 15 1 23 22 16 14 8 22 15 19 +24 20 7 8 15 24 12 4 4 23 21 13 19 15 21 12 ^ +59 1 15 7 3 21 20 8 22 14 23 26 19 2 10 18 3 5 3 1 9 15 15 3 7 13 23 9 7 1 13 +17 14 25 9 16 2 2 6 13 7 19 25 17 1 5 21 2 7 22 5 6 25 3 12 19 6 2 4 24 17 ^ +60 0 9 18 20 19 4 11 14 1 6 8 26 6 9 22 4 10 2 7 21 9 8 24 25 14 22 12 22 3 23 +3 3 20 6 11 23 6 1 7 5 18 5 15 25 26 1 1 10 11 11 4 12 11 20 3 14 2 3 2 23 15 ^ +49 0 12 17 24 11 8 6 24 16 15 22 21 14 6 12 20 19 5 5 12 11 6 23 2 16 23 7 24 6 +21 2 17 17 5 25 11 25 20 25 24 18 6 12 19 25 7 6 5 2 25 ^ +54 1 12 16 1 15 7 1 26 19 19 13 20 11 17 6 20 5 24 24 1 21 11 9 20 21 15 10 19 +26 3 2 6 7 12 9 10 8 14 10 15 5 17 8 21 1 20 25 6 19 8 3 22 16 16 20 ^ +63 0 17 13 11 10 17 15 12 6 13 14 17 4 12 10 24 5 13 24 3 5 2 5 11 14 8 5 10 17 +16 8 4 14 21 15 3 6 17 25 8 2 3 3 19 10 13 22 22 8 2 13 25 17 2 1 19 1 14 20 2 +5 4 15 24 ^ +49 0 14 20 7 25 20 26 20 16 7 17 17 22 1 13 6 5 1 18 14 15 23 15 10 5 19 18 18 +26 12 13 3 25 12 21 16 24 4 16 3 6 26 26 10 20 13 1 20 24 15 ^ +56 0 3 8 14 5 5 7 11 13 11 26 11 4 26 17 20 19 11 10 3 10 14 9 6 9 7 16 10 4 4 +19 19 2 26 13 19 17 15 24 15 4 21 22 13 13 12 22 2 14 20 5 18 7 17 24 20 20 ^ +58 1 6 17 9 20 2 10 19 3 22 4 1 11 3 5 3 21 11 15 12 23 26 5 2 27 6 5 16 6 3 2 +23 5 3 20 20 4 24 2 18 21 7 14 10 27 23 6 24 6 19 23 3 9 22 16 21 17 19 23 ^ +58 1 17 7 21 19 6 16 15 15 20 14 2 25 19 14 18 19 7 9 1 14 11 10 16 3 23 14 26 +10 11 1 18 1 12 24 19 19 1 7 2 3 24 7 12 9 2 8 16 20 24 5 26 26 4 9 2 7 25 17 ^ +54 1 8 12 18 14 26 7 17 18 4 20 1 16 14 21 26 4 6 8 24 11 25 15 24 16 23 4 10 +23 21 24 15 10 9 26 7 14 24 21 6 20 5 17 16 17 1 3 12 1 4 13 3 9 21 26 ^ +56 1 7 18 11 1 19 20 23 12 12 27 13 13 15 16 13 1 16 15 12 26 3 16 16 8 17 13 +21 4 6 5 19 14 16 4 16 11 14 18 18 27 9 13 21 3 26 22 3 7 6 4 26 3 15 8 25 21 ^ +50 1 20 13 9 11 20 6 11 21 27 25 20 7 4 18 26 16 27 5 12 19 7 23 6 25 25 2 11 +13 25 21 18 17 6 12 14 13 24 11 14 19 26 27 25 6 1 15 4 7 27 15 ^ +51 0 15 16 26 27 23 14 12 28 22 15 8 19 2 20 13 1 24 2 25 1 6 19 19 8 11 24 24 +21 13 27 5 11 28 17 7 25 6 23 24 14 25 12 5 13 26 2 5 8 10 16 17 ^ +58 1 5 26 18 19 21 3 12 11 13 4 14 22 22 14 16 13 3 22 16 23 5 19 6 13 10 26 17 +27 26 4 3 25 6 14 2 3 5 7 23 11 22 8 25 2 9 25 18 17 8 2 14 4 19 1 5 27 13 24 ^ +53 0 2 27 28 2 17 23 10 27 18 26 7 22 16 3 27 1 26 21 28 10 3 6 2 2 10 17 13 16 +6 17 21 23 13 20 22 5 6 11 12 12 8 23 13 17 9 23 20 3 28 27 12 17 22 ^ +59 0 28 19 5 21 4 27 8 1 19 14 20 6 7 9 1 6 22 3 19 26 14 8 6 7 19 15 23 1 17 +16 6 26 14 5 22 25 4 7 10 16 21 10 18 19 24 16 23 8 3 17 28 18 10 2 5 3 21 21 +15 ^ +58 0 6 24 1 4 24 18 10 22 1 21 12 5 4 4 20 25 24 26 8 25 11 2 7 27 22 19 4 18 +27 10 28 4 12 24 8 16 12 11 16 17 25 8 12 16 1 9 9 10 5 24 23 18 5 14 18 8 4 28 +^ +61 0 5 17 8 28 1 22 4 11 3 2 17 3 14 9 27 13 18 24 9 8 7 28 25 14 21 27 24 6 18 +16 2 12 15 9 14 10 1 8 17 4 6 15 26 11 15 2 28 20 26 16 3 7 5 8 9 26 10 12 25 +11 22 ^ +53 0 9 13 24 15 20 2 4 8 2 22 20 19 4 15 14 28 13 25 10 10 12 28 24 22 26 28 15 +9 11 26 19 22 27 2 21 8 20 23 26 12 10 21 9 15 13 25 7 26 1 13 5 9 20 ^ +58 0 3 9 21 22 7 1 23 28 1 2 8 22 12 18 28 5 18 14 7 11 17 20 20 7 21 13 8 28 +21 22 2 16 20 15 28 9 3 22 13 10 23 4 16 11 14 1 10 8 14 14 15 18 13 12 21 18 +25 28 ^ +60 1 29 20 2 29 22 8 16 20 4 12 9 6 12 16 16 7 9 20 29 11 9 4 1 15 25 16 29 10 +22 7 2 8 5 18 14 23 24 4 6 26 3 11 6 12 1 7 14 24 14 6 10 21 16 23 29 25 6 14 +17 24 ^ +64 0 12 10 5 10 15 25 8 15 3 7 13 25 16 14 1 29 22 26 15 27 9 1 8 8 28 6 13 5 +13 3 15 5 23 8 23 2 5 5 4 17 13 14 7 17 12 27 3 18 5 7 5 26 18 15 22 28 16 13 7 +2 23 19 25 15 ^ +56 1 17 7 16 25 23 11 11 15 2 13 9 26 2 24 26 7 28 11 2 29 7 22 23 5 28 19 1 27 +29 1 24 11 18 20 3 13 11 7 3 15 17 24 1 18 13 6 3 25 27 16 28 18 24 8 23 22 ^ +51 1 29 28 6 28 14 12 28 27 22 4 14 25 1 3 9 7 11 14 15 16 10 19 12 19 11 20 13 +28 4 27 28 7 27 12 4 28 21 17 22 20 17 15 15 23 22 13 12 21 22 21 29 ^ +64 1 12 14 12 18 27 8 7 4 9 14 16 15 8 11 21 20 10 10 21 23 20 2 11 23 1 11 1 5 +3 23 16 15 27 14 5 16 3 22 2 3 24 3 19 29 4 4 10 8 20 14 15 1 26 12 27 25 4 28 +22 11 19 19 24 9 ^ +60 1 20 8 9 5 25 19 17 19 15 7 24 24 21 3 20 16 8 3 17 28 18 29 9 23 9 10 29 4 +12 24 15 5 8 22 17 29 12 3 8 29 15 21 21 4 7 20 7 10 7 26 10 16 24 6 7 12 8 12 +15 17 ^ +60 0 9 17 11 28 12 26 26 6 29 13 10 20 6 23 10 4 3 26 26 14 20 20 25 14 13 15 +24 14 11 4 23 27 24 20 9 16 17 24 13 12 6 1 14 26 25 7 8 21 1 19 3 2 2 17 21 13 +5 9 21 11 ^ +54 0 25 1 27 24 6 23 16 5 1 20 29 22 25 9 25 10 3 28 28 25 19 18 16 24 14 15 5 +28 12 28 26 29 2 15 15 9 5 18 19 22 12 15 4 6 15 24 16 9 4 26 25 18 27 12 ^ +61 1 20 4 26 12 3 22 1 22 30 3 28 10 9 24 14 29 6 30 3 10 20 14 6 3 19 21 21 28 +16 18 11 30 11 20 30 1 9 8 11 5 19 10 24 4 22 4 2 26 5 15 20 8 3 13 30 18 8 1 +25 28 19 ^ +56 1 20 15 21 18 18 12 16 13 24 9 21 2 28 6 1 23 9 18 27 27 4 9 13 10 8 14 16 +15 12 11 14 21 14 10 11 25 17 17 30 21 13 27 26 26 22 14 13 17 21 19 9 9 20 23 +13 28 ^ +59 1 10 28 24 10 22 27 23 27 8 17 14 6 4 21 26 15 1 8 29 27 6 28 15 3 27 25 25 +14 19 13 29 8 24 2 8 2 4 12 19 11 10 6 26 14 22 24 30 10 11 12 2 12 17 23 8 8 +12 28 12 ^ +56 0 14 28 2 17 4 8 3 26 9 23 21 30 30 20 4 13 28 29 9 3 17 7 19 30 28 1 2 20 9 +12 24 15 30 20 27 3 23 11 6 29 25 23 26 17 20 10 22 15 23 6 25 5 4 30 2 29 ^ +63 1 23 15 27 14 26 1 1 7 19 12 7 6 20 18 14 4 15 17 28 7 11 7 8 9 22 17 12 5 +23 18 25 18 6 12 26 30 12 30 14 3 1 18 10 20 27 21 8 6 24 26 20 11 24 7 2 4 18 +15 14 30 16 19 14 ^ +52 0 27 15 4 19 25 29 29 7 14 18 9 11 9 27 11 15 29 9 28 20 2 30 26 21 17 8 28 +17 22 29 24 8 11 18 29 15 6 7 27 27 17 24 18 23 11 19 8 30 5 24 22 24 ^ +66 1 25 15 28 23 5 10 21 5 8 7 3 10 19 17 6 9 15 29 10 7 4 1 16 21 16 29 13 18 +5 3 8 15 8 21 29 20 5 27 2 13 27 7 7 30 2 18 26 10 2 5 29 21 15 25 26 24 8 12 +20 3 9 10 30 7 12 29 ^ +53 1 30 26 20 11 22 19 27 2 16 10 6 4 24 17 20 25 20 15 8 23 23 20 30 18 16 3 +30 15 26 23 28 7 21 8 7 31 31 14 26 18 3 1 26 28 15 25 11 31 3 25 9 21 30 ^ +67 0 2 6 14 4 9 5 28 8 17 22 1 4 8 7 10 14 19 10 14 8 27 9 24 26 4 30 11 8 19 5 +21 7 2 27 20 16 20 20 22 14 13 16 26 14 10 3 25 22 25 23 21 10 15 15 29 8 13 4 +2 13 22 20 7 4 20 31 23 ^ +65 0 2 2 28 13 19 14 12 23 27 6 2 14 2 22 6 25 30 29 31 13 14 16 31 12 16 30 5 +14 31 11 4 1 1 25 21 13 26 22 21 5 22 14 29 1 21 3 14 30 4 2 29 12 15 23 3 15 5 +1 6 23 22 13 1 14 23 ^ +59 1 25 5 15 6 13 3 22 11 23 31 24 6 5 20 4 14 3 29 8 29 19 7 29 23 25 28 19 11 +15 27 21 14 1 19 20 26 12 7 12 1 18 13 29 28 23 29 14 23 7 1 9 29 24 5 30 18 5 +25 30 ^ +55 1 31 25 13 7 24 25 24 1 12 19 9 7 6 28 20 14 28 21 19 31 20 20 6 24 18 27 24 +4 18 21 1 31 15 1 15 2 27 4 26 25 4 23 19 2 31 22 30 21 22 5 27 12 30 28 31 ^ +62 0 27 15 18 14 25 15 17 7 28 11 28 29 30 1 17 12 10 2 18 20 21 2 11 12 5 4 12 +25 14 5 5 24 22 18 31 15 22 29 11 3 21 31 21 27 3 28 7 10 25 2 15 30 9 30 7 22 +15 9 3 20 24 14 ^ +60 0 28 14 18 9 27 14 22 27 31 10 8 14 7 15 7 20 5 26 1 29 7 17 17 8 3 13 27 18 +8 31 27 28 22 22 17 19 18 18 11 19 13 25 10 19 6 28 4 31 23 10 18 26 31 5 10 13 +12 8 15 27 ^ +60 1 24 22 4 29 22 31 28 20 4 16 21 3 1 15 5 15 6 30 3 29 29 7 27 20 2 20 31 22 +26 9 29 16 4 26 32 17 20 14 28 17 19 6 24 11 26 28 5 18 15 8 16 20 21 4 9 12 4 +8 17 29 ^ +SHS Type 2 Strings +69 1 5 3 11 15 12 24 31 23 1 6 28 2 8 31 6 7 30 5 19 23 12 6 9 31 19 17 24 25 +22 6 12 16 3 7 9 9 11 29 4 11 2 5 13 29 10 12 30 32 18 28 18 27 3 30 4 4 26 6 +13 31 13 2 11 7 24 4 17 29 12 ^ +95 0 21 19 21 23 11 42 36 2 13 4 1 33 22 16 27 9 4 33 16 3 30 15 11 32 13 17 38 +32 9 38 4 36 15 32 27 19 42 18 6 36 22 10 29 12 25 40 15 29 23 28 30 4 8 11 24 +9 10 31 28 43 23 16 29 33 5 40 26 3 19 12 36 43 5 35 37 5 14 11 45 35 16 10 8 +32 4 15 35 26 2 39 22 37 22 30 29 ^ +106 1 18 14 51 2 6 32 51 9 32 50 44 46 51 8 11 53 45 55 16 10 3 52 8 20 20 46 +46 13 32 2 46 50 43 25 54 9 31 29 2 47 15 29 24 45 44 18 37 14 28 39 36 44 47 +16 50 10 44 24 53 35 22 40 20 15 51 22 18 22 42 6 54 49 38 21 7 13 30 16 7 52 +16 22 13 38 7 11 44 33 9 25 13 37 42 14 45 53 30 38 5 25 5 35 38 22 28 53 ^ +127 0 58 35 43 28 5 28 63 8 12 25 9 47 53 29 62 7 37 2 3 48 5 12 55 56 28 35 12 +63 6 58 27 27 48 44 35 14 17 22 56 10 8 1 16 15 42 63 14 51 57 19 41 7 8 56 47 +34 52 22 48 60 43 9 1 52 4 21 49 61 18 50 23 13 46 62 23 45 62 9 56 18 23 31 8 +30 27 36 13 38 4 58 53 47 24 18 41 58 19 12 18 52 42 29 44 45 26 63 34 32 41 64 +15 26 55 19 2 49 6 30 53 13 54 12 53 37 12 37 43 ^ +148 0 60 4 51 47 58 38 17 63 33 23 28 43 12 69 70 33 17 12 50 18 18 36 45 2 67 +4 45 20 4 33 38 29 45 8 22 58 39 71 38 32 53 35 19 53 31 29 51 35 4 63 18 33 26 +47 70 9 64 62 63 30 15 1 35 28 16 40 20 14 50 33 19 38 30 27 55 10 16 46 47 7 +55 12 53 26 56 33 29 55 25 17 48 43 21 43 18 24 63 27 68 46 38 33 35 10 18 11 +27 5 9 58 35 70 36 36 39 47 2 10 66 47 5 18 21 44 71 51 57 3 22 7 56 55 28 25 +14 40 16 24 48 37 66 50 24 45 18 39 53 55 ^ +165 1 15 62 35 29 15 40 19 76 67 4 5 71 46 61 26 8 77 48 1 23 12 60 40 24 44 33 +29 42 73 66 49 61 20 30 1 54 52 42 39 64 23 65 37 24 20 11 26 66 22 77 22 57 7 +38 57 33 61 73 7 64 1 49 35 76 14 27 21 45 68 38 58 73 13 72 47 73 33 8 66 23 +38 4 56 77 47 10 71 13 20 31 41 6 51 3 18 17 61 47 14 48 76 46 28 34 43 1 56 4 +25 7 65 41 1 34 37 23 59 59 27 26 13 15 14 75 60 14 1 28 59 26 65 61 16 23 17 +28 6 19 2 35 49 30 29 48 2 63 73 59 1 3 76 41 11 19 18 43 54 63 67 51 4 9 78 60 +66 ^ +181 0 18 19 84 17 12 10 57 18 77 51 52 16 39 74 49 52 63 38 72 2 15 64 83 62 49 +56 11 26 68 58 83 33 23 50 63 71 53 27 84 22 39 41 52 58 11 64 7 60 45 70 22 5 +73 38 30 30 48 21 75 80 40 21 8 53 9 26 30 34 81 71 71 51 23 75 33 41 23 32 5 8 +66 40 72 40 16 66 45 14 48 34 21 41 27 3 55 27 37 23 41 65 4 57 51 74 22 19 75 +42 16 19 46 16 10 48 20 19 37 41 14 57 9 17 55 38 5 60 7 46 20 43 36 39 52 20 +10 62 45 23 46 7 35 75 29 70 35 36 34 25 12 15 84 26 10 6 71 29 79 33 32 25 59 +76 82 64 58 7 8 19 41 74 2 53 65 24 1 55 51 36 21 79 7 ^ +184 1 60 66 66 6 3 9 73 12 7 40 70 18 71 70 65 51 14 14 27 50 9 87 81 50 22 19 +40 37 16 79 12 34 37 76 82 10 61 7 81 49 67 26 45 82 50 81 63 45 69 31 31 76 51 +9 59 34 51 54 34 83 10 33 51 86 81 82 69 18 8 22 64 19 86 62 58 33 37 17 34 5 +29 83 42 76 50 54 66 39 9 1 36 43 17 65 6 35 56 72 71 83 88 10 1 8 87 22 6 21 +78 25 89 43 62 40 55 85 31 89 74 63 46 28 24 26 31 17 7 8 27 19 12 85 17 20 27 +77 10 2 54 80 17 52 74 76 69 78 11 20 80 4 29 24 85 75 18 39 23 70 83 29 57 67 +72 70 33 4 15 46 42 2 69 13 53 33 69 64 33 64 14 40 69 59 78 54 ^ +193 1 68 43 95 53 38 58 55 28 20 16 67 48 17 86 32 44 68 67 28 16 14 79 25 15 +72 67 50 80 18 30 10 75 1 60 45 87 78 28 95 49 63 70 59 26 6 51 73 60 65 18 26 +8 87 5 58 31 25 57 40 46 78 57 34 78 61 36 66 57 38 80 22 32 68 71 30 74 37 81 +66 77 66 55 2 51 24 93 61 40 68 45 61 12 63 24 89 59 52 72 43 20 20 69 36 40 88 +46 9 62 55 77 84 20 18 6 77 15 52 39 75 3 26 4 85 17 62 29 11 92 46 58 29 59 28 +42 80 71 96 2 49 85 37 63 4 61 14 2 53 87 25 86 6 75 76 93 41 39 93 92 42 56 41 +63 26 28 18 77 11 50 78 79 1 12 12 91 29 13 58 5 56 92 66 59 4 39 47 95 5 5 62 +33 13 80 27 ^ +203 1 35 28 11 7 20 7 17 3 3 30 89 13 65 56 66 63 22 82 16 31 55 56 77 91 91 71 +101 13 10 85 101 95 17 99 98 91 33 14 20 48 32 7 64 29 38 35 25 4 95 23 34 1 85 +81 23 31 96 71 84 50 15 79 47 25 51 45 35 66 19 61 60 9 31 93 64 70 30 42 86 53 +1 71 46 42 22 38 96 10 99 34 76 26 55 73 63 63 97 23 92 81 64 46 1 30 31 35 86 +91 88 64 87 16 37 69 84 94 60 100 3 47 52 8 71 87 57 29 76 43 18 45 46 15 65 12 +44 42 66 60 15 68 19 58 39 62 76 9 92 101 57 32 4 34 15 41 62 32 89 71 43 35 31 +41 21 17 82 33 96 27 62 29 82 57 46 62 15 24 99 37 83 40 52 46 56 80 98 3 91 74 +6 27 7 58 94 10 41 79 97 84 77 74 26 99 35 ^ +212 1 26 101 17 91 45 97 80 59 102 30 68 4 85 9 4 39 16 18 85 70 11 87 62 72 78 +38 3 41 53 82 82 35 18 13 94 64 52 39 77 59 26 9 65 46 64 98 32 29 86 79 16 63 +54 76 56 98 16 98 78 22 72 33 103 104 52 84 12 65 15 85 101 97 84 31 51 26 100 +100 38 80 13 2 78 7 24 44 84 103 27 7 28 16 33 99 25 103 54 14 42 62 87 92 27 +22 42 5 52 100 84 73 72 63 24 48 56 52 23 5 17 76 31 1 95 58 43 60 50 62 30 23 +35 79 20 35 3 72 32 45 51 87 41 84 27 79 77 70 102 15 54 15 100 8 52 69 105 3 +30 84 42 93 66 89 69 74 24 33 42 97 4 38 99 106 13 93 6 106 74 100 54 45 21 59 +56 37 9 50 32 75 79 31 77 9 61 1 8 68 6 60 81 7 100 99 14 61 48 25 73 26 70 72 +94 34 ^ +233 0 11 98 110 88 35 110 35 64 49 88 93 28 85 6 78 65 90 52 24 97 51 39 51 59 +23 1 3 49 33 11 78 27 35 55 64 5 102 4 70 25 56 58 38 66 11 31 96 66 104 59 41 +86 58 29 79 41 40 72 51 12 92 34 52 44 69 104 21 97 89 96 48 21 4 61 40 28 67 +34 23 85 44 22 62 52 33 84 23 30 73 74 4 79 12 81 47 80 53 47 89 40 19 80 62 34 +61 29 41 95 43 1 70 63 55 53 18 19 13 48 10 19 89 49 4 52 53 56 76 10 8 104 77 +15 28 38 75 109 3 85 90 8 40 8 93 90 43 39 14 60 17 36 78 56 105 80 35 75 36 58 +82 50 100 98 45 74 13 66 95 72 71 95 34 14 98 72 33 38 37 52 6 14 107 59 3 29 +61 67 98 92 5 93 17 98 36 87 41 75 71 57 88 17 25 91 84 3 58 20 92 69 51 50 36 +31 14 25 18 30 18 1 41 104 30 82 59 87 70 34 96 28 47 62 81 103 48 ^ +234 1 63 90 108 108 102 64 82 88 4 111 76 97 22 1 108 41 34 91 33 20 25 24 26 8 +83 11 31 7 85 109 106 4 105 85 68 28 33 99 53 8 16 12 11 74 17 83 66 70 16 30 9 +67 68 34 24 81 47 92 72 47 37 33 38 92 17 8 28 88 22 62 69 32 89 75 3 72 96 85 +13 105 24 38 37 94 115 83 72 108 114 24 93 76 103 60 99 102 9 43 10 59 95 46 33 +93 15 26 69 44 2 86 107 55 45 61 65 92 66 9 55 39 70 83 29 98 67 13 111 15 20 +31 62 8 2 51 20 19 33 44 14 115 71 112 97 10 41 28 53 51 26 57 15 38 98 55 106 +22 56 31 50 95 107 110 84 70 10 108 96 73 100 25 36 55 88 71 63 96 30 90 96 79 +22 7 30 23 28 59 89 8 51 99 47 86 34 18 43 65 98 104 107 49 7 79 71 8 57 21 29 +80 2 74 78 44 57 9 61 22 13 68 52 91 74 98 43 30 58 68 95 101 72 102 76 42 99 +61 ^ +249 0 27 117 45 119 80 2 59 52 8 76 20 94 102 69 96 42 46 106 67 9 110 89 71 69 +34 31 15 85 16 29 100 82 37 62 68 95 108 44 23 114 34 36 56 93 11 30 96 12 31 +67 14 114 14 66 70 30 81 46 53 119 85 6 104 47 92 72 70 5 70 15 115 68 105 33 +97 13 85 106 14 61 29 22 86 45 57 69 91 38 38 28 66 13 60 95 103 3 15 5 113 38 +23 62 5 65 94 107 73 104 37 47 102 117 3 78 35 7 95 56 78 45 52 28 46 43 37 32 +53 19 55 29 47 97 76 115 83 71 11 45 62 73 99 116 2 24 116 7 28 41 2 29 37 52 +23 5 118 79 31 57 89 61 24 101 78 50 93 73 41 7 33 45 47 24 1 48 73 36 3 25 87 +46 28 108 54 68 53 67 119 28 36 118 104 42 88 27 112 4 74 85 1 63 39 97 71 74 +75 76 10 49 12 79 11 50 103 118 94 117 118 37 27 12 94 60 28 51 47 82 110 17 15 +105 23 52 43 12 21 22 81 41 12 74 90 42 108 117 98 67 4 69 85 ^ +243 0 76 81 26 101 13 68 62 106 87 19 98 32 81 63 79 93 31 121 123 75 52 11 66 +41 54 87 38 5 104 62 51 38 55 29 31 120 44 16 48 94 46 105 91 66 78 27 43 6 64 +2 55 79 75 84 113 22 4 113 109 31 33 17 96 11 29 63 98 103 107 116 34 14 9 95 +38 18 51 75 33 109 118 55 66 4 76 7 75 70 82 74 23 1 26 69 40 112 99 47 65 31 +70 119 52 103 88 85 86 28 16 12 76 25 22 78 64 21 86 27 61 77 72 108 2 18 106 +119 121 54 16 85 72 2 73 26 88 66 60 80 35 24 117 63 24 44 67 52 122 119 33 72 +16 99 98 69 54 19 42 28 53 114 32 117 81 100 57 49 123 56 21 68 80 53 95 1 45 +95 107 98 87 1 27 24 99 116 16 67 1 113 91 84 25 40 25 72 3 28 90 87 112 80 16 +117 45 77 36 90 105 59 88 122 64 108 108 71 98 18 50 115 93 105 77 35 6 46 55 +47 102 4 26 87 111 120 81 113 4 57 105 3 84 94 115 61 73 ^ +255 1 91 47 51 9 57 9 55 94 61 61 68 46 107 6 35 81 114 78 96 74 14 89 73 67 67 +69 113 107 11 98 113 109 20 92 17 67 70 88 57 10 124 9 60 122 93 91 45 7 15 24 +51 5 98 115 24 49 90 104 117 66 128 94 64 80 12 43 91 46 111 59 58 77 30 14 88 +60 123 68 41 44 68 40 104 118 41 43 93 90 105 92 16 127 26 54 125 114 79 71 24 +48 21 25 118 40 103 49 91 44 67 65 25 119 109 18 48 23 69 112 38 61 64 87 84 +104 119 110 122 92 22 1 8 83 34 100 32 62 41 46 112 34 102 76 56 39 4 127 30 13 +19 110 124 7 16 128 95 4 124 11 104 116 126 49 95 3 55 96 70 90 101 4 122 96 75 +118 39 128 99 92 18 42 20 87 83 35 75 111 61 67 71 28 101 9 56 34 105 95 71 23 +73 71 26 57 15 23 76 55 99 89 128 98 117 68 43 88 62 38 62 39 2 83 36 15 26 60 +128 96 73 74 10 1 12 42 22 2 77 33 33 32 57 13 14 82 57 12 39 3 58 80 14 87 85 +44 69 109 119 ^ +283 0 102 55 53 41 60 88 25 67 58 76 44 22 68 118 108 40 95 96 81 90 85 28 77 +18 11 37 72 93 60 110 124 119 95 131 91 37 109 126 8 73 69 72 80 17 83 5 76 20 +32 15 10 1 103 18 22 116 98 9 51 104 102 44 33 15 12 24 31 89 1 6 28 101 8 64 +72 106 30 5 52 89 111 39 108 64 85 17 57 124 22 105 78 115 3 40 108 66 108 77 +128 103 44 35 38 13 95 10 111 63 98 117 61 51 126 69 96 70 70 59 39 13 97 33 +112 2 77 7 123 70 83 29 66 67 49 79 19 104 115 14 60 2 55 40 71 33 28 114 51 91 +17 46 45 128 57 87 62 25 115 38 50 55 90 74 8 51 102 79 43 94 36 122 94 12 41 +36 25 104 91 24 7 99 80 30 126 32 63 122 107 114 27 28 79 41 12 35 51 115 122 +70 22 79 65 2 88 27 17 59 15 23 44 57 5 65 6 26 78 80 125 93 84 100 45 22 129 +68 36 111 74 118 11 50 42 120 47 21 8 86 112 26 67 60 99 45 93 47 8 38 59 52 56 +124 20 82 18 117 24 18 46 106 19 117 26 41 47 45 130 7 15 1 4 5 100 10 85 50 44 +11 48 92 119 108 42 118 125 ^ +272 0 8 61 99 70 96 20 87 123 134 82 22 2 110 118 33 86 5 7 5 94 56 15 60 96 54 +13 22 55 99 4 25 105 17 37 69 10 38 117 117 30 70 13 9 109 115 62 94 52 66 117 +100 135 7 75 23 5 81 110 31 118 29 1 62 11 41 88 109 119 102 37 3 30 123 47 31 +56 134 29 124 116 118 99 21 56 77 91 23 37 135 81 44 51 67 95 51 133 30 57 67 +116 122 48 100 7 132 97 106 69 93 4 95 125 102 103 119 81 57 133 96 37 118 50 +117 113 81 127 17 45 103 32 121 129 60 43 65 127 30 36 132 110 52 53 35 71 12 +76 22 72 130 112 99 76 26 21 73 63 63 97 23 58 115 132 114 1 132 31 35 18 23 54 +30 53 118 37 35 84 94 60 100 3 47 18 110 105 87 57 63 76 43 52 45 46 49 65 12 +10 42 66 60 117 34 19 92 5 28 76 9 126 101 125 32 38 34 15 7 62 32 21 3 43 69 +31 109 123 51 116 135 130 129 130 63 14 57 80 62 15 126 31 105 83 108 120 80 +124 46 98 105 91 6 6 27 7 58 128 78 7 79 63 84 77 74 128 65 61 95 121 17 24 123 +117 51 122 ^ +284 0 44 71 43 20 126 58 53 47 98 18 19 119 93 29 70 39 94 112 44 115 135 98 82 +10 67 29 102 113 68 80 19 75 1 91 114 87 80 7 40 37 86 120 16 104 136 117 82 +138 32 65 114 119 137 121 8 12 46 126 26 119 73 130 60 76 113 100 14 133 26 116 +34 120 80 95 84 53 15 24 44 51 4 10 23 77 24 99 66 37 54 63 42 136 21 34 76 5 +17 128 101 1 59 40 113 112 32 97 31 93 105 79 91 18 39 1 103 132 51 68 124 111 +13 97 43 128 69 84 85 72 15 12 26 87 16 16 92 101 13 77 4 118 89 103 56 42 16 +60 44 39 126 46 18 83 93 41 105 3 82 106 115 91 6 4 54 115 15 120 109 113 48 41 +9 95 20 62 67 105 111 25 132 7 116 46 138 44 83 61 124 131 35 107 6 109 81 114 +67 41 137 77 56 74 73 34 12 14 69 52 11 98 47 54 83 81 6 1 15 88 35 139 80 83 +49 89 27 47 130 92 133 87 51 112 76 49 109 49 57 93 73 22 117 50 64 58 97 139 +36 131 111 133 58 33 8 88 55 38 90 46 30 118 57 29 82 74 41 117 38 46 94 92 5 +105 15 117 70 103 68 60 120 48 21 110 85 40 81 66 ^ +291 0 46 113 52 134 79 74 64 57 18 23 9 52 8 16 103 57 138 59 59 65 92 2 7 130 +92 8 34 40 86 131 140 100 112 4 42 1 110 108 43 37 15 67 19 35 94 61 130 98 35 +88 34 65 104 56 126 118 50 87 10 81 109 90 86 118 32 6 114 88 39 38 39 62 3 12 +134 72 137 35 75 81 115 106 140 112 11 123 41 103 45 95 84 71 107 13 26 110 96 +62 16 109 84 59 53 38 27 8 28 13 32 137 17 138 41 122 36 99 65 99 83 36 112 29 +49 70 96 126 136 131 116 3 18 17 126 142 14 37 141 141 123 42 13 20 83 42 139 +83 54 49 58 42 7 137 29 48 16 121 127 34 52 140 106 128 58 36 124 83 24 69 54 +61 112 17 6 95 97 24 57 86 124 59 71 119 67 1 109 54 68 49 57 132 32 5 71 113 +40 80 104 75 106 133 31 126 130 104 62 9 39 44 66 116 141 135 96 132 19 41 121 +126 124 77 8 4 60 82 6 101 124 89 51 123 48 40 85 77 21 112 10 69 66 115 87 16 +108 30 84 65 80 103 32 131 134 73 47 10 63 39 50 93 37 135 114 69 48 34 58 23 +27 133 37 9 40 98 41 115 99 70 83 29 42 67 133 55 79 80 91 122 12 2 115 112 47 ^ +293 1 33 13 99 138 1 42 89 118 87 113 99 12 134 142 100 38 5 55 75 14 110 108 +42 64 130 79 138 62 64 69 57 11 123 25 59 16 111 94 24 65 30 51 119 48 107 92 +84 69 28 136 143 54 20 6 70 47 142 64 4 65 59 73 99 134 146 102 125 116 57 137 +137 72 48 128 78 5 80 63 54 85 30 22 129 68 21 21 74 28 128 107 27 60 2 93 95 +71 37 11 37 15 39 102 3 104 65 80 59 52 113 34 20 67 60 27 81 135 46 106 106 +102 68 128 17 15 100 124 15 43 136 122 100 67 142 35 14 53 120 2 89 93 99 73 9 +122 39 77 15 96 90 43 79 134 60 92 105 55 96 31 119 77 97 72 23 140 38 30 43 83 +136 88 107 117 72 109 118 58 91 119 73 95 100 59 138 123 54 49 143 50 133 66 +106 45 80 88 42 93 5 59 77 101 74 110 104 40 92 19 77 76 86 102 129 3 144 101 +139 134 56 90 18 91 94 85 55 10 137 11 58 1 107 113 70 22 7 56 29 143 111 8 46 +45 116 122 129 89 7 121 53 95 14 49 118 62 125 91 37 97 15 35 100 63 140 63 50 +51 58 26 127 6 45 59 102 121 114 85 141 135 10 72 19 106 66 66 41 53 13 38 1 21 +103 50 108 46 119 ^ +297 1 46 31 132 112 28 63 124 97 129 43 40 72 99 107 132 137 96 139 99 145 121 +144 118 37 81 39 94 60 55 109 47 109 110 75 42 12 139 137 43 128 106 107 19 126 +12 101 148 127 15 117 125 125 62 96 13 76 70 96 101 110 138 8 95 76 143 17 32 +97 79 149 39 31 94 123 21 41 135 55 84 70 33 135 118 50 62 121 81 1 45 144 93 +60 5 64 137 8 105 91 82 67 27 113 119 53 18 98 79 48 84 32 135 128 5 1 20 76 17 +85 108 72 36 141 140 49 150 105 104 3 149 14 54 18 148 64 49 125 37 28 28 101 +22 104 91 32 82 117 12 114 69 58 2 58 115 9 108 47 59 65 14 92 7 4 86 98 16 82 +92 95 38 94 10 10 48 97 104 66 115 97 142 115 122 119 40 97 16 32 47 34 88 89 +26 50 12 76 80 51 40 9 133 24 44 40 122 84 108 22 142 140 99 44 15 54 8 42 125 +150 130 21 79 124 62 46 119 15 29 91 57 150 42 138 71 61 68 80 114 6 1 70 121 +18 35 113 56 87 86 10 73 14 29 41 72 89 1 133 87 101 123 59 90 142 77 133 52 78 +48 34 138 134 27 17 60 131 147 61 93 148 39 132 49 62 71 36 91 4 139 49 100 120 +43 113 144 30 94 73 127 40 125 ^ +313 1 35 97 95 76 105 88 32 138 30 69 61 40 47 21 107 6 39 81 114 53 125 53 147 +14 4 73 146 96 98 13 136 11 98 117 138 153 67 146 71 99 88 7 139 24 13 35 47 97 +145 74 36 119 3 51 84 48 119 53 49 15 79 17 120 103 148 64 30 41 97 120 75 111 +63 58 131 134 18 13 10 48 18 16 48 43 15 54 18 41 47 122 144 80 92 145 77 1 33 +89 54 46 78 48 21 54 43 40 53 24 16 73 42 94 29 44 34 151 152 23 123 12 142 140 +43 37 88 29 19 35 72 96 151 130 62 112 34 36 91 120 50 112 138 2 105 60 68 137 +131 5 17 19 139 74 11 120 78 149 58 128 15 104 16 126 78 20 57 134 71 49 90 76 +108 126 100 54 68 39 132 153 42 147 146 124 62 87 35 75 61 65 46 100 82 105 113 +31 63 5 95 54 71 77 127 150 80 36 144 2 130 59 74 39 3 152 121 122 18 117 12 +117 141 118 135 62 36 69 5 39 53 150 52 153 143 30 66 96 126 131 56 137 8 7 86 +142 14 7 111 141 93 136 137 134 43 12 89 23 44 9 152 146 121 97 19 38 110 91 67 +14 32 110 66 68 8 130 84 73 118 59 24 41 72 121 150 55 37 138 27 104 66 124 9 +51 109 47 125 109 148 8 29 47 72 146 149 61 93 10 20 54 15 76 133 125 106 110 +67 ^ +330 0 23 9 26 136 27 51 115 122 44 106 6 146 108 113 85 51 8 96 47 56 137 62 59 +89 143 71 140 14 85 156 139 99 154 30 53 115 35 147 108 148 58 52 28 103 19 92 +95 152 152 10 11 13 155 67 11 83 101 69 153 152 45 141 14 120 129 140 119 59 2 +89 73 70 83 29 16 67 81 29 1 54 65 96 117 2 37 47 128 33 3 89 108 98 139 49 78 +27 103 39 119 94 132 90 38 132 55 65 131 90 58 2 54 100 69 118 22 44 19 7 148 +93 25 29 123 81 64 131 55 30 1 89 38 97 82 64 9 28 86 123 151 10 133 40 154 102 +4 111 65 9 63 59 124 116 72 105 76 57 137 97 32 145 108 78 112 50 43 34 75 20 +22 129 68 11 118 74 125 118 57 17 20 129 53 65 61 144 1 17 142 156 52 100 54 15 +20 59 52 63 131 20 57 124 31 125 46 106 76 92 8 98 154 152 80 114 15 140 136 +112 100 17 92 25 151 150 80 99 69 83 49 43 156 102 19 57 122 96 30 3 39 134 40 +32 75 5 76 127 138 99 17 57 52 150 130 18 127 33 23 116 107 78 77 77 42 69 68 +48 41 69 33 75 40 49 128 103 4 146 93 10 83 66 96 152 30 38 12 33 5 39 47 41 34 +60 74 20 42 156 67 46 56 102 89 3 124 81 99 104 56 50 8 61 74 55 15 87 108 28 +138 47 93 60 2 124 46 126 103 91 145 36 25 116 122 51 ^ +322 0 75 7 107 158 81 105 154 90 20 125 77 114 69 92 7 58 21 98 154 50 128 149 +117 127 153 45 3 18 121 86 29 71 79 101 2 5 22 143 10 27 53 146 157 148 112 33 +22 80 123 24 147 1 112 82 159 63 74 97 109 33 151 32 89 87 132 117 46 129 59 +115 91 114 118 37 21 9 94 60 25 89 47 79 110 55 12 143 99 87 43 88 56 57 160 76 +12 71 128 77 146 117 95 105 42 66 3 76 20 76 101 100 118 149 45 26 143 148 32 +57 39 129 19 31 84 123 1 152 135 5 54 30 13 125 68 30 62 101 51 142 5 94 83 20 +116 24 107 109 105 91 42 17 27 93 69 3 139 68 79 38 84 2 85 128 126 122 131 46 +17 35 98 42 26 111 100 29 120 55 84 114 109 145 14 18 138 14 9 85 7 18 129 91 2 +94 51 133 82 87 123 64 39 8 103 38 75 110 78 7 9 45 115 42 138 135 86 78 16 62 +52 75 159 54 151 121 149 77 74 16 85 47 102 105 82 119 10 67 137 153 148 135 28 +49 26 151 153 36 80 11 130 113 24 44 30 102 24 58 133 122 140 99 24 156 54 119 +42 115 140 90 132 19 94 2 157 99 136 19 71 7 130 153 108 51 21 58 70 74 137 1 +40 111 149 5 103 6 27 76 141 23 125 140 1 72 29 152 103 87 51 93 29 80 132 77 +123 153 68 159 14 98 114 158 121 158 81 131 ^ +322 0 35 93 109 125 119 10 10 19 135 26 4 74 135 35 120 129 113 92 17 29 47 88 +14 159 149 87 45 36 75 68 22 138 20 59 61 144 151 11 107 6 153 81 114 43 85 157 +97 148 118 73 126 56 58 137 96 11 98 67 98 103 57 146 21 59 88 151 139 148 127 +25 17 47 115 34 160 109 107 51 64 28 69 13 49 149 69 141 90 93 118 64 10 1 67 +80 35 111 13 58 101 124 132 147 154 18 162 6 162 33 5 34 142 41 161 82 114 70 +92 145 57 155 137 114 79 44 36 48 48 21 14 13 40 33 14 150 33 32 54 143 14 4 +101 142 23 93 136 132 120 147 17 38 163 143 5 52 46 151 130 32 72 34 124 150 51 +100 112 128 126 65 10 28 87 81 159 131 19 99 54 125 110 58 119 28 78 129 104 +140 126 38 154 27 114 61 153 90 66 98 76 50 158 48 39 82 123 22 147 136 114 52 +37 35 75 41 15 150 60 52 55 103 21 23 129 95 24 71 47 97 130 50 140 144 106 100 +9 64 19 117 122 71 92 8 77 156 97 121 98 85 2 36 39 109 143 23 120 156 133 93 +154 36 66 116 131 160 127 162 161 46 142 14 141 81 141 63 86 117 104 3 146 39 +127 34 133 102 106 91 57 9 28 60 61 7 158 12 80 26 8 122 80 44 63 68 49 158 21 +32 81 150 15 141 108 161 64 46 124 123 31 99 27 105 109 98 112 144 ^ +336 1 34 161 107 149 48 67 138 109 156 104 37 133 60 80 84 81 160 9 16 96 164 1 +95 112 4 86 163 116 98 103 55 31 8 56 37 36 127 32 9 89 103 31 100 161 85 106 +119 89 154 43 115 162 137 108 128 38 42 155 103 9 62 65 102 122 10 138 160 125 +47 158 43 91 69 123 132 35 121 4 110 89 130 69 29 139 69 53 70 83 29 163 67 41 +9 108 34 45 76 87 2 144 164 98 33 160 79 78 48 89 9 38 134 93 146 79 54 122 80 +38 112 55 55 101 70 8 129 44 70 59 98 149 24 136 124 138 63 25 166 83 51 34 91 +45 30 118 59 28 87 72 44 116 28 36 103 101 113 10 114 62 111 71 65 126 53 19 +114 86 42 85 36 57 137 57 159 95 88 78 72 20 23 14 65 10 22 129 68 1 68 74 75 +108 7 7 147 109 13 35 51 104 158 164 122 126 2 50 4 132 127 59 52 13 81 20 47 +107 74 148 115 46 106 46 82 115 68 144 142 60 104 15 90 136 102 100 134 42 15 +141 100 40 49 49 73 166 13 156 82 166 37 82 96 137 130 166 134 20 139 45 122 56 +107 98 79 124 17 32 130 120 165 77 23 130 96 67 68 47 37 12 29 18 38 158 19 160 +55 147 39 118 83 121 96 43 137 33 66 86 112 147 155 149 140 5 19 17 148 161 10 +44 159 146 57 16 26 102 49 3 104 61 59 74 56 10 165 31 54 25 142 157 37 58 165 +128 154 73 50 149 94 137 ^ +330 1 61 51 65 132 23 169 116 122 14 66 7 98 131 72 69 127 72 163 125 68 69 51 +47 159 31 164 71 118 50 83 113 81 127 153 45 137 134 121 68 163 26 43 65 127 +166 138 98 144 18 53 137 139 148 76 158 4 62 78 167 102 144 94 55 141 63 29 97 +91 24 115 166 80 69 132 99 1 120 23 88 64 87 118 37 137 152 94 60 168 71 47 52 +110 37 155 125 63 42 43 52 11 12 151 31 12 44 110 32 128 117 68 87 24 39 164 76 +145 58 101 91 100 140 151 143 130 32 21 3 111 1 31 75 123 153 116 135 130 27 +164 165 116 23 12 62 83 24 133 139 49 74 154 80 158 80 64 105 91 6 142 27 75 24 +128 112 41 79 29 84 145 40 128 99 95 95 19 17 160 89 15 17 84 64 11 93 10 66 78 +73 127 148 18 129 139 143 49 150 9 84 82 154 85 15 88 82 60 87 19 12 133 58 20 +39 65 51 141 134 27 70 167 120 117 86 60 16 44 16 57 132 18 142 85 104 59 47 +141 58 2 66 96 46 119 153 40 110 126 103 90 144 13 26 106 144 80 145 134 103 95 +24 44 21 84 140 13 97 104 140 99 6 147 54 83 42 106 131 54 96 135 67 118 121 81 +109 10 53 132 112 117 81 33 155 49 61 38 119 1 13 102 131 148 94 131 143 67 123 +148 89 104 135 72 145 152 76 87 6 66 2 71 123 77 114 108 59 123 166 62 96 140 +94 149 116 169 ^ +349 0 125 17 93 82 80 110 156 147 156 99 154 4 29 90 163 120 84 113 56 8 157 29 +61 169 141 113 78 48 50 13 138 11 50 61 99 106 2 107 6 117 81 114 34 49 112 52 +130 82 73 108 20 22 110 60 11 98 22 62 58 48 146 149 23 88 142 139 121 91 16 +163 2 88 171 133 100 62 51 46 10 24 150 49 131 60 114 63 84 91 64 165 138 40 44 +172 111 141 58 74 115 96 129 145 164 153 170 126 24 169 16 115 41 125 46 87 61 +92 145 39 155 92 78 70 35 27 21 48 21 151 159 40 15 5 132 170 23 18 107 160 150 +56 133 23 66 109 123 102 102 172 166 145 116 151 34 1 151 130 5 36 34 97 114 15 +82 128 112 119 99 29 138 165 42 36 159 95 19 63 36 89 101 40 92 1 33 93 104 113 +126 2 136 96 52 108 90 57 89 31 5 113 30 39 37 96 4 147 127 105 43 165 35 75 23 +143 105 24 25 10 94 12 160 102 95 170 71 20 70 112 23 95 144 61 73 137 55 1 81 +95 26 65 172 41 147 79 103 80 40 121 36 12 64 98 169 93 111 115 48 127 9 39 107 +131 115 118 162 161 10 142 14 123 54 141 36 41 99 77 140 128 167 82 25 106 57 +70 64 21 19 15 34 126 149 167 53 163 127 86 35 8 54 23 40 140 3 169 45 150 152 +96 81 143 28 28 124 87 13 90 9 87 109 53 67 164 28 131 89 149 42 55 126 79 132 +74 19 133 30 68 72 75 148 9 10 72 152 144 83 106 153 74 163 98 152 ^ +375 1 94 28 13 8 20 28 18 118 5 140 89 67 171 64 152 85 61 101 80 154 149 34 +115 135 128 108 110 20 33 128 103 35 38 57 95 10 111 151 98 29 149 7 82 69 96 +114 26 103 171 101 53 121 24 2 121 51 35 70 83 29 154 67 5 167 63 16 27 58 60 2 +99 128 71 33 160 70 51 3 44 149 2 89 84 101 43 18 113 71 38 94 55 46 74 52 139 +102 35 43 50 80 122 6 100 88 129 36 25 148 47 24 7 55 36 30 82 32 19 78 63 26 +71 28 167 85 56 167 95 159 78 26 66 35 65 90 44 159 105 59 15 67 57 137 21 132 +50 70 78 36 169 5 172 56 1 22 129 68 168 23 74 30 99 138 174 120 91 153 8 42 68 +158 155 104 99 133 5 135 96 82 59 52 144 36 20 38 62 29 112 106 46 106 19 73 70 +41 135 133 42 95 15 45 136 93 100 98 173 6 132 55 4 4 31 64 130 162 156 64 157 +19 46 96 92 103 139 134 2 94 18 86 38 89 62 61 79 157 14 112 111 156 32 14 85 +78 31 59 20 1 161 169 149 29 122 150 133 37 102 30 109 65 85 51 174 110 164 66 +77 76 111 119 131 95 5 1 166 103 134 141 17 158 123 137 48 165 175 102 13 3 86 +43 23 47 56 150 165 4 36 174 115 157 168 13 147 119 109 55 41 140 67 27 31 27 +53 126 17 163 116 122 160 60 7 92 113 66 45 109 60 151 125 62 39 39 17 153 13 +152 53 94 50 53 89 57 127 153 45 119 104 121 56 145 172 19 41 103 166 108 68 +126 12 53 131 127 148 52 134 168 50 48 155 72 132 82 37 129 63 175 160 ^ +366 1 73 15 79 139 71 51 132 81 135 111 166 61 37 60 118 37 92 134 94 60 150 53 +47 25 110 19 137 107 27 176 43 16 145 146 142 165 12 17 92 166 110 117 41 69 6 +12 164 76 109 40 101 82 82 131 134 115 143 112 32 164 146 93 162 31 66 123 144 +80 135 94 137 156 107 157 173 62 65 176 124 112 4 65 127 44 131 53 19 105 91 +149 106 27 57 158 92 85 14 79 20 84 127 174 128 72 68 59 171 17 124 80 167 8 57 +28 172 66 144 48 42 37 109 121 18 120 103 116 13 132 39 73 145 76 158 43 82 33 +51 153 164 97 13 2 3 20 24 114 98 9 25 131 102 99 86 42 16 26 159 39 105 161 +133 49 59 41 20 105 31 136 30 87 10 119 135 13 83 99 58 45 99 156 26 61 135 143 +80 118 107 76 77 24 44 12 66 95 147 61 86 140 99 167 138 54 47 42 97 122 18 60 +90 40 73 85 63 82 1 35 96 94 81 54 15 128 40 52 2 101 1 165 93 113 130 85 95 98 +58 105 112 53 68 108 72 100 152 49 87 140 39 154 62 114 77 105 63 50 87 157 26 +78 122 67 140 71 170 119 5 93 64 50 104 144 129 138 75 130 4 178 60 139 120 54 +113 32 2 133 17 43 163 129 89 72 149 155 30 38 7 138 5 44 61 69 76 175 107 6 93 +81 114 28 25 82 22 118 58 73 96 175 177 92 36 11 98 171 38 28 42 146 125 178 88 +136 139 103 67 10 151 151 70 153 115 94 32 51 34 177 173 132 49 119 54 96 45 78 +73 64 159 120 22 20 154 111 117 58 56 109 72 143 ^ +372 1 136 146 144 170 90 15 169 180 88 41 89 10 60 52 92 145 21 155 47 42 61 26 +18 176 48 21 124 141 40 179 178 114 143 14 164 71 142 132 11 124 23 39 82 114 +84 57 163 130 127 89 133 16 138 151 130 160 34 70 78 161 64 92 112 110 72 175 +102 138 179 173 159 59 19 27 18 53 92 22 65 156 170 57 104 86 126 148 118 155 +78 43 63 90 48 80 168 142 68 12 39 174 69 168 147 118 96 34 129 35 75 5 107 60 +170 180 147 85 3 133 75 95 152 71 175 43 94 178 50 144 16 46 101 46 165 45 68 +163 38 172 5 138 61 85 62 177 76 36 167 19 53 151 66 66 97 3 100 164 12 98 131 +70 109 162 161 156 142 14 105 27 141 9 178 81 50 113 110 131 37 16 79 12 34 37 +167 173 10 152 7 81 140 158 26 136 82 50 172 154 45 160 31 122 167 142 9 150 +125 51 54 125 174 10 124 51 177 81 173 69 109 8 22 155 19 86 62 149 33 37 108 +34 96 29 174 133 167 50 54 66 130 9 1 36 134 108 65 97 126 56 163 71 83 88 10 1 +8 178 22 6 112 169 116 89 43 153 40 146 85 31 89 74 154 137 28 115 117 122 108 +98 8 27 110 103 176 17 20 27 77 10 93 145 80 17 143 165 76 69 78 102 20 91 171 +95 29 115 176 166 109 39 23 70 83 29 148 67 163 161 33 4 15 46 42 2 69 104 53 +33 160 64 33 155 14 131 160 59 78 71 19 176 107 65 38 82 55 40 56 40 115 84 29 +25 44 68 104 176 76 64 123 18 25 136 23 6 171 31 30 30 58 14 13 72 57 14 41 177 +^ +363 0 135 69 16 167 79 143 46 178 26 3 65 58 36 135 97 35 175 51 152 57 137 173 +108 10 54 78 4 153 173 164 48 177 22 129 68 168 167 74 174 91 106 174 96 75 129 +168 34 36 158 147 88 75 101 149 103 64 42 59 52 112 180 20 30 22 173 80 98 46 +106 179 65 30 17 127 125 26 87 15 5 136 85 100 66 141 182 124 15 156 148 15 56 +98 146 156 48 149 3 14 96 52 79 115 134 170 54 178 54 22 73 30 45 39 133 182 96 +103 148 176 6 45 62 183 51 180 153 145 145 117 21 90 118 109 21 62 22 101 49 53 +11 142 86 132 66 69 44 79 87 115 55 5 169 150 63 110 109 177 150 91 129 40 149 +159 102 165 3 70 27 175 23 56 126 165 164 20 158 91 157 136 157 131 111 69 39 +33 132 43 19 175 179 37 118 9 155 116 122 128 52 7 84 89 58 13 85 44 135 125 54 +183 23 161 145 173 136 29 62 50 13 57 25 127 153 45 95 64 121 40 121 140 171 9 +71 166 68 28 102 4 53 123 111 148 20 102 160 34 8 139 32 116 66 13 113 63 143 +97 63 10 59 124 66 41 132 71 115 106 151 46 22 45 118 37 67 124 94 60 140 43 47 +10 110 9 127 97 7 156 43 180 125 126 137 145 12 2 82 146 100 117 26 59 180 181 +164 76 89 30 101 77 72 126 114 95 143 102 32 149 131 83 157 31 61 123 139 60 +135 74 169 122 151 102 137 168 62 55 166 119 97 163 60 112 24 116 38 178 105 91 +134 86 27 47 138 72 70 183 79 15 84 117 154 128 57 53 39 161 88 ^ +393 1 92 72 151 33 183 164 42 112 32 10 5 93 97 18 112 71 92 168 116 179 186 65 +137 68 134 3 82 9 19 121 148 65 160 173 158 167 90 66 180 172 99 86 83 86 26 16 +10 135 23 81 137 125 17 19 25 183 73 7 104 185 79 165 119 119 176 59 75 18 5 59 +132 26 21 127 119 80 94 83 52 61 24 44 4 50 55 115 29 70 140 99 159 130 54 15 +42 89 114 173 28 50 16 33 53 47 58 180 19 64 78 49 30 186 104 32 44 157 85 1 +149 85 97 114 77 63 58 50 89 80 21 36 84 72 60 152 25 87 108 15 138 54 106 77 +97 23 42 55 149 181 62 106 43 132 31 138 111 176 93 40 10 96 128 105 114 43 98 +4 146 20 107 120 14 113 181 101 1 19 155 113 57 64 117 131 6 22 186 138 184 36 +61 29 36 175 107 6 61 81 114 20 180 42 169 102 26 73 80 151 153 68 4 11 98 139 +6 175 34 146 93 154 88 128 139 79 35 2 135 119 46 129 91 86 179 51 18 169 141 +108 49 103 46 72 21 70 49 64 151 96 185 175 130 111 85 58 32 101 40 101 131 136 +139 170 70 10 169 175 73 41 69 177 45 47 92 145 11 155 22 22 56 21 13 166 48 21 +109 131 40 174 178 104 128 9 149 51 132 122 173 119 23 24 67 109 74 32 158 110 +117 74 123 6 118 151 130 150 167 34 55 58 146 54 72 112 105 57 160 82 123 159 +153 159 39 19 7 8 33 87 12 50 146 150 37 104 71 126 133 108 145 68 38 38 90 43 +75 148 122 43 2 39 154 54 163 147 113 91 29 109 35 75 182 87 35 155 170 127 80 +185 118 60 95 142 71 165 28 84 168 25 144 178 31 81 41 160 25 53 143 ^ +381 1 14 172 163 130 45 69 46 145 36 36 151 169 13 135 42 26 81 153 76 148 178 +90 131 30 101 162 161 132 142 14 89 3 141 175 146 65 26 89 94 99 187 8 55 162 2 +13 143 173 2 120 173 41 132 150 2 112 42 18 140 130 37 128 23 106 159 118 167 +150 101 11 30 109 150 184 124 19 169 73 165 53 109 158 172 147 11 46 38 149 25 +21 92 184 64 179 158 133 135 34 38 58 114 9 183 4 118 76 49 89 102 40 163 47 75 +80 176 175 8 154 14 180 104 153 84 89 11 129 8 138 85 181 73 66 154 121 20 115 +93 114 108 82 182 19 86 103 176 183 186 177 53 10 69 137 56 1 135 141 68 69 54 +86 12 75 171 87 187 107 144 150 93 23 7 70 83 29 140 67 139 153 183 178 189 30 +18 2 29 72 29 33 160 56 9 123 164 107 136 19 70 31 177 152 99 57 38 66 55 32 32 +24 83 60 21 1 36 52 80 168 44 32 115 184 25 120 181 172 155 189 22 30 26 180 5 +64 49 188 1 28 111 57 176 167 67 131 22 160 186 169 65 34 30 117 91 17 163 39 +134 57 137 155 90 170 42 78 170 141 167 158 42 177 22 129 68 168 143 74 150 85 +82 174 78 63 111 156 28 12 158 141 76 57 77 125 79 40 12 59 52 88 156 20 24 182 +149 56 92 46 106 167 59 189 121 119 14 81 15 165 136 79 100 42 117 182 118 175 +138 124 3 50 74 134 156 36 143 181 180 96 22 61 97 134 164 24 166 30 10 61 6 33 +9 115 176 84 97 142 152 15 50 165 45 168 135 133 127 93 15 66 94 91 9 32 16 95 +37 29 171 118 68 108 66 63 20 55 186 ^ +396 1 97 10 5 160 132 18 83 73 159 141 55 120 31 131 141 102 138 3 52 9 148 189 +56 99 165 146 2 140 64 157 100 121 113 102 24 21 24 123 16 10 139 152 19 109 +146 116 122 92 43 7 75 62 49 170 58 26 117 125 45 147 5 125 136 155 118 2 26 50 +161 21 182 127 153 45 68 19 121 22 94 104 144 166 35 166 23 176 75 188 53 114 +93 148 177 66 151 16 156 121 180 98 48 179 95 63 107 97 45 1 23 97 57 23 132 53 +79 97 124 19 188 18 118 37 22 106 94 60 122 25 47 176 110 184 109 79 164 120 43 +153 89 90 128 109 12 168 64 110 82 117 192 41 171 163 164 76 53 12 101 68 54 +117 78 59 143 84 32 122 104 65 148 31 52 123 130 24 135 38 151 95 142 93 101 +159 62 37 148 110 70 127 51 85 181 89 11 142 105 91 107 50 27 29 102 36 43 165 +79 6 84 99 118 128 30 26 3 143 17 68 66 139 187 15 165 158 24 88 20 179 174 81 +79 18 106 47 74 150 104 179 162 59 131 62 116 166 82 184 188 97 136 41 136 167 +140 143 175 72 42 174 148 75 74 71 86 14 16 191 117 11 63 119 119 186 182 13 +171 49 182 80 167 73 147 119 107 164 41 57 181 168 29 114 26 184 121 101 80 76 +65 34 49 24 44 191 38 25 91 5 58 140 99 153 124 54 184 42 83 108 155 4 20 191 3 +29 35 40 180 7 40 66 25 12 180 86 26 38 139 73 1 137 79 85 102 71 39 28 44 77 +56 190 12 66 72 30 152 7 87 84 190 126 48 100 77 91 186 36 31 143 163 50 94 25 +126 1 114 105 170 93 22 173 90 116 87 96 19 74 4 122 183 83 120 177 113 169 181 +77 182 1 149 186 ^ +384 1 25 56 85 107 177 6 186 138 184 28 61 184 191 175 107 6 29 81 114 12 156 2 +137 86 189 73 64 127 129 44 167 11 98 107 169 143 26 146 61 130 88 120 139 55 3 +189 119 87 22 105 67 78 147 51 2 161 109 84 49 87 38 48 192 62 25 64 143 72 169 +151 106 111 53 58 8 93 8 85 123 120 131 170 38 2 169 167 49 41 37 153 21 39 92 +145 190 155 177 185 48 13 5 150 48 21 85 115 40 166 178 88 104 1 125 19 116 106 +141 111 23 43 101 58 187 150 78 101 50 107 185 86 151 130 134 143 34 31 26 122 +38 40 112 97 33 136 50 99 127 121 159 7 19 170 187 1 79 191 26 130 118 5 104 47 +126 109 92 129 52 30 193 90 35 67 116 90 3 181 39 122 30 155 147 105 83 21 77 +35 75 174 55 190 131 154 95 72 185 94 36 95 126 71 149 4 68 152 180 144 146 7 +49 33 152 188 29 111 194 172 148 125 35 59 36 125 11 36 141 149 183 125 27 1 71 +133 61 138 168 85 131 5 96 162 161 117 142 14 79 183 141 165 126 55 11 74 84 79 +167 3 40 142 177 193 128 173 192 100 163 16 127 145 182 97 17 193 120 115 32 +108 18 96 154 103 152 150 86 181 15 99 135 179 124 194 164 68 160 43 109 138 +152 142 6 21 23 149 20 11 82 164 44 159 148 133 115 24 28 53 104 9 183 179 108 +56 39 84 87 30 163 32 70 75 166 170 8 139 9 175 99 143 64 89 186 114 183 133 85 +161 63 61 154 111 15 115 78 109 108 72 177 14 71 103 176 173 176 157 38 10 54 +132 41 186 130 126 63 69 39 76 7 65 171 82 172 102 124 140 83 113 ^ +396 1 189 70 83 29 132 67 115 145 151 170 181 14 192 2 187 40 5 33 160 48 183 +91 132 83 112 177 62 189 153 128 91 49 38 50 55 24 8 8 51 36 13 175 28 36 56 +160 12 107 168 25 104 157 156 139 165 14 30 192 164 195 56 41 180 159 28 79 41 +144 167 51 115 188 136 154 145 65 2 22 93 83 191 147 23 110 57 137 131 66 138 +26 78 146 125 159 150 34 177 22 129 68 168 111 74 118 77 50 174 54 47 87 140 20 +178 158 133 60 33 45 93 47 8 170 59 52 56 124 20 16 150 117 24 84 46 106 151 51 +158 173 113 111 196 73 15 133 136 71 100 10 85 182 110 143 114 92 185 42 42 118 +156 20 135 173 156 96 180 37 73 134 156 182 150 196 192 45 172 17 167 91 168 68 +89 134 120 190 173 34 141 37 152 111 117 103 61 7 34 62 67 191 190 8 87 21 195 +139 86 44 76 66 55 186 23 31 87 183 5 155 122 191 68 53 149 136 35 115 26 121 +131 102 123 3 42 197 133 179 56 84 165 136 190 130 49 157 80 101 103 97 197 11 +19 118 1 5 119 137 9 104 193 141 116 122 72 38 7 70 47 44 155 43 16 107 125 40 +127 193 105 131 145 108 185 6 50 141 1 167 127 153 45 53 192 121 12 79 84 129 +151 15 166 196 156 60 188 53 109 83 148 162 46 146 6 136 111 160 88 38 169 85 +63 87 97 35 194 3 82 52 13 132 43 59 92 109 4 178 3 118 37 195 96 94 60 112 15 +47 166 110 179 99 69 149 100 43 138 69 70 123 89 12 158 54 90 72 117 182 31 166 +153 164 76 33 2 101 63 44 112 58 39 143 74 32 107 89 55 143 31 47 123 125 4 135 +18 141 80 137 88 81 154 187 ^ +406 0 23 134 103 49 99 44 64 160 68 190 114 105 91 86 22 27 15 74 8 22 151 79 +199 84 85 90 128 9 5 175 129 17 40 59 125 187 194 144 151 3 60 6 158 153 67 58 +18 99 19 53 129 90 179 134 52 124 55 95 138 82 170 167 69 122 13 108 160 119 +115 161 51 14 167 120 47 60 57 86 16 184 96 197 42 98 112 165 154 199 157 21 +168 52 146 66 126 119 93 150 20 36 153 140 194 93 26 156 114 80 80 55 44 13 35 +24 44 191 24 190 63 177 44 140 99 146 117 54 163 42 76 101 134 176 185 177 168 +1 21 19 180 193 12 52 197 191 173 65 19 31 118 59 1 123 72 71 88 64 11 193 37 +63 28 169 184 45 72 195 152 186 87 56 176 112 41 93 77 84 158 29 3 136 142 36 +80 4 119 166 86 98 163 93 1 145 83 102 66 75 191 46 4 94 155 55 120 149 113 148 +181 49 175 180 142 87 5 51 65 92 167 196 186 138 184 23 61 164 171 175 107 6 9 +81 114 7 141 177 117 76 174 73 54 112 114 29 152 11 98 87 154 123 21 146 41 115 +88 115 139 40 183 189 109 67 7 90 52 73 127 51 192 156 89 69 49 77 33 33 182 57 +10 64 138 57 159 136 91 111 33 58 193 88 188 75 118 110 126 170 18 197 169 162 +34 41 17 138 6 34 92 145 185 155 157 170 43 8 140 48 21 70 105 40 161 178 78 89 +196 110 199 106 96 121 106 23 185 28 96 48 167 145 58 91 35 97 180 66 151 130 +124 128 34 16 6 107 28 20 112 92 18 121 30 84 107 101 159 187 19 155 182 181 74 +186 11 120 98 185 104 32 126 94 82 119 42 25 173 90 30 62 96 70 178 176 39 102 +15 150 147 100 78 16 57 35 75 169 35 170 116 144 75 146 ^ +409 1 185 70 12 95 110 71 133 183 52 136 148 144 114 186 17 25 144 164 5 79 178 +172 124 117 19 43 20 93 174 36 125 117 151 109 3 164 55 101 37 122 152 77 131 +168 88 162 161 93 142 14 63 167 141 149 94 39 190 50 68 47 135 198 16 110 153 +177 104 173 192 68 147 179 119 137 166 73 180 169 88 91 24 76 10 80 146 79 128 +150 62 149 194 83 111 171 124 170 156 60 152 27 109 106 120 134 201 184 202 149 +12 198 66 132 12 127 132 133 83 8 12 45 88 9 183 155 92 24 23 76 63 14 163 8 62 +67 150 162 8 115 1 167 91 127 32 89 162 90 159 125 85 129 47 53 154 95 7 115 54 +101 108 56 169 6 47 103 176 157 160 125 14 10 30 124 17 178 122 102 55 69 15 60 +202 49 171 74 148 94 92 124 67 200 184 70 83 29 127 67 100 140 131 165 176 4 +182 2 167 20 193 33 160 43 173 71 112 68 97 157 57 169 138 113 86 44 38 40 55 +19 196 201 31 21 8 165 23 26 41 155 195 183 102 158 25 94 142 146 129 150 9 30 +177 154 195 51 36 175 139 28 59 31 124 167 41 105 173 121 134 130 65 185 17 78 +78 181 137 13 95 57 137 116 51 118 16 78 131 115 154 145 29 177 22 129 68 168 +91 74 98 72 30 174 39 37 72 130 15 163 158 128 50 18 25 73 27 191 150 59 52 36 +104 20 11 130 97 4 79 46 106 141 46 138 163 108 106 191 68 15 113 136 66 100 +193 65 182 105 123 99 72 180 37 22 108 156 10 130 168 141 96 160 22 58 134 151 +162 140 181 187 35 157 7 147 76 163 58 84 129 100 190 153 24 126 32 142 96 107 +88 41 2 14 42 52 186 170 3 82 11 180 119 66 29 56 66 50 171 3 11 77 163 5 150 +112 128 ^ +413 1 47 25 135 129 7 108 19 107 117 102 102 3 28 190 112 165 56 63 165 122 183 +116 28 157 52 73 89 90 169 202 12 111 185 203 91 116 200 97 193 134 116 122 44 +31 7 63 26 37 134 22 2 93 125 33 99 186 77 124 131 94 171 183 50 113 178 146 +127 153 45 32 164 121 203 58 56 108 130 192 166 168 128 39 188 53 102 69 148 +141 18 139 197 108 97 132 74 24 155 71 63 59 97 21 194 180 61 45 204 132 29 31 +85 88 188 164 187 118 37 167 82 94 60 98 1 47 152 110 172 85 55 128 72 43 117 +41 42 116 61 12 144 40 62 58 117 168 17 159 139 164 76 5 193 101 56 30 105 30 +11 143 60 32 86 68 41 136 31 40 123 118 181 135 195 127 59 130 81 53 147 62 13 +124 98 34 79 39 49 145 53 180 94 105 91 71 2 27 5 54 193 7 141 79 199 84 75 70 +128 199 195 160 119 17 20 54 115 187 184 129 146 193 40 201 143 138 57 43 18 94 +204 38 114 80 179 114 47 119 50 80 118 82 160 152 49 112 198 88 155 104 95 151 +36 199 162 100 27 50 47 86 195 16 179 81 192 27 83 107 150 134 194 147 1 158 32 +131 61 111 119 83 140 5 21 133 120 174 78 26 136 109 65 80 40 29 203 25 24 44 +191 14 170 43 162 34 140 99 141 112 54 148 42 71 96 119 161 165 167 148 186 11 +4 180 188 197 42 182 181 168 50 14 26 103 49 1 113 67 61 78 59 196 173 32 53 8 +154 169 30 72 175 152 176 87 36 166 102 36 88 77 79 138 24 188 131 127 26 70 +194 114 146 66 93 158 93 191 125 78 92 51 60 176 26 4 74 135 35 120 129 113 133 +181 29 170 170 137 77 190 46 45 77 157 191 186 138 184 18 61 144 151 175 107 6 +194 81 114 2 126 110 ^ +427 1 85 60 150 73 38 88 90 5 128 11 98 55 130 91 13 146 9 91 88 107 139 16 159 +189 93 35 191 66 28 65 95 51 184 148 57 45 49 61 25 9 166 49 194 64 130 33 143 +112 67 111 1 58 177 80 164 59 110 94 118 170 194 197 169 154 10 41 193 114 190 +26 92 145 177 155 125 146 35 200 124 48 21 46 89 40 153 178 62 65 196 86 175 90 +80 89 98 23 169 4 88 32 135 137 26 75 11 81 172 34 151 130 108 104 34 200 182 +83 12 196 112 84 202 97 206 60 75 69 159 163 19 131 174 157 66 178 195 104 66 +161 104 8 126 70 66 103 26 17 141 90 22 54 64 38 146 168 39 70 199 142 147 92 +70 8 25 35 75 161 3 138 92 128 43 59 185 55 205 95 100 71 123 173 42 126 128 +144 94 176 205 20 139 149 198 59 168 172 109 112 9 33 10 73 154 36 115 97 131 +99 196 144 45 81 22 112 142 72 131 148 83 162 161 78 142 14 53 157 141 139 74 +29 180 35 58 27 115 198 1 90 138 167 89 173 192 48 137 159 114 132 156 58 160 +154 68 76 19 56 5 70 141 64 113 150 47 129 184 73 96 166 124 155 151 55 147 17 +109 86 100 129 201 164 192 149 7 193 56 112 200 107 122 133 63 206 2 40 78 9 +183 140 82 4 13 71 48 4 163 201 57 62 140 157 8 100 204 162 86 117 12 89 147 75 +144 120 85 109 37 48 154 85 2 115 39 96 108 46 164 1 32 103 176 147 150 105 207 +10 15 119 2 173 117 87 50 69 50 202 39 171 69 133 89 72 114 57 195 179 70 83 29 +122 67 85 135 111 160 171 202 172 2 147 183 33 160 38 163 51 92 53 82 137 52 +149 123 98 81 39 38 30 55 14 186 196 11 6 3 155 18 16 26 150 180 168 97 148 25 +84 127 136 119 135 4 30 162 144 195 46 31 170 119 28 190 ^ +443 1 17 96 167 27 91 152 100 106 109 65 164 10 57 71 167 123 209 74 57 137 95 +30 90 2 78 110 101 147 138 22 177 22 129 68 168 63 74 70 65 2 174 18 23 51 116 +8 142 158 121 36 207 207 45 209 170 122 59 52 8 76 20 4 102 69 186 72 46 106 +127 39 110 149 101 99 184 61 15 85 136 59 100 172 37 182 98 95 78 44 173 30 204 +94 156 206 123 161 120 96 132 1 37 134 144 134 126 160 180 21 136 203 119 55 +156 44 77 122 72 190 125 10 105 25 128 75 93 67 13 205 196 14 31 179 142 206 75 +207 159 91 38 8 28 66 43 150 185 193 63 135 5 143 98 143 32 5 125 124 197 103 +14 97 107 102 87 3 18 185 97 155 56 48 165 112 178 106 13 157 32 53 79 85 149 +197 7 106 175 203 71 101 195 92 193 129 116 122 24 26 7 58 11 32 119 7 202 83 +125 28 79 181 57 119 121 84 161 168 50 93 163 131 127 153 45 17 144 121 198 43 +36 93 115 177 166 148 108 24 188 53 97 59 148 126 208 134 192 88 87 112 64 14 +145 61 63 39 97 11 194 165 46 40 199 132 19 11 80 73 178 154 177 118 37 147 72 +94 60 88 201 47 142 110 167 75 45 113 52 43 102 21 22 111 41 12 134 30 42 48 +117 158 7 154 129 164 76 195 188 101 51 20 100 10 201 143 50 32 71 53 31 131 31 +35 123 113 166 135 180 117 44 125 76 33 142 62 3 114 93 19 59 34 34 130 38 170 +74 105 91 56 192 27 205 34 178 202 131 79 199 84 65 50 128 189 185 145 109 17 +49 105 187 174 114 141 183 20 196 128 123 47 28 18 89 189 23 99 70 179 94 42 +114 45 65 98 82 150 137 29 102 183 68 150 89 75 141 21 184 157 80 7 40 37 86 +190 16 174 66 187 12 68 102 135 114 189 137 191 148 12 116 56 96 119 73 130 200 +6 113 100 154 63 26 116 104 50 80 25 14 193 83 ^ +436 1 24 44 191 211 138 11 138 18 140 99 133 104 54 124 42 63 88 95 137 133 151 +116 162 208 193 180 180 173 26 158 165 160 26 6 18 79 33 1 97 59 45 62 51 172 +141 24 37 189 130 145 6 72 143 152 160 87 4 150 86 28 80 77 71 106 16 164 123 +103 10 54 178 106 114 34 85 150 93 175 93 70 76 27 36 152 207 4 42 103 3 120 97 +113 109 181 210 162 154 129 61 166 38 13 53 141 183 186 138 184 10 61 112 119 +175 107 6 170 81 114 207 102 125 65 50 135 73 28 73 75 203 113 11 98 35 115 71 +8 146 202 76 88 102 139 1 144 189 83 15 181 51 13 60 75 51 179 143 37 30 49 51 +20 207 156 44 184 64 125 18 133 97 52 111 194 58 167 75 149 49 105 84 113 170 +179 197 169 149 208 41 178 99 180 21 92 145 172 155 105 131 30 208 200 114 48 +21 31 79 40 148 178 52 50 196 71 160 80 70 69 93 23 159 202 83 22 115 132 6 65 +209 71 167 14 151 130 98 89 34 190 167 68 2 181 112 79 192 82 191 45 55 49 159 +148 19 116 169 142 61 173 185 94 46 146 104 206 126 55 56 93 16 12 121 90 17 49 +44 18 126 163 39 50 189 137 147 87 65 3 5 35 75 156 196 118 77 118 23 54 185 40 +195 95 90 71 113 163 32 116 108 144 74 166 190 15 134 134 188 39 158 172 94 107 +212 23 53 134 36 105 77 111 89 186 124 35 61 7 102 132 67 131 128 78 162 161 63 +142 14 43 147 141 129 54 19 170 20 48 7 95 198 199 70 123 157 74 173 192 28 127 +139 109 127 146 43 140 139 48 61 14 36 60 136 49 98 150 32 109 174 63 81 161 +124 140 146 50 142 7 109 66 80 124 201 144 182 149 2 188 46 92 185 87 112 133 +43 201 205 35 68 9 183 125 72 197 3 66 33 207 163 191 52 57 130 152 8 85 204 +157 81 107 205 187 ^ +462 1 126 54 123 113 85 81 23 41 154 71 210 115 18 89 108 32 157 209 11 103 176 +133 136 77 193 10 209 112 196 166 110 66 43 69 194 36 202 25 171 62 112 82 44 +100 43 188 172 70 83 29 115 67 64 128 83 153 164 195 158 2 119 187 169 33 160 +31 149 23 64 32 61 109 45 121 102 77 74 32 38 16 55 7 172 189 198 200 211 141 +11 2 5 143 159 147 90 134 25 70 106 122 105 114 212 30 141 130 195 39 24 163 91 +28 11 7 76 167 17 81 137 85 86 94 65 149 5 42 66 157 113 204 59 57 137 80 15 70 +207 78 95 91 142 133 17 177 22 129 68 168 43 74 50 60 197 174 3 13 36 106 3 127 +158 116 26 197 192 25 194 155 102 59 52 203 56 20 214 82 49 171 67 46 106 117 +34 90 139 96 94 179 56 15 65 136 54 100 157 17 182 93 75 63 24 168 25 189 84 +156 201 118 156 105 96 112 201 22 134 139 114 116 145 175 11 121 198 99 40 151 +34 72 117 52 190 105 90 20 118 60 83 52 208 205 181 209 16 174 122 206 70 202 +144 71 18 208 8 66 38 135 170 178 53 115 5 138 88 123 17 200 115 119 182 98 9 +87 97 102 72 3 8 180 82 145 56 33 165 102 173 96 213 157 12 33 69 80 129 192 2 +101 165 203 51 86 190 87 193 124 116 122 4 21 7 53 211 27 104 207 197 73 125 23 +59 176 37 114 111 74 151 153 50 73 148 116 127 153 45 2 124 121 193 28 16 78 +100 162 166 128 88 9 188 53 92 49 148 111 193 129 187 68 77 92 54 4 135 51 63 +19 97 1 194 150 31 35 194 132 9 206 75 58 168 144 167 118 37 127 62 94 60 78 +196 47 132 110 162 65 35 98 32 43 87 1 2 106 21 12 124 20 22 38 117 148 212 149 +119 164 76 180 183 101 46 10 95 205 186 143 40 32 56 38 21 126 31 30 123 108 +151 135 165 107 29 120 71 13 137 62 208 104 88 4 39 29 19 115 23 160 54 105 91 +41 177 27 200 14 163 124 ^ +453 0 115 79 199 84 49 18 128 173 169 121 93 17 186 41 89 187 158 90 133 167 +206 188 104 99 31 4 18 81 165 217 75 54 179 62 34 106 37 41 66 82 134 113 215 +86 159 36 142 65 43 125 215 160 149 48 193 24 21 86 182 16 166 42 179 206 44 94 +111 82 181 121 167 132 198 92 48 72 119 57 114 184 200 81 68 122 39 26 84 96 26 +80 1 208 177 217 24 44 191 206 118 209 123 8 140 99 128 99 54 109 42 58 83 80 +122 113 141 96 147 203 183 180 175 158 16 143 155 155 11 1 13 64 23 1 87 54 35 +52 46 157 121 19 27 174 115 130 209 72 123 152 150 87 202 140 76 23 75 77 66 86 +11 149 118 88 44 168 101 94 14 80 145 93 165 73 65 66 12 21 137 192 4 22 83 201 +120 77 113 94 181 195 157 144 124 51 151 33 211 38 131 178 186 138 184 5 61 92 +99 175 107 6 155 81 114 207 87 105 45 40 120 73 18 58 60 193 98 11 98 15 100 51 +3 146 187 61 88 97 139 204 129 189 73 213 171 36 216 55 55 51 174 138 17 15 49 +41 15 197 146 39 174 64 120 3 123 82 37 111 179 58 157 70 134 39 100 74 108 170 +164 197 169 144 198 41 163 84 170 16 92 145 167 155 85 116 25 208 200 104 48 21 +16 69 40 143 178 42 35 196 56 145 70 60 49 88 23 149 192 78 12 95 127 204 55 +199 61 162 212 151 130 88 74 34 180 152 53 210 166 112 74 182 67 176 30 35 29 +159 133 19 101 164 127 56 168 175 84 26 131 104 196 126 40 46 83 6 7 101 90 12 +44 24 216 106 158 39 30 179 132 147 82 60 216 203 35 75 151 181 98 62 108 3 49 +185 25 185 95 80 71 103 153 22 106 88 144 54 156 175 10 129 119 178 19 148 172 +79 102 207 13 208 33 114 36 95 57 91 79 176 104 25 41 210 92 122 62 131 108 73 +162 161 48 142 14 33 137 141 119 34 9 160 5 38 205 75 198 189 50 108 112 ^ +454 1 53 173 192 113 111 102 120 132 22 112 118 20 40 7 8 213 46 129 28 77 150 +11 81 160 49 60 154 124 119 139 43 135 213 109 38 52 117 201 116 168 149 215 +181 32 64 164 59 98 133 15 194 198 28 54 9 183 104 58 176 209 59 12 200 163 177 +45 50 116 145 8 64 204 150 74 93 184 89 111 39 108 108 85 61 13 36 154 61 210 +115 3 84 108 22 152 209 216 103 176 123 126 57 183 10 199 107 186 161 105 51 38 +69 184 26 202 15 171 57 97 77 24 90 33 183 167 70 83 29 110 67 49 123 63 148 +159 190 148 2 99 172 159 33 160 26 139 3 44 17 46 89 40 101 87 62 69 27 38 6 55 +2 162 184 183 190 211 131 6 212 210 138 144 132 85 124 25 60 91 112 95 99 212 +30 126 120 195 34 19 158 71 28 211 217 56 167 7 71 122 70 66 79 65 134 27 61 +147 103 199 44 57 137 65 50 202 78 80 81 137 128 12 177 22 129 68 168 23 74 30 +55 182 174 208 3 21 96 218 112 158 111 16 187 177 5 179 140 82 59 52 188 36 20 +214 62 29 156 62 46 106 107 29 70 129 91 89 174 51 15 45 136 49 100 142 217 182 +88 55 48 4 163 20 174 74 156 196 113 151 90 96 92 191 7 134 134 94 106 130 170 +1 106 193 79 25 146 24 67 112 32 190 85 210 75 15 108 45 73 37 193 205 166 194 +1 169 102 206 65 197 129 51 218 198 208 66 33 120 155 163 43 95 5 133 78 103 2 +185 105 114 167 93 4 77 87 102 57 3 218 175 67 135 56 18 165 92 168 86 203 157 +212 13 59 75 109 187 217 96 155 203 31 71 185 82 193 119 116 122 204 16 7 48 +201 22 89 197 192 63 125 18 39 171 17 109 101 64 141 138 50 53 133 101 127 153 +45 207 104 121 188 13 216 63 85 147 166 108 68 214 188 53 87 39 148 96 178 124 +182 48 67 72 44 214 125 41 63 219 97 211 194 135 16 30 189 132 219 191 70 43 +158 181 ^ +475 0 153 118 37 99 48 94 60 64 189 47 118 110 155 51 21 77 4 43 66 195 196 99 +215 12 110 6 216 24 117 134 205 142 105 164 76 159 176 101 39 218 88 184 165 +143 26 32 35 17 7 119 31 23 123 101 130 135 144 93 8 113 64 207 130 62 201 90 +81 205 11 22 220 94 2 146 26 105 91 20 156 27 193 208 142 178 107 79 199 84 41 +2 128 165 161 109 85 17 174 37 81 187 150 78 129 159 194 184 92 87 23 214 18 77 +153 209 63 46 179 46 30 102 33 29 50 82 126 101 203 78 147 20 138 53 27 117 207 +148 145 32 181 16 13 86 178 16 162 30 175 198 32 90 99 66 177 113 155 124 186 +80 44 60 119 49 106 176 192 65 52 106 27 26 68 92 14 80 211 200 169 213 24 44 +191 202 102 197 111 140 99 124 95 54 97 42 54 79 68 110 97 133 80 135 199 175 +180 171 146 8 131 147 151 221 219 9 52 15 1 79 50 27 44 42 145 105 15 19 162 +103 118 201 72 107 152 142 87 190 132 68 19 71 77 62 70 7 137 114 76 214 36 160 +97 78 220 76 141 93 157 57 61 58 9 125 180 4 6 67 189 120 61 113 82 181 183 153 +136 120 43 139 29 199 26 123 174 186 138 184 1 61 76 83 175 107 6 143 81 114 +207 75 89 29 32 108 73 10 46 48 185 86 11 98 221 88 35 221 146 175 49 88 93 139 +196 117 189 65 201 163 24 208 51 39 51 170 134 1 3 49 33 11 189 138 35 166 64 +116 213 115 70 25 111 167 58 149 66 122 31 96 66 104 170 152 197 169 140 190 41 +151 72 162 12 92 145 163 155 69 104 21 208 200 96 48 21 4 61 40 139 178 34 23 +196 44 133 62 52 33 84 23 141 184 74 4 79 123 192 47 191 53 158 200 151 130 80 +62 34 172 140 41 206 154 112 70 174 55 164 18 19 13 159 121 19 89 160 115 52 +164 167 76 10 119 104 188 126 28 38 75 220 3 85 90 8 40 8 204 90 154 39 14 171 +128 147 78 56 216 191 35 75 147 169 82 50 100 209 45 185 13 177 95 150 ^ +471 0 71 89 139 8 92 60 144 26 142 154 3 122 98 164 216 134 172 58 95 200 224 +201 5 86 36 81 29 63 65 162 76 11 13 196 78 108 55 131 80 66 162 161 27 142 14 +19 123 141 105 6 220 146 209 24 184 47 198 175 22 87 133 38 173 192 205 103 91 +97 115 122 7 92 103 25 2 213 213 36 124 13 62 150 221 61 150 39 45 149 124 104 +134 38 130 208 109 18 32 112 201 96 158 149 215 176 22 44 149 39 88 133 220 189 +193 23 44 9 183 89 48 161 204 54 222 195 163 167 40 45 106 140 8 49 204 145 69 +83 169 89 96 24 93 103 85 41 3 31 154 51 210 115 213 79 108 12 147 209 206 103 +176 113 116 37 173 10 189 102 176 156 100 36 33 69 174 16 202 5 171 52 82 72 4 +80 23 178 162 70 83 29 105 67 34 118 43 143 154 185 138 2 79 157 149 33 160 21 +129 208 24 2 31 69 35 81 72 47 64 22 38 221 55 222 152 179 168 180 211 121 1 +207 200 133 129 117 80 114 25 50 76 102 85 84 212 30 111 110 195 29 14 153 51 +28 196 212 36 167 222 61 107 55 46 64 65 119 220 12 56 137 93 194 29 57 137 50 +210 30 197 78 65 71 132 123 7 177 22 129 68 168 3 74 10 50 167 174 198 218 6 86 +218 97 158 106 6 177 162 210 164 125 62 59 52 173 16 20 214 42 9 141 57 46 106 +97 24 50 119 86 84 169 46 15 25 136 44 100 127 202 182 83 35 33 209 158 15 159 +64 156 191 108 146 75 96 72 181 217 134 129 74 96 115 165 216 91 188 59 10 141 +14 62 107 12 190 65 205 60 10 98 30 63 22 178 205 151 179 211 164 82 206 60 192 +114 31 203 188 193 66 28 105 140 148 33 75 5 128 68 83 212 170 95 109 152 88 +224 67 77 102 42 3 213 170 52 125 56 3 165 82 163 76 193 157 197 218 49 70 89 +182 217 91 145 203 11 56 180 77 193 114 116 122 189 11 7 43 191 17 74 187 187 +53 125 13 19 166 222 104 91 54 131 123 50 33 118 86 127 167 ^ +480 1 45 193 76 121 181 219 195 42 64 126 166 80 40 200 188 53 80 25 148 75 157 +117 175 20 53 44 30 207 111 27 63 198 97 204 194 114 222 23 182 132 212 170 63 +22 144 120 143 118 37 79 38 94 60 54 184 47 108 110 150 41 11 62 211 43 51 180 +181 94 200 12 100 223 201 14 117 124 200 137 95 164 76 144 171 101 34 213 83 +169 150 143 16 32 20 2 224 114 31 18 123 96 115 135 129 83 220 108 59 192 125 +62 196 80 76 195 218 17 210 79 214 136 6 105 91 5 141 27 188 193 127 168 97 79 +199 84 31 209 128 155 151 94 75 17 159 32 71 187 140 63 124 149 179 179 77 72 +13 204 18 72 138 199 48 36 179 26 25 97 28 14 30 82 116 86 188 68 132 133 38 7 +107 197 133 140 12 166 6 3 86 173 16 157 15 170 188 17 85 84 46 172 103 140 114 +171 65 39 45 119 39 96 166 182 45 32 86 12 26 48 87 226 80 201 190 159 208 24 +44 191 197 82 182 96 217 140 99 119 90 54 82 42 49 74 53 95 77 123 60 120 194 +165 180 166 131 225 116 137 146 211 219 4 37 5 1 69 45 17 34 37 130 85 10 9 147 +88 103 191 72 87 152 132 87 175 122 58 14 66 77 57 50 2 122 109 61 209 26 150 +92 58 205 71 136 93 147 37 56 48 212 221 110 165 4 213 47 174 120 41 113 67 181 +168 148 126 115 33 124 24 184 11 113 169 186 138 184 223 61 56 63 175 107 6 128 +81 114 207 60 69 9 22 93 73 31 33 175 71 11 98 206 73 15 221 146 160 34 88 88 +139 186 102 189 55 186 153 9 198 46 19 51 165 129 208 215 49 23 6 179 128 30 +156 64 111 203 105 55 10 111 152 58 139 61 107 21 91 56 99 170 137 197 169 135 +180 41 136 57 152 7 92 145 158 155 49 89 16 208 200 86 48 21 216 51 40 134 178 +24 8 196 29 118 52 42 13 79 23 131 174 69 221 59 118 177 37 181 43 153 185 151 +130 70 47 34 162 125 26 201 139 112 65 164 40 149 3 226 220 159 106 19 74 155 +100 47 159 157 193 ^ +471 0 211 98 104 174 126 7 24 61 213 225 57 90 1 33 209 183 62 147 39 215 157 +121 147 71 49 216 170 35 75 140 148 54 29 86 188 38 185 221 163 95 58 71 81 131 +84 44 144 10 134 142 228 118 86 156 204 126 172 46 91 196 220 197 218 70 36 73 +13 47 57 154 60 3 226 188 70 100 51 131 64 62 162 161 15 142 14 11 115 141 97 +219 216 138 201 16 172 31 198 167 6 75 125 26 173 192 193 95 75 93 111 114 224 +76 91 213 13 227 201 213 28 120 1 50 150 213 45 142 31 33 145 124 92 130 34 126 +204 109 2 16 108 201 80 150 149 215 172 14 28 137 23 80 133 208 185 189 19 36 9 +183 77 40 149 200 50 214 191 163 159 36 41 98 136 8 37 204 141 65 75 157 89 84 +12 81 99 85 25 224 27 154 43 210 115 205 75 108 4 143 209 198 103 176 105 108 +21 165 10 181 98 168 152 96 24 29 69 166 8 202 226 171 48 70 68 217 72 15 174 +158 70 83 29 101 67 22 114 27 139 150 181 130 2 63 145 141 33 160 17 121 196 8 +219 19 53 31 65 60 35 60 18 38 217 55 222 144 175 156 172 211 113 226 203 192 +129 117 105 76 106 25 42 64 94 77 72 212 30 99 102 195 25 10 149 35 28 184 208 +20 167 218 53 95 43 30 52 65 107 220 52 129 85 190 17 57 137 38 202 14 193 78 +53 63 128 119 3 177 22 129 68 168 216 74 223 46 155 174 190 214 223 78 218 85 +158 102 227 169 150 198 152 113 46 59 52 161 20 214 26 222 129 53 46 106 89 20 +34 111 82 80 165 42 15 9 136 40 100 115 190 182 79 19 21 197 154 11 147 56 156 +187 104 142 63 96 56 173 209 134 125 58 88 103 161 212 79 184 43 227 137 6 58 +103 225 190 49 201 48 6 90 18 55 10 166 205 139 167 203 160 66 206 56 188 102 +15 191 180 181 66 24 93 128 136 25 59 5 124 60 67 204 158 87 105 140 84 224 59 +69 102 30 3 209 166 40 117 56 220 165 74 159 68 185 157 185 206 41 66 167 ^ +490 1 176 217 85 133 203 218 38 174 71 193 108 116 122 171 5 7 37 179 11 56 175 +181 41 125 7 226 160 204 98 79 42 119 105 50 9 100 68 127 153 45 185 60 121 177 +211 183 30 52 114 166 64 24 192 188 53 76 17 148 63 145 113 171 4 45 28 22 203 +103 19 63 186 97 200 194 102 214 19 178 132 208 158 59 10 136 112 135 118 37 63 +30 94 60 46 180 47 100 110 146 33 3 50 199 43 39 168 169 90 188 12 92 219 189 6 +117 116 196 133 87 164 76 132 167 101 30 209 79 157 138 143 8 32 8 221 220 110 +31 14 123 92 103 135 117 75 212 104 55 180 121 62 192 72 72 187 206 13 202 67 +206 128 221 105 91 224 129 27 184 181 115 160 89 79 199 84 23 197 128 147 143 +82 67 17 147 28 63 187 132 51 120 141 167 175 65 60 5 196 18 68 126 191 36 28 +179 10 21 93 24 2 14 82 108 74 176 60 120 215 129 26 222 99 189 121 136 227 154 +229 226 86 169 16 153 3 166 180 5 81 72 30 168 95 128 106 159 53 35 33 119 31 +88 158 174 29 16 70 26 32 83 218 80 193 182 151 204 24 44 191 193 66 170 84 213 +140 99 115 86 54 70 42 45 70 41 83 61 115 44 108 190 157 180 162 119 221 104 +129 142 203 219 25 228 1 61 41 9 26 33 118 69 6 1 135 76 91 183 72 71 152 124 +87 163 114 50 10 62 77 53 34 229 110 105 49 205 18 142 88 42 193 67 132 93 139 +21 52 40 204 213 98 153 4 201 31 162 120 25 113 55 181 156 144 118 111 25 112 +20 172 230 105 165 186 138 184 223 61 40 47 175 107 6 116 81 114 207 48 53 224 +14 81 73 223 19 21 167 59 11 98 194 61 230 221 146 148 22 88 84 139 178 90 189 +47 174 145 228 190 42 3 51 161 125 196 207 49 15 2 171 120 26 148 64 107 195 97 +43 229 111 140 58 131 57 95 13 87 48 95 170 125 197 169 131 172 41 124 45 144 3 +92 145 154 155 33 77 12 208 200 78 48 21 208 43 40 130 178 16 227 196 17 106 44 +34 228 75 23 123 166 65 217 43 114 165 29 173 35 200 ^ +479 0 167 151 130 58 29 34 150 107 8 195 121 112 59 152 22 131 218 208 202 159 +88 19 56 149 82 41 153 145 54 199 86 104 166 126 228 16 53 209 225 41 90 230 29 +197 171 46 143 39 203 149 117 147 67 45 216 158 35 75 136 136 38 17 78 176 34 +185 213 155 95 50 71 73 123 225 76 28 144 227 126 130 228 114 74 148 192 118 +172 34 87 192 216 193 206 54 36 65 230 31 49 146 44 228 214 180 62 92 47 131 48 +58 162 161 3 142 14 3 107 141 89 207 212 130 193 8 160 15 198 159 223 63 117 14 +173 192 181 87 59 89 107 106 216 60 79 201 1 227 189 213 20 116 222 38 150 205 +29 134 23 21 141 124 80 126 30 122 200 109 219 104 201 64 142 149 215 168 6 12 +125 7 72 133 196 181 185 15 28 9 183 65 32 137 196 46 206 187 163 151 32 37 90 +132 8 25 204 137 61 67 145 89 72 69 95 85 9 220 23 154 35 210 115 197 71 108 +229 139 209 190 103 176 97 100 5 157 10 173 94 160 148 92 12 25 69 158 202 222 +171 44 58 64 205 64 7 170 154 70 83 29 97 67 10 110 11 135 146 177 122 2 47 133 +133 33 160 13 113 184 225 211 7 37 27 49 48 23 56 14 38 213 55 222 136 171 144 +164 211 105 226 199 184 125 105 93 72 98 25 34 52 86 69 60 212 30 87 94 195 21 +6 145 19 28 172 204 4 167 214 45 83 31 14 40 65 95 220 221 48 121 77 186 5 57 +137 26 194 231 189 78 41 55 124 115 232 177 22 129 68 168 204 74 211 42 143 174 +182 210 215 70 218 73 158 98 223 161 138 186 140 101 30 59 52 149 217 20 214 10 +210 117 49 46 106 81 16 18 103 78 76 161 38 15 226 136 36 100 103 178 182 75 3 +9 185 150 7 135 48 156 183 100 138 51 96 40 165 201 134 121 42 80 91 157 208 67 +180 27 219 133 231 54 99 213 190 33 197 36 2 82 6 47 231 154 205 127 155 195 +156 50 206 52 184 90 232 179 172 169 66 20 81 116 124 17 43 5 120 52 51 196 146 +79 101 128 80 224 65 ^ +503 1 55 102 9 3 202 159 19 103 56 206 165 60 152 54 171 157 164 185 27 59 45 +171 217 80 123 203 203 23 169 66 193 103 116 122 156 7 32 169 6 41 165 176 31 +125 2 211 155 189 93 69 32 109 90 50 225 85 53 127 153 45 175 40 121 172 201 +168 15 37 99 166 44 4 182 188 53 71 7 148 48 130 108 166 220 35 8 12 198 93 9 +63 171 97 195 194 87 204 14 173 132 203 143 54 231 126 102 125 118 37 43 20 94 +60 36 175 47 90 110 141 23 229 35 184 43 24 153 154 85 173 12 82 214 174 232 +117 106 191 128 77 164 76 117 162 101 25 204 74 142 123 143 234 32 229 211 215 +105 31 9 123 87 88 135 102 65 202 99 50 165 116 62 187 62 67 177 191 8 192 52 +196 118 206 105 91 214 114 27 179 166 100 150 79 79 199 84 13 182 128 137 133 +67 57 17 132 23 53 187 122 36 115 131 152 170 50 45 231 186 18 63 111 181 21 18 +179 226 16 88 19 223 230 82 98 59 161 50 105 200 124 11 207 89 179 106 131 212 +139 224 221 86 164 16 148 224 161 170 226 76 57 10 163 85 113 96 144 38 30 18 +119 21 78 148 164 9 232 50 221 26 12 78 208 80 183 172 141 199 24 44 191 188 46 +155 69 208 140 99 110 81 54 55 42 40 65 26 68 41 105 24 93 185 147 180 157 104 +216 89 119 137 193 219 231 10 223 1 51 36 235 16 28 103 49 1 227 120 61 76 173 +72 51 152 114 87 148 104 40 5 57 77 48 14 229 95 100 34 200 8 132 83 22 178 62 +127 93 129 1 47 30 194 203 83 138 4 186 11 147 120 5 113 40 181 141 139 108 106 +15 97 15 157 220 95 160 186 138 184 223 61 20 27 175 107 6 101 81 114 207 33 33 +209 4 66 73 218 4 6 157 44 11 98 179 46 215 221 146 133 7 88 79 139 168 75 189 +37 159 135 218 180 37 219 51 156 120 181 197 49 5 233 161 110 21 138 64 102 185 +87 28 219 111 125 58 121 52 80 3 82 38 90 170 110 197 169 126 162 41 109 30 134 +234 92 145 149 155 13 62 7 208 200 68 48 21 198 33 40 125 178 6 217 196 2 91 34 +24 213 70 23 113 161 ^ +470 0 58 210 15 107 144 15 159 21 142 152 151 130 48 14 34 140 92 231 190 106 +112 54 142 7 116 208 193 187 159 73 19 41 144 67 36 148 135 44 184 71 104 156 +126 218 6 43 204 225 21 90 230 24 182 156 26 138 39 188 139 112 147 62 40 216 +143 35 75 131 121 18 2 68 161 29 185 203 145 95 40 71 63 113 220 66 8 144 212 +116 115 228 109 59 138 177 108 172 19 82 187 211 188 191 34 36 55 215 11 39 136 +24 223 199 170 52 82 42 131 28 53 162 161 226 142 14 231 97 141 79 192 207 120 +183 236 145 233 198 149 208 48 107 237 173 192 166 77 39 84 102 96 206 40 64 +186 224 227 174 213 10 111 212 23 150 195 9 124 13 6 136 124 65 121 25 117 195 +109 204 218 99 201 44 132 149 215 163 234 230 110 225 62 133 181 176 180 10 18 +9 183 50 22 122 191 41 196 182 163 141 27 32 80 127 8 10 204 132 56 57 130 89 +57 223 54 90 85 227 215 18 154 25 210 115 187 66 108 224 134 209 180 103 176 87 +90 223 147 10 163 89 150 143 87 235 20 69 148 228 202 217 171 39 43 59 190 54 +235 165 149 70 83 29 92 67 233 105 229 130 141 172 112 2 27 118 123 33 160 8 +103 169 210 201 230 17 22 29 33 8 51 9 38 208 55 222 126 166 129 154 211 95 226 +194 174 120 90 78 67 88 25 24 37 76 59 45 212 30 72 84 195 16 1 140 237 28 157 +199 222 167 209 35 68 16 232 25 65 80 220 211 43 111 67 181 228 57 137 11 184 +216 184 78 26 45 119 110 232 177 22 129 68 168 189 74 196 37 128 174 172 205 +205 60 218 58 158 93 218 151 123 171 125 86 10 59 52 134 202 20 214 228 195 102 +44 46 106 71 11 236 93 73 71 156 33 15 211 136 31 100 88 163 182 70 221 232 170 +145 2 120 38 156 178 95 133 36 96 20 155 191 134 116 22 70 76 152 203 52 175 7 +209 128 226 49 94 198 190 13 192 21 235 72 229 37 221 139 205 112 140 185 151 +30 206 47 179 75 217 101 ^ +502 0 158 148 66 13 60 95 103 3 15 5 113 38 23 182 125 65 94 107 73 224 37 47 +102 237 3 198 155 7 95 56 198 165 52 148 46 163 157 152 173 19 55 29 167 217 76 +115 203 191 11 165 62 193 99 116 122 144 236 7 28 161 2 29 157 172 23 125 238 +199 151 177 89 61 24 101 78 50 213 73 41 127 153 45 167 24 121 168 193 156 3 25 +87 166 28 228 174 188 53 67 239 148 36 118 104 162 208 27 232 4 194 85 1 63 159 +97 191 194 75 196 10 169 132 199 131 50 223 118 94 117 118 37 27 12 94 60 28 +171 47 82 110 137 15 225 23 172 43 12 141 142 81 161 12 74 210 162 228 117 98 +187 124 69 164 76 105 158 101 21 200 70 130 111 143 230 32 221 203 211 101 31 5 +123 83 76 135 90 57 194 95 46 153 112 62 183 54 63 169 179 4 184 40 188 110 194 +105 91 206 102 27 175 154 88 142 71 79 199 84 5 170 128 129 125 55 49 17 120 19 +45 187 114 24 111 123 140 166 38 33 227 178 18 59 99 173 9 10 179 214 12 84 15 +215 218 82 90 47 149 42 93 188 120 239 195 81 171 94 127 200 127 220 217 86 160 +16 144 216 157 162 218 72 45 234 159 77 101 88 132 26 26 6 119 13 70 140 156 +233 220 34 213 26 236 74 200 80 175 164 133 195 24 44 191 184 30 143 57 204 140 +99 106 77 54 43 42 36 61 14 56 25 97 8 81 181 139 180 153 92 212 77 111 133 185 +219 231 238 219 1 43 32 231 8 24 91 33 237 223 108 49 64 165 72 35 152 106 87 +136 96 32 1 53 77 44 238 229 83 96 22 196 124 79 6 166 58 123 93 121 225 43 22 +186 195 71 126 4 174 235 135 120 229 113 28 181 129 135 100 102 7 85 11 145 212 +87 156 186 138 184 223 61 4 11 175 107 6 89 81 114 207 21 17 197 236 54 73 214 +232 234 149 32 11 98 167 34 203 221 146 121 235 88 75 139 160 63 189 29 147 127 +210 172 33 207 51 152 116 169 189 49 237 233 153 102 17 130 64 98 177 79 16 211 +111 113 58 113 48 68 235 78 30 86 170 98 197 169 122 154 41 97 18 126 234 92 +145 145 155 237 50 209 ^ +481 1 208 200 56 48 21 186 21 40 119 178 236 205 196 226 73 22 12 195 64 23 101 +144 54 206 241 103 132 7 151 13 138 140 151 130 40 2 34 132 80 223 186 94 112 +50 134 237 104 200 181 175 159 61 19 29 140 55 32 144 127 36 172 59 104 148 126 +210 240 35 200 225 5 90 230 20 170 144 10 134 39 176 131 108 147 58 36 216 131 +35 75 127 109 2 232 60 149 25 185 195 137 95 32 71 55 105 216 58 234 144 200 +108 103 228 105 47 130 165 100 172 7 78 183 207 184 179 18 36 47 203 237 31 128 +8 219 187 162 44 74 38 131 12 49 162 161 218 142 14 227 89 141 71 180 203 112 +175 232 133 221 198 141 196 36 99 229 173 192 154 69 23 80 98 88 198 24 52 174 +216 227 162 213 2 107 204 11 150 187 235 116 5 236 132 124 53 117 21 113 191 +109 192 206 95 201 28 124 149 215 159 230 218 98 213 54 133 169 172 176 6 10 9 +183 38 14 110 187 37 188 178 163 133 23 28 72 123 8 240 204 128 52 49 118 89 45 +215 42 86 85 215 211 14 154 17 210 115 179 62 108 220 130 209 172 103 176 79 82 +211 139 10 155 85 142 139 83 227 16 69 140 224 202 213 171 35 31 55 178 46 231 +161 145 70 83 29 88 67 225 101 217 126 137 168 104 2 11 106 115 33 160 4 95 157 +198 193 222 1 18 13 21 238 47 5 38 204 55 222 118 162 117 146 211 87 226 190 +166 116 78 66 63 80 25 16 25 68 51 33 212 30 60 76 195 12 239 136 225 28 145 +195 210 167 205 27 56 4 220 13 65 68 220 203 39 103 59 177 220 57 137 241 176 +204 180 78 14 37 115 106 232 177 22 129 68 168 177 74 184 33 116 174 164 201 +197 52 218 46 158 89 214 143 111 159 113 74 236 59 52 122 190 20 214 216 183 90 +40 46 106 63 7 224 85 69 67 152 29 15 199 136 27 100 76 151 182 66 209 224 158 +141 240 108 30 156 174 91 129 24 96 4 147 183 134 112 6 62 64 148 199 40 171 +233 201 124 222 45 90 186 190 239 188 9 235 64 221 29 213 127 178 ^ +508 1 94 122 173 145 6 206 41 173 57 199 146 150 136 66 9 48 83 91 239 243 5 +109 30 7 174 113 57 90 95 69 224 29 39 102 229 3 194 151 239 87 56 190 165 44 +144 38 155 157 140 161 11 51 13 163 217 72 107 203 179 243 161 58 193 95 116 +122 132 236 7 24 153 242 17 149 168 15 125 238 187 147 165 85 53 16 93 66 50 +201 61 29 127 153 45 159 8 121 164 185 144 235 13 75 166 12 216 166 188 53 63 +235 148 24 106 100 158 196 19 220 240 190 77 237 63 147 97 187 194 63 188 6 165 +132 195 119 46 215 110 86 109 118 37 11 4 94 60 20 167 47 74 110 133 7 221 11 +160 43 129 130 77 149 12 66 206 150 224 117 90 183 120 61 164 76 93 154 101 17 +196 66 118 99 143 226 32 213 195 207 97 31 1 123 79 64 135 78 49 186 91 42 141 +108 62 179 46 59 161 167 176 28 180 102 182 105 91 198 90 27 171 142 76 134 63 +79 199 84 241 158 128 121 117 43 41 17 108 15 37 187 106 12 107 115 128 162 26 +21 223 170 18 55 87 165 241 2 179 202 8 80 11 207 206 82 82 35 137 34 81 176 +116 231 183 73 163 82 123 188 115 216 213 86 156 16 140 208 153 154 210 68 33 +222 155 69 89 80 120 14 22 238 119 5 62 132 148 221 208 18 205 26 224 70 192 80 +167 156 125 191 24 44 191 180 14 131 45 200 140 99 102 73 54 31 42 32 57 2 44 9 +89 236 69 177 131 180 149 80 208 65 103 129 177 219 231 230 215 1 35 28 227 20 +79 17 237 219 96 37 52 157 72 19 152 98 87 124 88 24 241 49 77 40 226 229 71 92 +10 192 236 116 75 234 154 54 119 93 113 213 39 14 178 187 59 114 4 162 223 123 +120 217 113 16 181 117 131 92 98 243 73 7 133 204 79 152 186 138 184 223 61 232 +239 175 107 6 77 81 114 207 9 1 185 232 42 73 210 224 226 141 20 11 98 155 22 +191 221 146 109 227 88 71 139 152 51 189 21 135 119 202 164 29 195 51 148 112 +157 181 49 233 233 145 94 13 122 64 94 169 71 4 203 111 101 58 105 44 56 231 74 +22 82 170 86 197 169 118 146 41 85 6 118 234 92 145 141 149 ^ +484 1 219 32 243 208 200 48 48 21 178 13 40 115 178 232 197 196 218 61 14 4 183 +60 23 93 136 50 202 229 99 120 245 143 5 134 128 151 130 32 236 34 124 68 215 +182 82 112 46 126 229 92 192 169 163 159 49 19 17 136 43 28 140 119 28 160 47 +104 140 126 202 236 27 196 225 235 90 230 16 158 132 240 130 39 164 123 104 147 +54 32 216 119 35 75 123 97 232 224 52 137 21 185 187 129 95 24 71 47 97 212 50 +222 144 188 100 91 228 101 35 122 153 92 172 241 74 179 203 180 167 2 36 39 191 +225 23 120 238 215 175 154 36 66 34 131 242 45 162 161 210 142 14 223 81 141 63 +168 199 104 167 228 121 209 198 133 184 24 91 221 173 192 142 61 7 76 94 80 190 +8 40 162 208 227 150 213 240 103 196 245 150 179 223 108 243 228 128 124 41 113 +17 109 187 109 180 194 91 201 12 116 149 215 155 226 206 86 201 46 133 157 168 +172 2 2 9 183 26 6 98 183 33 180 174 163 125 19 24 64 119 8 232 204 124 48 41 +106 89 33 207 30 82 85 203 207 10 154 9 210 115 171 58 108 216 126 209 164 103 +176 71 74 199 131 10 147 81 134 135 79 219 12 69 132 220 202 209 171 31 19 51 +166 38 227 157 141 70 83 29 84 67 217 97 205 122 133 164 96 2 241 94 107 33 160 +87 145 186 185 214 231 14 243 9 230 43 1 38 200 55 222 110 158 105 138 211 79 +226 186 158 112 66 54 59 72 25 8 13 60 43 21 212 30 48 68 195 8 239 132 213 28 +133 191 198 167 201 19 44 238 208 1 65 56 220 195 35 95 51 173 212 57 137 233 +168 192 176 78 2 29 111 102 232 177 22 129 68 168 165 74 172 29 104 174 156 197 +189 44 218 34 158 85 210 135 99 147 101 62 224 59 52 110 178 20 214 204 171 78 +36 46 106 55 3 212 77 65 63 148 25 15 187 136 23 100 64 139 182 62 197 216 146 +137 240 96 22 156 170 87 125 12 96 234 139 175 134 108 236 54 52 144 195 28 167 +221 193 120 218 41 86 174 190 227 184 243 235 56 213 21 205 115 205 71 ^ +506 0 110 165 141 238 206 37 169 45 187 134 142 124 66 5 36 71 79 235 231 5 105 +22 239 166 101 49 86 83 65 224 21 31 102 221 3 190 147 231 79 56 182 165 36 140 +30 147 157 128 149 3 47 245 159 217 68 99 203 167 235 157 54 193 91 116 122 120 +236 7 20 145 242 5 141 164 7 125 238 175 143 153 81 45 8 85 54 50 189 49 17 127 +153 45 151 240 121 160 177 132 227 1 63 166 244 204 158 188 53 59 231 148 12 94 +96 154 184 11 208 236 186 69 233 63 135 97 183 194 51 180 2 161 132 191 107 42 +207 102 78 101 118 37 243 244 94 60 12 163 47 66 110 129 247 217 247 148 43 236 +117 118 73 137 12 58 202 138 220 117 82 179 116 53 164 76 81 150 101 13 192 62 +106 87 143 222 32 205 187 203 93 31 245 123 75 52 135 66 41 178 87 38 129 104 +62 175 38 55 153 155 244 168 16 172 94 170 105 91 190 78 27 167 130 64 126 55 +79 199 84 237 146 128 113 109 31 33 17 96 11 29 187 98 103 107 116 158 14 9 219 +162 18 51 75 157 233 242 179 190 4 76 7 199 194 82 74 23 125 26 69 164 112 223 +171 65 155 70 119 176 103 212 209 86 152 16 136 200 149 146 202 64 21 210 151 +61 77 72 108 2 18 230 119 245 54 124 140 209 196 2 197 26 212 66 184 80 159 148 +117 187 24 44 191 176 246 119 33 196 140 99 98 69 54 19 42 28 53 238 32 241 81 +224 57 173 123 180 145 68 204 53 95 125 169 219 231 222 211 1 27 24 223 240 16 +67 1 237 215 84 25 40 149 72 3 152 90 87 112 80 16 241 45 77 36 214 229 59 88 +246 188 232 108 71 222 142 50 115 93 105 201 35 6 170 179 47 102 4 150 211 111 +120 205 113 4 181 105 127 84 94 239 61 3 121 196 71 148 186 138 184 223 61 220 +227 175 107 6 65 81 114 207 245 233 173 228 30 73 206 216 218 133 8 11 98 143 +10 179 221 146 97 219 88 67 139 144 39 189 13 123 111 194 156 25 183 51 144 108 +145 173 49 229 233 137 86 9 114 64 90 161 63 240 195 111 89 58 97 40 44 227 70 +14 78 170 74 197 169 114 138 41 73 242 110 234 177 ^ +491 0 145 135 155 207 20 243 208 200 40 48 21 170 5 40 111 178 228 189 196 210 +49 6 246 171 56 23 85 128 46 198 217 95 108 241 135 247 130 116 151 130 24 228 +34 116 56 207 178 70 112 42 118 221 80 184 157 151 159 37 19 5 132 31 24 136 +111 20 148 35 104 132 126 194 232 19 192 225 223 90 230 12 146 120 228 126 39 +152 115 100 147 50 28 216 107 35 75 119 85 220 216 44 125 17 185 179 121 95 16 +71 39 89 208 42 210 144 176 92 79 228 97 23 114 141 84 172 233 70 175 199 176 +155 236 36 31 179 213 15 112 226 211 163 146 28 58 30 131 230 41 162 161 202 +142 14 219 73 141 55 156 195 96 159 224 109 197 198 125 172 12 83 213 173 192 +130 53 241 72 90 72 182 242 28 150 200 227 138 213 236 99 188 237 150 171 211 +100 239 220 124 124 29 109 13 105 183 109 168 182 87 201 246 108 149 215 151 +222 194 74 189 38 133 145 164 168 248 244 9 183 14 248 86 179 29 172 170 163 +117 15 20 56 115 8 224 204 120 44 33 94 89 21 199 18 78 85 191 203 6 154 1 210 +115 163 54 108 212 122 209 156 103 176 63 66 187 123 10 139 77 126 131 75 211 8 +69 124 216 202 205 171 27 7 47 154 30 223 153 137 70 83 29 80 67 209 93 193 118 +129 160 88 2 229 82 99 33 160 246 79 133 174 177 206 219 10 231 247 222 39 247 +38 196 55 222 102 154 93 130 211 71 226 182 150 108 54 42 55 64 25 1 52 35 9 +212 30 36 60 195 4 239 128 201 28 121 187 186 167 197 11 32 230 196 239 65 44 +220 187 31 87 43 169 204 57 137 225 160 180 172 78 240 21 107 98 232 177 22 129 +68 168 153 74 160 25 92 174 148 193 181 36 218 22 158 81 206 127 87 135 89 50 +212 59 52 98 166 20 214 192 159 66 32 46 106 47 249 200 69 61 59 144 21 15 175 +136 19 100 52 127 182 58 185 208 134 133 240 84 14 156 166 83 121 96 222 131 +167 134 104 224 46 40 140 191 16 163 209 185 116 214 37 82 162 190 215 180 235 +235 48 205 13 197 103 205 76 104 161 139 232 146 ^ +516 0 33 165 33 175 122 134 112 66 1 24 59 67 231 219 5 101 14 227 158 89 41 82 +71 61 224 13 23 102 213 3 186 143 223 71 56 174 165 28 136 22 139 157 116 137 +247 43 233 155 217 64 91 203 155 227 153 50 193 87 116 122 108 236 7 16 137 242 +245 133 160 251 125 238 163 139 141 77 37 77 42 50 177 37 5 127 153 45 143 228 +121 156 169 120 219 241 51 166 232 192 150 188 53 55 227 148 82 92 150 172 3 +196 232 182 61 229 63 123 97 179 194 39 172 250 157 132 187 95 38 199 94 70 93 +118 37 231 240 94 60 4 159 47 58 110 125 243 213 239 136 43 228 105 106 69 125 +12 50 198 126 216 117 74 175 112 45 164 76 69 146 101 9 188 58 94 75 143 218 32 +197 179 199 89 31 245 123 71 40 135 54 33 170 83 34 117 100 62 171 30 51 145 +143 244 160 4 164 86 158 105 91 182 66 27 163 118 52 118 47 79 199 84 233 134 +128 105 101 19 25 17 84 7 21 187 90 240 99 99 104 154 2 249 215 154 18 47 63 +149 225 238 179 178 72 3 191 182 82 66 11 113 18 57 152 108 215 159 57 147 58 +115 164 91 208 205 86 148 16 132 192 145 138 194 60 9 198 147 53 65 64 96 242 +14 222 119 241 46 116 132 197 184 238 189 26 200 62 176 80 151 140 109 183 24 +44 191 172 234 107 21 192 140 99 94 65 54 7 42 24 49 230 20 229 73 212 45 169 +115 180 141 56 200 41 87 121 161 219 231 214 207 1 19 20 219 236 12 55 237 237 +211 72 13 28 141 72 239 152 82 87 100 72 8 241 41 77 32 202 229 47 84 238 184 +228 100 67 210 130 46 111 93 97 189 31 250 162 171 35 90 4 138 199 99 120 193 +113 244 181 93 123 76 90 235 49 251 109 188 63 144 186 138 184 223 61 208 215 +175 107 6 53 81 114 207 237 221 161 224 18 73 202 208 210 125 248 11 98 131 250 +167 221 146 85 211 88 63 139 136 27 189 5 111 103 186 148 21 171 51 140 104 133 +165 49 225 233 129 78 5 106 64 86 153 55 232 187 111 77 58 89 36 32 223 66 6 74 +170 62 197 169 110 130 41 61 234 102 234 92 145 133 155 201 14 243 208 200 36 +48 21 166 1 40 109 178 147 ^ +522 0 179 196 200 34 251 241 156 51 23 75 118 41 193 202 90 93 236 125 242 125 +101 151 130 14 218 34 106 41 197 173 55 112 37 108 211 65 174 142 136 159 22 19 +245 127 16 19 131 101 10 133 20 104 122 126 184 227 9 187 225 208 90 230 7 131 +105 213 121 39 137 105 95 147 45 23 216 92 35 75 114 70 205 206 34 110 12 185 +169 111 95 6 71 29 79 203 32 195 144 161 82 64 228 92 8 104 126 74 172 223 65 +170 194 171 140 221 36 21 164 198 5 102 211 206 148 136 18 48 25 131 215 36 162 +161 192 142 14 214 63 141 45 141 190 86 149 219 94 182 198 115 157 252 73 203 +173 192 115 43 226 67 85 62 172 227 13 135 190 227 123 213 231 94 178 227 150 +161 196 90 234 210 119 124 14 104 8 100 178 109 153 167 82 201 231 98 149 215 +146 217 179 59 174 28 133 130 159 163 248 239 9 183 254 243 71 174 24 162 165 +163 107 10 15 46 110 8 214 204 115 39 23 79 89 6 189 3 73 85 176 198 1 154 246 +210 115 153 49 108 207 117 209 146 103 176 53 56 172 113 10 129 72 116 126 70 +201 3 69 114 211 202 200 171 22 247 42 139 20 218 148 132 70 83 29 75 67 199 88 +178 113 124 155 78 2 214 67 89 33 160 246 69 118 159 167 196 204 5 216 237 212 +34 247 38 191 55 222 92 149 78 120 211 61 226 177 140 103 39 27 50 54 25 245 +241 42 25 249 212 30 21 50 195 254 239 123 186 28 106 182 171 167 192 1 17 220 +181 229 65 29 220 177 26 77 33 164 194 57 137 215 150 165 167 78 230 11 102 93 +232 177 22 129 68 168 138 74 145 20 77 174 138 188 171 26 218 7 158 76 201 117 +72 120 74 35 197 59 52 83 151 20 214 177 144 51 27 46 106 37 249 185 59 56 54 +139 16 15 160 136 14 100 37 112 182 53 170 198 119 128 240 69 4 156 161 78 116 +240 96 207 121 157 134 99 209 36 25 135 186 1 158 194 175 111 209 32 77 147 190 +200 175 225 235 38 195 3 187 88 205 61 89 151 134 217 206 30 162 24 166 113 128 +103 66 253 15 50 58 228 210 5 98 8 218 152 80 35 79 62 58 224 7 17 102 207 3 +183 140 217 65 56 168 165 22 133 16 133 157 107 128 244 12 ^ +517 1 218 150 217 59 81 203 140 217 148 45 193 82 116 122 93 236 7 11 127 242 +235 123 155 246 125 238 148 134 126 72 27 247 67 27 50 162 22 247 127 153 45 +133 213 121 151 159 105 209 231 36 166 217 177 140 188 53 50 222 148 242 67 87 +145 157 250 181 227 177 51 224 63 108 97 174 194 24 162 250 152 132 182 80 33 +189 84 60 83 118 37 216 235 94 60 251 154 47 48 110 120 238 208 229 121 43 218 +90 91 64 110 12 40 193 111 211 117 64 170 107 35 164 76 54 141 101 4 183 53 79 +60 143 213 32 187 169 194 84 31 245 123 66 25 135 39 23 160 78 29 102 95 62 166 +20 46 135 128 244 150 246 154 76 143 105 91 172 51 27 158 103 37 108 37 79 199 +84 228 119 128 95 91 4 15 17 69 2 11 187 80 230 94 89 89 149 244 239 210 144 18 +42 48 139 215 233 179 163 252 67 255 181 167 82 56 253 98 8 42 137 103 205 144 +47 137 43 110 149 76 203 200 86 143 16 127 182 140 128 184 55 251 183 142 43 50 +54 81 232 9 212 119 236 36 106 122 182 169 223 179 26 185 57 166 80 141 130 99 +178 24 44 191 167 219 92 6 187 140 99 89 60 54 249 42 19 44 220 5 214 63 197 30 +164 105 180 136 41 195 26 77 116 151 219 231 204 202 1 9 15 214 231 7 40 222 +237 206 57 255 13 131 72 224 152 72 87 85 62 255 241 36 77 27 187 229 32 79 228 +179 223 90 62 195 115 41 106 93 87 174 26 245 152 161 20 75 4 123 184 84 120 +178 113 234 181 78 118 66 85 230 34 251 94 178 53 139 186 138 184 223 61 193 +200 175 107 6 38 81 114 207 227 206 146 219 3 73 197 198 200 115 238 11 98 116 +240 152 221 146 70 201 88 58 139 126 12 189 252 96 93 176 138 16 156 51 135 99 +118 155 49 220 233 119 68 96 64 81 143 45 222 177 111 62 58 79 31 17 218 61 253 +69 170 47 197 169 105 120 41 46 224 92 234 92 145 128 155 186 256 243 208 200 +26 48 21 156 248 40 104 178 221 175 196 196 28 249 239 150 49 23 71 114 39 191 +196 88 87 234 121 240 123 95 151 130 10 214 34 102 35 193 171 49 112 35 104 207 +59 170 136 130 159 16 19 241 125 213 ^ +529 1 15 127 93 2 121 8 104 114 126 176 223 1 183 225 196 90 230 3 119 93 201 +117 39 125 97 91 147 41 19 216 80 35 75 110 58 193 198 26 98 8 185 161 103 95 +257 71 21 71 199 24 183 144 149 74 52 228 88 255 96 114 66 172 215 61 166 190 +167 128 209 36 13 152 186 256 94 199 202 136 128 10 40 21 131 203 32 162 161 +184 142 14 210 55 141 37 129 186 78 141 215 82 170 198 107 145 244 65 195 173 +192 103 35 214 63 81 54 164 215 1 123 182 227 111 213 227 90 170 219 150 153 +184 82 230 202 115 124 2 100 4 96 174 109 141 155 78 201 219 90 149 215 142 213 +167 47 162 20 133 118 155 159 248 235 9 183 246 239 59 170 20 154 161 163 99 6 +11 38 106 8 206 204 111 35 15 67 89 253 181 250 69 85 164 194 256 154 242 210 +115 145 45 108 203 113 209 138 103 176 45 48 160 105 10 121 68 108 122 66 193 +258 69 106 207 202 196 171 18 239 38 127 12 214 144 128 70 83 29 71 67 191 84 +166 109 120 151 70 2 202 55 81 33 160 246 61 106 147 159 188 192 1 204 229 204 +30 247 38 187 55 222 84 145 66 112 211 53 226 173 132 99 27 15 46 46 25 241 233 +34 17 241 212 30 9 42 195 254 239 119 174 28 94 178 159 167 188 252 5 212 169 +221 65 17 220 169 22 69 25 160 186 57 137 207 142 153 163 78 222 3 98 89 232 +177 22 129 68 168 126 74 133 16 65 174 130 184 163 18 218 254 158 72 197 109 60 +108 62 23 185 59 52 71 139 20 214 165 132 39 23 46 106 29 249 173 51 52 50 135 +12 15 148 136 10 100 25 100 182 49 158 190 107 124 240 57 255 156 157 74 112 +232 96 195 113 149 134 95 197 28 13 131 182 248 154 182 167 107 205 28 73 135 +190 188 171 217 235 30 187 254 179 76 205 49 77 143 130 205 206 26 158 12 154 +101 120 91 66 253 3 38 46 224 198 5 94 206 144 68 27 75 50 54 224 258 9 102 199 +3 179 136 209 57 56 160 165 14 129 8 125 157 95 116 240 36 212 148 217 57 77 +203 134 213 146 43 193 80 116 122 87 236 7 9 123 242 231 119 153 244 125 238 +142 132 120 70 23 245 63 21 50 156 16 243 127 153 45 129 207 121 149 155 99 205 +227 30 166 211 57 ^ +548 0 134 188 53 47 219 148 236 58 84 142 148 247 172 224 174 45 221 63 99 97 +171 194 15 156 250 149 132 179 71 30 183 78 54 77 118 37 207 232 94 60 248 151 +47 42 110 117 235 205 223 112 43 212 81 82 61 101 12 34 190 102 208 117 58 167 +104 29 164 76 45 138 101 1 180 50 70 51 143 210 32 181 163 191 81 31 245 123 63 +16 135 30 17 154 75 26 93 92 62 163 14 43 129 119 244 144 240 148 70 134 105 91 +166 42 27 155 94 28 102 31 79 199 84 225 110 128 89 85 255 9 17 60 259 5 187 74 +224 91 83 80 146 238 233 207 138 18 39 39 133 209 230 179 154 252 64 255 175 +158 82 50 247 89 2 33 128 100 199 135 41 131 34 107 140 67 200 197 86 140 16 +124 176 137 122 178 52 245 174 139 37 41 48 72 226 6 206 119 233 30 100 116 173 +160 214 173 26 176 54 160 80 135 124 93 175 24 44 191 164 210 83 257 184 140 99 +86 57 54 243 42 16 41 214 256 205 57 188 21 161 99 180 133 32 192 17 71 113 145 +219 231 198 199 1 3 12 211 228 4 31 213 237 203 48 249 4 125 72 215 152 66 87 +76 56 252 241 33 77 24 178 229 23 76 222 176 220 84 59 186 106 38 103 93 81 165 +23 242 146 155 11 66 4 114 175 75 120 169 113 228 181 69 115 60 82 227 25 251 +85 172 47 136 186 138 184 223 61 184 191 175 107 6 29 81 114 207 221 197 137 +216 254 73 194 192 194 109 232 11 98 107 234 143 221 146 61 195 88 55 139 120 3 +189 249 87 87 170 132 13 147 51 132 96 109 149 49 217 233 113 62 257 90 64 78 +137 39 216 171 111 53 58 73 28 8 215 58 250 66 170 38 197 169 102 114 41 37 218 +86 234 92 145 125 155 177 250 243 208 200 20 48 21 150 245 40 101 178 218 169 +196 190 19 246 236 141 46 23 65 108 36 188 187 85 78 231 115 237 120 86 151 130 +4 208 34 96 26 187 168 40 112 32 98 201 50 164 127 121 159 7 19 235 122 1 14 +126 91 118 5 104 112 126 174 222 259 182 225 193 90 230 2 116 90 198 116 39 122 +95 90 147 40 18 216 77 35 75 109 55 190 196 24 95 7 185 159 101 95 256 71 19 69 +198 22 180 144 146 72 49 228 87 253 94 111 64 172 213 60 165 189 166 125 206 36 +11 149 183 255 92 196 201 133 126 8 38 20 131 213 ^ +547 0 29 162 161 178 142 14 207 49 141 31 120 183 72 135 212 73 161 198 101 136 +238 59 189 173 192 94 29 205 60 78 48 158 206 254 114 176 227 102 213 224 87 +164 213 150 147 175 76 227 196 112 124 255 97 1 93 171 109 132 146 75 201 210 +84 149 215 139 210 158 38 153 14 133 109 152 156 248 232 9 183 240 236 50 167 +17 148 158 163 93 3 8 32 103 8 200 204 108 32 9 58 89 247 175 244 66 85 155 191 +256 154 239 210 115 139 42 108 200 110 209 132 103 176 39 42 151 99 10 115 65 +102 119 63 187 258 69 100 204 202 193 171 15 233 35 118 6 211 141 125 70 83 29 +68 67 185 81 157 106 117 148 64 2 193 46 75 33 160 246 55 97 138 153 182 183 +260 195 223 198 27 247 38 184 55 222 78 142 57 106 211 47 226 170 126 96 18 6 +43 40 25 238 227 28 11 235 212 30 36 195 254 239 116 165 28 85 175 150 167 185 +249 258 206 160 215 65 8 220 163 19 63 19 157 180 57 137 201 136 144 160 78 216 +259 95 86 232 177 22 129 68 168 117 74 124 13 56 174 124 181 157 12 218 248 158 +69 194 103 51 99 53 14 176 59 52 62 130 20 214 156 123 30 20 46 106 23 249 164 +45 49 47 132 9 15 139 136 7 100 16 91 182 46 149 184 98 121 240 48 252 156 154 +71 109 226 96 186 107 143 134 92 188 22 4 128 179 242 151 173 161 104 202 25 70 +126 190 179 168 211 235 24 181 251 173 67 205 40 68 137 127 196 206 23 155 3 +145 92 114 82 66 253 256 29 37 221 189 5 91 256 197 138 59 21 72 41 51 224 255 +3 102 193 3 176 133 203 51 56 154 165 8 126 2 119 157 86 107 237 33 203 145 217 +54 71 203 125 207 143 40 193 77 116 122 78 236 7 6 117 242 225 113 150 241 125 +238 133 129 111 67 17 242 57 12 50 147 7 237 127 153 45 123 198 121 146 149 90 +199 221 21 166 202 162 130 188 53 45 217 148 232 52 82 140 142 245 166 222 172 +41 219 63 93 97 169 194 9 152 250 147 132 177 65 28 179 74 50 73 118 37 201 230 +94 60 246 149 47 38 110 115 233 203 219 106 43 208 75 76 59 95 12 30 188 96 206 +117 54 165 102 25 164 76 39 136 101 261 178 48 64 45 143 208 32 177 159 189 79 +31 245 123 61 10 135 24 13 150 73 24 87 90 62 161 10 41 125 209 ^ +542 1 244 136 232 140 62 122 105 91 158 30 27 151 82 16 94 23 79 199 84 221 98 +128 81 77 247 1 17 48 259 261 187 66 216 87 75 68 142 230 225 203 130 18 35 27 +125 201 226 179 142 252 60 255 167 146 82 42 239 77 258 21 116 96 191 123 33 +123 22 103 128 55 196 193 86 136 16 120 168 133 114 170 48 237 162 135 29 29 40 +60 218 2 198 119 229 22 92 108 161 148 202 165 26 164 50 152 80 127 116 85 171 +24 44 191 160 198 71 249 180 140 99 82 53 54 235 42 12 37 206 248 193 49 176 9 +157 91 180 129 20 188 5 63 109 137 219 231 190 195 1 259 8 207 224 19 201 237 +199 36 241 256 117 72 203 152 58 87 64 48 248 241 29 77 20 166 229 11 72 214 +172 216 76 55 174 94 34 99 93 73 153 19 238 138 147 263 54 4 102 163 63 120 157 +113 220 181 57 111 52 78 223 13 251 73 164 39 132 186 138 184 223 61 172 179 +175 107 6 17 81 114 207 213 185 125 212 246 73 190 184 186 101 224 11 98 95 226 +131 221 146 49 187 88 51 139 112 255 189 245 75 79 162 124 9 135 51 128 92 97 +141 49 213 233 105 54 257 82 64 74 129 31 208 163 111 41 58 65 24 260 211 54 +246 62 170 26 197 169 98 106 41 25 210 78 234 92 145 121 155 165 242 243 208 +200 12 48 21 142 241 40 97 178 214 161 196 182 7 242 232 129 42 23 57 100 32 +184 175 81 66 227 107 233 116 74 151 130 260 200 34 88 14 179 164 28 112 28 90 +193 38 156 115 109 159 259 19 227 118 253 10 122 83 256 106 257 104 104 126 166 +218 255 178 225 181 90 230 262 104 78 186 112 39 110 87 86 147 36 14 216 65 35 +75 105 43 178 188 16 83 3 185 151 93 95 252 71 11 61 194 14 168 144 134 64 37 +228 83 245 86 99 56 172 205 56 161 185 162 113 194 36 3 137 171 251 84 184 197 +121 118 30 16 131 188 27 162 161 174 142 14 205 45 141 27 114 181 68 131 210 67 +155 198 97 130 234 55 185 173 192 88 25 199 58 76 44 154 200 250 108 172 227 96 +213 222 85 160 209 150 143 169 72 225 192 110 124 251 95 263 91 169 109 126 140 +73 201 204 80 149 215 137 208 152 32 147 10 133 103 150 154 248 230 9 183 236 +234 44 165 15 144 156 163 89 1 6 28 101 8 196 204 106 164 ^ +567 0 1 46 89 239 167 236 62 85 143 187 256 154 235 210 115 131 38 108 196 106 +209 124 103 176 31 34 139 91 10 107 61 94 115 59 179 258 69 92 200 202 189 171 +11 225 31 106 264 207 137 121 70 83 29 64 67 177 77 145 102 113 144 56 2 181 34 +67 33 160 246 47 85 126 145 174 171 260 183 215 190 23 247 38 180 55 222 70 138 +45 98 211 39 226 166 118 92 6 260 39 32 25 234 219 20 3 227 212 30 254 28 195 +254 239 112 153 28 73 171 138 167 181 245 250 198 148 207 65 262 220 155 15 55 +11 153 172 57 137 193 128 132 156 78 208 255 91 82 232 177 22 129 68 168 105 74 +112 9 44 174 116 177 149 4 218 240 158 65 190 95 39 87 41 2 164 59 52 50 118 20 +214 144 111 18 16 46 106 15 249 152 37 45 43 128 5 15 127 136 3 100 4 79 182 42 +137 176 86 117 240 36 248 156 150 67 105 218 96 174 99 135 134 88 176 14 258 +124 175 234 147 161 153 100 198 21 66 114 190 167 164 203 235 16 173 247 165 55 +205 28 56 129 123 184 206 19 151 257 133 80 106 70 66 253 248 17 25 217 177 5 +87 252 185 130 47 13 68 29 47 224 251 261 102 185 3 172 129 195 43 56 146 165 +122 260 111 157 74 95 233 29 191 141 217 50 63 203 113 199 139 36 193 73 116 +122 66 236 7 2 109 242 217 105 146 237 125 238 121 125 99 63 9 238 49 50 135 +261 229 127 153 45 115 186 121 142 141 78 191 213 9 166 190 150 122 188 53 41 +213 148 224 40 78 136 130 241 154 218 168 33 215 63 81 97 165 194 263 144 250 +143 132 173 53 24 171 66 42 65 118 37 189 226 94 60 242 145 47 30 110 111 229 +199 211 94 43 200 63 64 55 83 12 22 184 84 202 117 46 161 98 17 164 76 27 132 +101 261 174 44 52 33 143 204 32 169 151 185 75 31 245 123 57 264 135 12 5 142 +69 20 75 86 62 157 2 37 117 101 244 132 228 136 58 116 105 91 154 24 27 149 76 +10 90 19 79 199 84 219 92 128 77 73 243 263 17 42 259 259 187 62 212 85 71 62 +140 226 221 201 126 18 33 21 121 197 224 179 136 252 58 255 163 140 82 38 235 +71 256 15 110 94 187 117 29 119 16 101 122 49 194 191 86 134 16 118 164 131 110 +166 46 233 156 133 25 23 36 54 214 194 119 227 18 88 104 155 142 196 161 26 158 +48 148 80 123 112 81 169 24 44 191 158 192 65 245 178 140 223 ^ +551 1 78 49 54 227 42 8 33 198 240 181 41 164 265 153 83 180 125 8 184 261 55 +105 129 219 231 182 191 1 255 4 203 220 264 7 189 237 195 24 233 248 109 72 191 +152 50 87 52 40 244 241 25 77 16 154 229 267 68 206 168 212 68 51 162 82 30 95 +93 65 141 15 234 130 139 255 42 4 90 151 51 120 145 113 212 181 45 107 44 74 +219 1 251 61 156 31 128 186 138 184 223 61 160 167 175 107 6 5 81 114 207 205 +173 113 208 238 73 186 176 178 93 216 11 98 83 218 119 221 146 37 179 88 47 139 +104 247 189 241 63 71 154 116 5 123 51 124 88 85 133 49 209 233 97 46 257 74 64 +70 121 23 200 155 111 29 58 57 20 252 207 50 242 58 170 14 197 169 94 98 41 13 +202 70 234 92 145 117 155 153 234 243 208 200 4 48 21 134 237 40 93 178 210 153 +196 174 263 238 228 117 38 23 49 92 28 180 163 77 54 223 99 229 112 62 151 130 +256 192 34 80 2 171 160 16 112 24 82 185 26 148 103 97 159 251 19 219 114 245 6 +118 75 252 94 249 104 96 126 158 214 251 174 225 169 90 230 262 92 66 174 108 +39 98 79 82 147 32 10 216 53 35 75 101 31 166 180 8 71 267 185 143 85 95 248 71 +3 53 190 6 156 144 122 56 25 228 79 237 78 87 48 172 197 52 157 181 158 101 182 +36 263 125 159 247 76 172 193 109 110 260 22 12 131 176 23 162 161 166 142 14 +201 37 141 19 102 177 60 123 206 55 143 198 89 118 226 47 177 173 192 76 17 187 +54 72 36 146 188 242 96 164 227 84 213 218 81 152 201 150 135 157 64 221 184 +106 124 243 91 263 87 165 109 114 128 69 201 192 72 149 215 133 204 140 20 135 +2 133 91 146 150 248 226 9 183 228 230 32 161 11 136 152 163 81 265 2 20 97 8 +188 204 102 26 265 40 89 235 163 232 60 85 137 185 256 154 233 210 115 127 36 +108 194 104 209 120 103 176 27 30 133 87 10 103 59 90 113 57 175 258 69 88 198 +202 187 171 9 221 29 100 262 205 135 119 70 83 29 62 67 173 75 139 100 111 142 +52 2 175 28 63 33 160 246 43 79 120 141 170 165 260 177 211 186 21 247 38 178 +55 222 66 136 39 94 211 35 226 164 114 90 256 37 28 25 232 215 16 267 223 212 +30 250 24 195 254 239 110 147 28 67 169 132 167 179 243 246 194 142 203 65 263 ^ +578 0 220 147 11 47 3 149 164 57 137 185 120 120 152 78 200 251 87 78 232 177 +22 129 68 168 93 74 100 5 32 174 108 173 141 266 218 232 158 61 186 87 27 75 29 +260 152 59 52 38 106 20 214 132 99 6 12 46 106 7 249 140 29 41 39 124 1 15 115 +136 269 100 262 67 182 38 125 168 74 113 240 24 244 156 146 63 101 210 96 162 +91 127 134 84 164 6 250 120 171 226 143 149 145 96 194 17 62 102 190 155 160 +195 235 8 165 243 157 43 205 16 44 121 119 172 206 15 147 249 121 68 98 58 66 +253 240 5 13 213 165 5 83 248 173 122 35 5 64 17 43 224 247 257 102 177 3 168 +125 187 35 56 138 165 262 118 256 103 157 62 83 229 25 179 137 217 46 55 203 +101 191 135 32 193 69 116 122 54 236 7 268 101 242 209 97 142 233 125 238 109 +121 87 59 1 234 41 258 50 123 253 221 127 153 45 107 174 121 138 133 66 183 205 +267 166 178 138 114 188 53 37 209 148 216 28 74 132 118 237 142 214 164 25 211 +63 69 97 161 194 255 136 250 139 132 169 41 20 163 58 34 57 118 37 177 222 94 +60 238 141 47 22 110 107 225 195 203 82 43 192 51 52 51 71 12 14 180 72 198 117 +38 157 94 9 164 76 15 128 101 261 170 40 40 21 143 200 32 161 143 181 71 31 245 +123 53 256 135 267 134 65 16 63 82 62 153 264 33 109 89 244 124 220 128 50 104 +105 91 146 12 27 145 64 268 82 11 79 199 84 215 80 128 69 65 235 259 17 30 259 +255 187 54 204 81 63 50 136 218 213 197 118 18 29 9 113 189 220 179 124 252 54 +255 155 128 82 30 227 59 252 3 98 90 179 105 21 111 4 97 110 37 190 187 86 130 +16 114 156 127 102 158 42 225 144 129 17 11 28 42 206 266 186 119 223 10 80 96 +143 130 184 153 26 146 44 140 80 115 104 73 165 24 44 191 154 180 53 237 174 +140 99 76 47 54 223 42 6 31 194 236 175 37 158 261 151 79 180 123 2 182 257 51 +103 125 219 231 178 189 1 253 2 201 218 264 1 183 237 193 18 229 244 105 72 185 +152 46 87 46 36 242 241 23 77 14 148 229 263 66 202 166 210 64 49 156 76 28 93 +93 61 135 13 232 126 135 251 36 4 84 145 45 120 139 113 208 181 39 105 40 72 +217 265 251 55 152 27 126 186 138 184 223 61 154 161 175 107 6 269 81 114 207 +201 167 107 206 234 73 184 172 174 89 212 11 98 77 214 113 221 146 31 175 88 45 +139 100 243 189 213 ^ +578 1 51 63 146 108 1 111 51 120 84 73 125 49 205 233 89 38 257 66 64 66 113 15 +192 147 111 17 58 49 16 244 203 46 238 54 170 2 197 169 90 90 41 1 194 62 234 +92 145 113 155 141 226 243 208 200 268 48 21 126 233 40 89 178 206 145 196 166 +255 234 224 105 34 23 41 84 24 176 151 73 42 219 91 225 108 50 151 130 252 184 +34 72 262 163 156 4 112 20 74 177 14 140 91 85 159 243 19 211 110 237 2 114 67 +248 82 241 104 88 126 150 210 247 170 225 157 90 230 262 80 54 162 104 39 86 71 +78 147 28 6 216 41 35 75 97 19 154 172 59 267 185 135 77 95 244 71 267 45 186 +270 144 144 110 48 13 228 75 229 70 75 40 172 189 48 153 177 154 89 170 36 259 +113 147 243 68 160 189 97 102 256 14 8 131 164 19 162 161 158 142 14 197 29 141 +11 90 173 52 115 202 43 131 198 81 106 218 39 169 173 192 64 9 175 50 68 28 138 +176 234 84 156 227 72 213 214 77 144 193 150 127 145 56 217 176 102 124 235 87 +263 83 161 109 102 116 65 201 180 64 149 215 129 200 128 8 123 266 133 79 142 +146 248 222 9 183 220 226 20 157 7 128 148 163 73 265 270 12 93 8 180 204 98 22 +261 28 89 227 155 224 56 85 125 181 256 154 229 210 115 119 32 108 190 100 209 +112 103 176 19 22 121 79 10 95 55 82 109 53 167 258 69 80 194 202 183 171 5 213 +25 88 258 201 131 115 70 83 29 58 67 165 71 127 96 107 138 44 2 163 16 55 33 +160 246 35 67 108 133 162 153 260 165 203 178 17 247 38 174 55 222 58 132 27 86 +211 27 226 160 106 86 260 248 33 20 25 228 207 8 263 215 212 30 242 16 195 254 +239 106 135 28 55 165 120 167 175 239 238 186 130 195 65 250 220 143 9 43 271 +147 160 57 137 181 116 114 150 78 196 249 85 76 232 177 22 129 68 168 87 74 94 +3 26 174 104 171 137 264 218 228 158 59 184 83 21 69 23 256 146 59 52 32 100 20 +214 126 93 10 46 106 3 249 134 25 39 37 122 271 15 109 136 269 100 258 61 182 +36 119 164 68 111 240 18 242 156 144 61 99 206 96 156 87 123 134 82 158 2 246 +118 169 222 141 143 141 94 192 15 60 96 190 149 158 191 235 4 161 241 153 37 +205 10 38 117 117 166 206 13 145 245 115 62 94 52 66 253 236 271 7 211 159 5 81 +246 167 118 29 1 62 11 41 224 245 255 102 173 3 166 123 183 31 56 134 165 260 +116 254 81 ^ +583 1 157 50 71 225 21 167 133 217 42 47 203 89 183 131 28 193 65 116 122 42 +236 7 268 93 242 201 89 138 229 125 238 97 117 75 55 267 230 33 250 50 111 245 +213 127 153 45 99 162 121 134 125 54 175 197 259 166 166 126 106 188 53 33 205 +148 208 16 70 128 106 233 130 210 160 17 207 63 57 97 157 194 247 128 250 135 +132 165 29 16 155 50 26 49 118 37 165 218 94 60 234 137 47 14 110 103 221 191 +195 70 43 184 39 40 47 59 12 6 176 60 194 117 30 153 90 1 164 76 3 124 101 261 +166 36 28 9 143 196 32 153 135 177 67 31 245 123 49 248 135 262 263 126 61 12 +51 78 62 149 260 29 101 77 244 116 212 120 42 92 105 91 138 27 141 52 260 74 3 +79 199 84 211 68 128 61 57 227 255 17 18 259 251 187 46 196 77 55 38 132 210 +205 193 110 18 25 271 105 181 216 179 112 252 50 255 147 116 82 22 219 47 248 +265 86 86 171 93 13 103 266 93 98 25 186 183 86 126 16 110 148 123 94 150 38 +217 132 125 9 273 20 30 198 266 178 119 219 2 72 88 131 118 172 145 26 134 40 +132 80 107 96 65 161 24 44 191 150 168 41 229 170 140 99 72 43 54 215 42 2 27 +186 228 163 29 146 253 147 71 180 119 264 178 249 43 99 117 219 231 170 185 1 +249 272 197 214 264 263 171 237 189 6 221 236 97 72 173 152 38 87 34 28 238 241 +19 77 10 136 229 255 62 194 162 206 56 45 144 64 24 89 93 53 123 9 228 118 127 +243 24 4 72 133 33 120 127 113 200 181 27 101 32 68 213 257 251 43 144 19 122 +186 138 184 223 61 142 149 175 107 6 261 81 114 207 193 155 95 202 226 73 180 +164 166 81 204 11 98 65 206 101 221 146 19 167 88 41 139 92 235 189 235 45 59 +142 104 273 105 51 118 82 67 121 49 203 233 85 34 257 62 64 64 109 11 188 143 +111 11 58 45 14 240 201 44 236 52 170 270 197 169 88 86 41 269 190 58 234 92 +145 111 155 135 222 243 208 200 266 48 21 122 231 40 87 178 204 141 196 162 251 +232 222 99 32 23 37 80 22 174 145 71 36 217 87 223 106 44 151 130 250 180 34 68 +258 159 154 272 112 18 70 173 8 136 85 79 159 239 19 207 108 233 112 63 246 76 +237 104 84 126 146 208 245 168 225 151 90 230 262 74 48 156 102 39 80 67 76 147 +26 4 216 35 35 75 95 13 148 168 270 53 267 185 131 73 95 242 71 265 41 184 268 +138 144 104 44 7 228 73 225 66 69 36 272 ^ +588 0 181 44 149 173 150 77 158 36 255 101 135 239 60 148 185 85 94 252 6 4 131 +152 15 162 161 150 142 14 193 21 141 3 78 169 44 107 198 31 119 198 73 94 210 +31 161 173 192 52 1 163 46 64 20 130 164 226 72 148 227 60 213 210 73 136 185 +150 119 133 48 213 168 98 124 227 83 263 79 157 109 90 104 61 201 168 56 149 +215 125 196 116 272 111 262 133 67 138 142 248 218 9 183 212 222 8 153 3 120 +144 163 65 265 270 4 89 8 172 204 94 18 257 16 89 219 147 216 52 85 113 177 256 +154 225 210 115 111 28 108 186 96 209 104 103 176 11 14 109 71 10 87 51 74 105 +49 159 258 69 72 190 202 179 171 1 205 21 76 254 197 127 111 70 83 29 54 67 157 +67 115 92 103 134 36 2 151 4 47 33 160 246 27 55 96 125 154 141 260 153 195 170 +13 247 38 170 55 222 50 128 15 78 211 19 226 156 98 82 252 240 29 12 25 224 199 +259 207 212 30 234 8 195 254 239 102 123 28 43 161 108 167 171 235 230 178 118 +187 65 242 220 135 5 35 267 143 152 57 137 173 108 102 146 78 188 245 81 72 232 +177 22 129 68 168 75 74 82 275 14 174 96 167 129 260 218 220 158 55 180 75 9 57 +11 248 134 59 52 20 88 20 214 114 81 264 6 46 106 271 249 122 17 35 33 118 271 +15 97 136 269 100 250 49 182 32 107 156 56 107 240 6 238 156 140 57 95 198 96 +144 79 115 134 78 146 270 238 114 165 214 137 131 133 90 188 11 56 84 190 137 +154 183 235 272 153 237 145 25 205 274 26 109 113 154 206 9 141 237 103 50 86 +40 66 253 228 263 271 207 147 5 77 242 155 110 17 269 58 275 37 224 241 251 102 +165 3 162 119 175 23 56 126 165 256 112 250 91 157 44 65 223 19 161 131 217 40 +43 203 83 179 129 26 193 63 116 122 36 236 7 268 89 242 197 85 136 227 125 238 +91 115 69 53 265 228 29 246 50 105 241 209 127 153 45 95 156 121 132 121 48 171 +193 255 166 160 120 102 188 53 31 203 148 204 10 68 126 100 231 124 208 158 13 +205 63 51 97 155 194 243 124 250 133 132 163 23 14 151 46 22 45 118 37 159 216 +94 60 232 135 47 10 110 101 219 189 191 64 43 180 33 34 45 53 12 2 174 54 192 +117 26 151 88 273 164 76 273 122 101 261 164 34 22 3 143 194 32 149 131 175 65 +31 245 123 47 244 135 258 261 122 59 10 45 76 62 147 258 27 97 71 244 112 208 +116 38 86 105 91 134 270 27 139 46 256 70 275 79 199 160 ^ +594 0 207 56 128 53 49 219 251 17 6 259 247 187 38 188 73 47 26 128 202 197 189 +102 18 21 263 97 173 212 179 100 252 46 255 139 104 82 14 211 35 244 257 74 82 +163 81 5 95 258 89 86 13 182 179 86 122 16 106 140 119 86 142 34 209 120 121 1 +265 12 18 190 266 170 119 215 272 64 80 119 106 160 137 26 122 36 124 80 99 88 +57 157 24 44 191 146 156 29 221 166 140 99 68 39 54 207 42 276 23 178 220 151 +21 134 245 143 63 180 115 256 174 241 35 95 109 219 231 162 181 1 245 272 193 +210 264 255 159 237 185 272 213 228 89 72 161 152 30 87 22 20 234 241 15 77 6 +124 229 247 58 186 158 202 48 41 132 52 20 85 93 45 111 5 224 110 119 235 12 4 +60 121 21 120 115 113 192 181 15 97 24 64 209 249 251 31 136 11 118 186 138 184 +223 61 130 137 175 107 6 253 81 114 207 185 143 83 198 218 73 176 156 158 73 +196 11 98 53 198 89 221 146 7 159 88 37 139 84 227 189 231 33 51 134 96 273 93 +51 114 78 55 113 49 199 233 77 26 257 54 64 60 101 3 180 135 111 277 58 37 10 +232 197 40 232 48 170 262 197 169 84 78 41 261 182 50 234 92 145 107 155 123 +214 243 208 200 262 48 21 114 227 40 83 178 200 133 196 154 243 228 218 87 28 +23 29 72 18 170 133 67 24 213 79 219 102 32 151 130 246 172 34 60 250 151 150 +264 112 14 62 165 274 128 73 67 159 231 19 199 104 225 274 108 55 242 64 229 +104 76 126 138 204 241 164 225 139 90 230 262 62 36 144 98 39 68 59 72 147 22 +216 23 35 75 91 1 136 160 266 41 267 185 123 65 95 238 71 261 33 180 264 126 +144 92 36 273 228 69 217 58 57 28 172 177 42 147 171 148 71 152 36 253 95 129 +237 56 142 183 79 90 250 2 2 131 146 13 162 161 146 142 14 191 17 141 277 72 +167 40 103 196 25 113 198 69 88 206 27 157 173 192 46 275 157 44 62 16 126 158 +222 66 144 227 54 213 208 71 132 181 150 115 127 44 211 164 96 124 223 81 263 +77 155 109 84 98 59 201 162 52 149 215 123 194 110 268 105 260 133 61 136 140 +248 216 9 183 208 220 2 151 1 116 142 163 61 265 270 87 8 168 204 92 16 255 10 +89 215 143 212 50 85 107 175 256 154 223 210 115 107 26 108 184 94 209 100 103 +176 7 10 103 67 10 83 49 70 103 47 155 258 69 68 188 202 177 171 277 201 19 70 +252 195 125 109 70 83 29 52 67 153 65 109 90 101 132 32 2 145 276 43 33 160 246 +23 259 ^ +600 1 87 119 148 132 260 144 189 164 10 247 38 167 55 222 44 125 6 72 211 13 +226 153 92 79 246 234 26 6 25 221 193 273 256 201 212 30 228 2 195 254 239 99 +114 28 34 158 99 167 168 232 224 172 109 181 65 236 220 129 2 29 264 140 146 57 +137 167 102 93 143 78 182 242 78 69 232 177 22 129 68 168 66 74 73 275 5 174 90 +164 123 257 218 214 158 52 177 69 48 2 242 125 59 52 11 79 20 214 105 72 258 3 +46 106 268 249 113 11 32 30 115 271 15 88 136 269 100 244 40 182 29 98 150 47 +104 240 276 235 156 137 54 92 192 96 135 73 109 134 75 137 267 232 111 162 208 +134 122 127 87 185 8 53 75 190 128 151 177 235 269 147 234 139 16 205 268 17 +103 110 145 206 6 138 231 94 41 80 31 66 253 222 257 265 204 138 5 74 239 146 +104 8 266 55 269 34 224 238 248 102 159 3 159 116 169 17 56 120 165 253 109 247 +85 157 35 56 220 16 152 128 217 37 37 203 74 173 126 23 193 60 116 122 27 236 7 +268 83 242 191 79 133 224 125 238 82 112 60 50 262 225 23 240 50 96 235 203 127 +153 45 89 147 121 129 115 39 165 187 249 166 151 111 96 188 53 28 200 148 198 1 +65 123 91 228 115 205 155 7 202 63 42 97 152 194 237 118 250 130 132 160 14 11 +145 40 16 39 118 37 150 213 94 60 229 132 47 4 110 98 216 186 185 55 43 174 24 +25 42 44 12 275 171 45 189 117 20 148 85 270 164 76 267 119 101 261 161 31 13 +273 143 191 32 143 125 172 62 31 245 123 44 238 135 252 258 116 56 7 36 73 62 +144 255 24 91 62 244 106 202 110 32 77 105 91 128 264 27 136 37 250 64 272 79 +199 84 206 53 128 51 47 217 250 17 3 259 246 187 36 186 72 45 23 127 200 195 +188 100 18 20 261 95 171 211 179 97 252 45 255 137 101 82 12 209 32 243 255 71 +81 161 78 3 93 256 88 83 10 181 178 86 121 16 105 138 118 84 140 33 207 117 120 +278 263 10 15 188 266 168 119 214 271 62 78 116 103 157 135 26 119 35 122 80 97 +86 55 156 24 44 191 145 153 26 219 165 140 99 67 38 54 205 42 276 22 176 218 +148 19 131 243 142 61 180 114 254 173 239 33 94 107 219 231 160 180 1 244 272 +192 209 264 253 156 237 184 270 211 226 87 72 158 152 28 87 19 18 233 241 14 77 +5 121 229 245 57 184 157 201 46 40 129 49 19 84 93 43 108 4 223 108 117 233 9 4 +57 118 18 120 112 113 190 181 12 96 22 63 208 247 251 28 134 9 117 186 138 184 +223 61 127 216 ^ +590 1 175 107 6 247 81 114 207 179 134 74 195 212 73 173 150 152 67 190 11 98 +44 192 80 221 146 279 153 88 34 139 78 221 189 228 24 45 128 90 273 84 51 111 +75 46 107 49 196 233 71 20 257 48 64 57 95 278 174 129 111 271 58 31 7 226 194 +37 229 45 170 256 197 169 81 72 41 255 176 44 234 92 145 104 155 114 208 243 +208 200 259 48 21 108 224 40 80 178 197 127 196 148 237 225 215 78 25 23 23 66 +15 167 124 64 15 210 73 216 99 23 151 130 243 166 34 54 244 145 147 258 112 11 +56 159 268 122 64 58 159 225 19 193 101 219 274 105 49 239 55 223 104 70 126 +132 201 238 161 225 130 90 230 262 53 27 135 95 39 59 53 69 147 19 278 216 14 +35 75 88 273 127 154 263 32 267 185 117 59 95 235 71 258 27 177 261 117 144 83 +30 267 228 66 211 52 48 22 172 171 39 144 168 145 62 143 36 250 86 120 234 50 +133 180 70 84 247 277 280 131 137 10 162 161 140 142 14 188 11 141 274 63 164 +34 97 193 16 104 198 63 79 200 21 151 173 192 37 272 148 41 59 10 120 149 216 +57 138 227 45 213 205 68 126 175 150 109 118 38 208 158 93 124 217 78 263 74 +152 109 75 89 56 201 153 46 149 215 120 191 101 262 96 257 133 52 133 137 248 +213 9 183 202 217 274 148 279 110 139 163 55 265 270 275 84 8 162 204 89 13 252 +1 89 209 137 206 47 85 98 172 256 154 220 210 115 101 23 108 181 91 209 94 103 +176 1 4 94 61 10 77 46 64 100 44 149 258 69 62 185 202 174 171 277 195 16 61 +249 192 122 106 70 83 29 49 67 147 62 100 87 98 129 26 2 136 270 37 33 160 246 +17 40 81 115 144 126 260 138 185 160 8 247 38 165 55 222 40 123 68 211 9 226 +151 88 77 242 230 24 2 25 219 189 271 254 197 212 30 224 279 195 254 239 97 108 +28 28 156 93 167 166 230 220 168 103 177 65 232 220 125 25 262 138 142 57 137 +163 98 87 141 78 178 240 76 67 232 177 22 129 68 168 60 74 67 275 280 174 86 +162 119 255 218 210 158 50 175 65 275 42 277 238 119 59 52 5 73 20 214 99 66 +254 1 46 106 266 249 107 7 30 28 113 271 15 82 136 269 100 240 34 182 27 92 146 +41 102 240 272 233 156 135 52 90 188 96 129 69 105 134 73 131 265 228 109 160 +204 132 116 123 85 183 6 51 69 190 122 149 173 235 267 143 232 135 10 205 264 +11 99 108 139 206 4 136 227 88 35 76 25 66 253 218 253 261 202 132 5 72 237 140 +203 ^ +620 0 279 262 51 261 30 224 234 244 102 151 3 155 112 161 9 56 112 165 249 105 +243 77 157 23 44 216 12 140 124 217 33 29 203 62 165 122 19 193 56 116 122 15 +236 7 268 75 242 183 71 129 220 125 238 70 108 48 46 258 221 15 232 50 84 227 +195 127 153 45 81 135 121 125 107 27 157 179 241 166 139 99 88 188 53 24 196 +148 190 272 61 119 79 224 103 201 151 282 198 63 30 97 148 194 229 110 250 126 +132 156 2 7 137 32 8 31 118 37 138 209 94 60 225 128 47 279 110 94 212 182 177 +43 43 166 12 13 38 32 12 271 167 33 185 117 12 144 81 266 164 76 259 115 101 +261 157 27 1 265 143 187 32 135 117 168 58 31 245 123 40 230 135 244 254 108 52 +3 24 69 62 140 251 20 83 50 244 98 194 102 24 65 105 91 120 256 27 132 25 242 +56 268 79 199 84 202 41 128 43 39 209 246 17 274 259 242 187 28 178 68 37 11 +123 192 187 184 92 18 16 253 87 163 207 179 85 252 41 255 129 89 82 4 201 20 +239 247 59 77 153 66 278 85 248 84 71 281 177 174 86 117 16 101 130 114 76 132 +29 199 105 116 274 255 2 3 180 266 160 119 210 267 54 70 104 91 145 127 26 107 +31 114 80 89 78 47 152 24 44 191 141 141 14 211 161 140 99 63 34 54 197 42 276 +18 168 210 136 11 119 235 138 53 180 110 246 169 231 25 90 99 219 231 152 176 1 +240 272 188 205 264 245 144 237 180 262 203 218 79 72 146 152 20 87 7 10 229 +241 10 77 1 109 229 237 53 176 153 197 38 36 117 37 15 80 93 35 96 219 100 109 +225 280 4 45 106 6 120 100 113 182 181 92 14 59 204 239 251 16 126 1 113 186 +138 184 223 61 115 122 175 107 6 243 81 114 207 175 128 68 193 208 73 171 146 +148 63 186 11 98 38 188 74 221 146 275 149 88 32 139 74 217 189 226 18 41 124 +86 273 78 51 109 73 40 103 49 194 233 67 16 257 44 64 55 91 276 170 125 111 267 +58 27 5 222 192 35 227 43 170 252 197 169 79 68 41 251 172 40 234 92 145 102 +155 108 204 243 208 200 257 48 21 104 222 40 78 178 195 123 196 144 233 223 213 +72 23 23 19 62 13 165 118 62 9 208 69 214 97 17 151 130 241 162 34 50 240 141 +145 254 112 9 52 155 264 118 58 52 159 221 19 189 99 215 274 103 45 237 49 219 +104 66 126 128 199 236 159 225 124 90 230 262 47 21 129 93 39 53 49 67 147 17 +278 216 8 35 75 86 269 121 150 261 26 267 185 113 55 95 233 71 256 23 175 259 +111 144 77 26 263 228 64 207 48 42 18 172 167 37 142 166 143 56 137 36 248 80 +114 232 46 127 257 ^ +605 1 58 76 243 273 280 131 125 6 162 161 132 142 14 184 3 141 270 51 160 26 89 +189 4 92 198 55 67 192 13 143 173 192 25 268 136 37 55 2 112 137 208 45 130 227 +33 213 201 64 118 167 150 101 106 30 204 150 89 124 209 74 263 70 148 109 63 77 +52 201 141 38 149 215 116 187 89 254 84 253 133 40 129 133 248 209 9 183 194 +213 266 144 279 102 135 163 47 265 270 271 80 8 154 204 85 9 248 274 89 201 129 +198 43 85 86 168 256 154 216 210 115 93 19 108 177 87 209 86 103 176 278 281 82 +53 10 69 42 56 96 40 141 258 69 54 181 202 170 171 277 187 12 49 245 188 118 +102 70 83 29 45 67 139 58 88 83 94 125 18 2 124 262 29 33 160 246 9 28 69 107 +136 114 260 126 177 152 4 247 38 161 55 222 32 119 273 60 211 1 226 147 80 73 +234 222 20 279 25 215 181 267 250 189 212 30 216 275 195 254 239 93 96 28 16 +152 81 167 162 226 212 160 91 169 65 224 220 117 281 17 258 134 134 57 137 155 +90 75 137 78 170 236 72 63 232 177 22 129 68 168 48 74 55 275 272 174 78 158 +111 251 218 202 158 46 171 57 267 30 269 230 107 59 52 278 61 20 214 87 54 246 +282 46 106 262 249 95 284 26 24 109 271 15 70 136 269 100 232 22 182 23 80 138 +29 98 240 264 229 156 131 48 86 180 96 117 61 97 134 69 119 261 220 105 156 196 +128 104 115 81 179 2 47 57 190 110 145 165 235 263 135 228 127 283 205 256 284 +91 104 127 206 132 219 76 23 68 13 66 253 210 245 253 198 120 5 68 233 128 92 +275 260 49 257 28 224 232 242 102 147 3 153 110 157 5 56 108 165 247 103 241 73 +157 17 38 214 10 134 122 217 31 25 203 56 161 120 17 193 54 116 122 9 236 7 268 +71 242 179 67 127 218 125 238 64 106 42 44 256 219 11 228 50 78 223 191 127 153 +45 77 129 121 123 103 21 153 175 237 166 133 93 84 188 53 22 194 148 186 268 59 +117 73 222 97 199 149 280 196 63 24 97 146 194 225 106 250 124 132 154 281 5 +133 28 4 27 118 37 132 207 94 60 223 126 47 277 110 92 210 180 173 37 43 162 6 +7 36 26 12 269 165 27 183 117 8 142 79 264 164 76 255 113 101 261 155 25 280 +261 143 185 32 131 113 166 56 31 245 123 38 226 135 240 252 104 50 1 18 67 62 +138 249 18 79 44 244 94 190 98 20 59 105 91 116 252 27 130 19 238 52 266 79 199 +84 200 35 128 39 35 205 244 17 270 259 240 187 24 174 66 33 5 121 188 183 182 +88 18 14 249 83 159 205 179 79 252 186 ^ +615 0 255 121 77 82 283 193 8 235 239 47 73 145 54 274 77 240 80 59 273 173 170 +86 113 16 97 122 110 68 124 25 191 93 112 270 247 281 278 172 266 152 119 206 +263 46 62 92 79 133 119 26 95 27 106 80 81 70 39 148 24 44 191 137 129 2 203 +157 140 99 59 30 54 189 42 276 14 160 202 124 3 107 227 134 45 180 106 238 165 +223 17 86 91 219 231 144 172 1 236 272 184 201 264 237 132 237 176 254 195 210 +71 72 134 152 12 87 282 2 225 241 6 77 284 97 229 229 49 168 149 193 30 32 105 +25 11 76 93 27 84 283 215 92 101 217 272 4 33 94 281 120 88 113 174 181 275 88 +6 55 200 231 251 4 118 280 109 186 138 184 223 61 103 110 175 107 6 235 81 114 +207 167 116 56 189 200 73 167 138 140 55 178 11 98 26 180 62 221 146 267 141 88 +28 139 66 209 189 222 6 33 116 78 273 66 51 105 69 28 95 49 190 233 59 8 257 36 +64 51 83 272 162 117 111 259 58 19 1 214 188 31 223 39 170 244 197 169 75 60 41 +243 164 32 234 92 145 98 155 96 196 243 208 200 253 48 21 96 218 40 74 178 191 +115 196 136 225 219 209 60 19 23 11 54 9 161 106 58 284 204 61 210 93 5 151 130 +237 154 34 42 232 133 141 246 112 5 44 147 256 110 46 40 159 213 19 181 95 207 +274 99 37 233 37 211 104 58 126 120 195 232 155 225 112 90 230 262 35 9 117 89 +39 41 41 63 147 13 278 216 283 35 75 82 261 109 142 257 14 267 185 105 47 95 +229 71 252 15 171 255 99 144 65 18 255 228 60 199 40 30 10 172 159 33 138 162 +139 44 125 36 244 68 102 228 38 115 174 52 72 241 271 280 131 119 4 162 161 128 +142 14 182 286 141 268 45 158 22 85 187 285 86 198 51 61 188 9 139 173 192 19 +266 130 35 53 285 108 131 204 39 126 227 27 213 199 62 114 163 150 97 100 26 +202 146 87 124 205 72 263 68 146 109 57 71 50 201 135 34 149 215 114 185 83 250 +78 251 133 34 127 131 248 207 9 183 190 211 262 142 279 98 133 163 43 265 270 +269 78 8 150 204 83 7 246 270 89 197 125 194 41 85 80 166 256 154 214 210 115 +89 17 108 175 85 209 82 103 176 276 279 76 49 10 65 40 52 94 38 137 258 69 50 +179 202 168 171 277 183 10 43 243 186 116 100 70 83 29 43 67 135 56 82 81 92 +123 14 2 118 258 25 33 160 246 5 22 63 103 132 108 260 120 173 148 2 247 38 159 +55 222 28 117 269 56 211 284 226 145 76 71 230 218 18 277 25 213 177 265 248 +185 212 30 212 273 195 254 239 91 90 28 10 150 75 167 160 224 175 ^ +613 0 152 79 161 65 216 220 109 281 9 254 130 126 57 137 147 82 63 133 78 162 +232 68 59 232 177 22 129 68 168 36 74 43 275 264 174 70 154 103 247 218 194 158 +42 167 49 259 18 261 222 95 59 52 270 49 20 214 75 42 238 282 46 106 258 249 83 +280 22 20 105 271 15 58 136 269 100 224 10 182 19 68 130 17 94 240 256 225 156 +127 44 82 172 96 105 53 89 134 65 107 257 212 101 152 188 124 92 107 77 175 287 +43 45 190 98 141 157 235 259 127 224 119 275 205 248 276 83 100 115 206 285 128 +211 64 11 60 1 66 253 202 237 245 194 108 5 64 229 116 84 267 256 45 249 24 224 +228 238 102 139 3 149 106 149 286 56 100 165 243 99 237 65 157 5 26 210 6 122 +118 217 27 17 203 44 153 116 13 193 50 116 122 286 236 7 268 63 242 171 59 123 +214 125 238 52 102 30 40 252 215 3 220 50 66 215 183 127 153 45 69 117 121 119 +95 9 145 167 229 166 121 81 76 188 53 18 190 148 178 260 55 113 61 218 85 195 +145 276 192 63 12 97 142 194 217 98 250 120 132 150 273 1 125 20 285 19 118 37 +120 203 94 60 219 122 47 273 110 88 206 176 165 25 43 154 283 284 32 14 12 265 +161 15 179 117 138 75 260 164 76 247 109 101 261 151 21 272 253 143 181 32 123 +105 162 52 31 245 123 34 218 135 232 248 96 46 286 6 63 62 134 245 14 71 32 244 +86 182 90 12 47 105 91 108 244 27 126 7 230 44 262 79 199 84 196 23 128 31 27 +197 240 17 262 259 236 187 16 166 62 25 282 117 180 175 178 80 18 10 241 75 151 +201 179 67 252 35 255 117 71 82 281 189 2 233 235 41 71 141 48 272 73 236 78 53 +269 171 168 86 111 16 95 118 108 64 120 23 187 87 110 268 243 279 274 168 266 +148 119 204 261 42 58 86 73 127 115 26 89 25 102 80 77 66 35 146 24 44 191 135 +123 285 199 155 140 99 57 28 54 185 42 276 12 156 198 118 288 101 223 132 41 +180 104 234 163 219 13 84 87 219 231 140 170 1 234 272 182 199 264 233 126 237 +174 250 191 206 67 72 128 152 8 87 278 287 223 241 4 77 284 91 229 225 47 164 +147 191 26 30 99 19 9 74 93 23 78 283 213 88 97 213 268 4 27 88 277 120 82 113 +170 181 271 86 2 53 198 227 251 287 114 278 107 186 138 184 223 61 97 104 175 +107 6 231 81 114 207 163 110 50 187 196 73 165 134 136 51 174 11 98 20 176 56 +221 146 263 137 88 26 139 62 205 189 220 29 112 74 273 60 51 103 67 22 91 49 +188 233 55 4 257 32 64 49 79 270 158 113 111 255 58 15 288 210 213 ^ +624 1 28 220 36 170 238 197 169 72 54 41 237 158 26 234 92 145 95 155 87 190 +243 208 200 250 48 21 90 215 40 71 178 188 109 196 130 219 216 206 51 16 23 5 +48 6 158 97 55 278 201 55 207 90 286 151 130 234 148 34 36 226 127 138 240 112 +2 38 141 250 104 37 31 159 207 19 175 92 201 274 96 31 230 28 205 104 52 126 +114 192 229 152 225 103 90 230 262 26 108 86 39 32 35 60 147 10 278 216 277 35 +75 79 255 100 136 254 5 267 185 99 41 95 226 71 249 9 168 252 90 144 56 12 249 +228 57 193 34 21 4 172 153 30 135 159 136 35 116 36 241 59 93 225 32 106 171 43 +66 238 268 280 131 110 1 162 161 122 142 14 179 283 141 265 36 155 16 79 184 +279 77 198 45 52 182 3 133 173 192 10 263 121 32 50 282 102 122 198 30 120 227 +18 213 196 59 108 157 150 91 91 20 199 140 84 124 199 69 263 65 143 109 48 62 +47 201 126 28 149 215 111 182 74 244 69 248 133 25 124 128 248 204 9 183 184 +208 256 139 279 92 130 163 37 265 270 266 75 8 144 204 80 4 243 264 89 191 119 +188 38 85 71 163 256 154 211 210 115 83 14 108 172 82 209 76 103 176 273 276 67 +43 10 59 37 46 91 35 131 258 69 44 176 202 165 171 277 177 7 34 240 183 113 97 +70 83 29 40 67 129 53 73 78 89 120 8 2 109 252 19 33 160 246 289 13 54 97 126 +99 260 111 167 142 289 247 38 156 55 222 22 114 263 50 211 281 226 142 70 68 +224 212 15 274 25 210 171 262 245 179 212 30 206 270 195 254 239 88 81 28 1 147 +66 167 157 221 202 150 76 159 65 214 220 107 281 7 253 129 124 57 137 145 80 60 +132 78 160 231 67 58 232 177 22 129 68 168 33 74 40 275 262 174 68 153 101 246 +218 192 158 41 166 47 257 15 259 220 92 59 52 268 46 20 214 72 39 236 282 46 +106 257 249 80 279 21 19 104 271 15 55 136 269 100 222 7 182 18 65 128 14 93 +240 254 224 156 126 43 81 170 96 102 51 87 134 64 104 256 210 100 151 186 123 +89 105 76 174 287 42 42 190 95 140 155 235 258 125 223 117 273 205 246 274 81 +99 112 206 285 127 209 61 8 58 288 66 253 200 235 243 193 105 5 63 228 113 82 +265 255 44 247 23 224 227 237 102 137 3 148 105 147 285 56 98 165 242 98 236 63 +157 2 23 209 5 119 117 217 26 15 203 41 151 115 12 193 49 116 122 284 236 7 268 +61 242 169 57 122 213 125 238 49 101 27 39 251 214 1 218 50 63 213 181 127 153 +45 67 114 121 118 93 6 143 165 227 166 118 78 74 188 53 17 189 148 176 258 54 +112 58 217 82 194 144 275 191 141 ^ +628 1 3 97 139 194 211 92 250 117 132 147 267 290 119 14 282 13 118 37 111 200 +94 60 216 119 47 270 110 85 203 173 159 16 43 148 277 278 29 5 12 262 158 6 176 +117 286 135 72 257 164 76 241 106 101 261 148 18 266 247 143 178 32 117 99 159 +49 31 245 123 31 212 135 226 245 90 43 286 289 60 62 131 242 11 65 23 244 80 +176 84 6 38 105 91 102 238 27 123 290 224 38 259 79 199 84 193 14 128 25 21 191 +237 17 256 259 233 187 10 160 59 19 276 114 174 169 175 74 18 7 235 69 145 198 +179 58 252 32 255 111 62 82 278 183 285 230 229 32 68 135 39 269 67 230 75 44 +263 168 165 86 108 16 92 112 105 58 114 20 181 78 107 265 237 276 268 162 266 +142 119 201 258 36 52 77 64 118 109 26 80 22 96 80 71 60 29 143 24 44 191 132 +114 279 193 152 140 99 54 25 54 179 42 276 9 150 192 109 285 92 217 129 35 180 +101 228 160 213 7 81 81 219 231 134 167 1 231 272 179 196 264 227 117 237 171 +244 185 200 61 72 119 152 2 87 272 284 220 241 1 77 284 82 229 219 44 158 144 +188 20 27 90 10 6 71 93 17 69 283 210 82 91 207 262 4 18 79 271 120 73 113 164 +181 265 83 288 50 195 221 251 281 108 275 104 186 138 184 223 61 88 95 175 107 +6 225 81 114 207 157 101 41 184 190 73 162 128 130 45 168 11 98 11 170 47 221 +146 257 131 88 23 139 56 199 189 217 283 23 106 68 273 51 51 100 64 13 85 49 +185 233 49 290 257 26 64 46 73 267 152 107 111 249 58 9 288 204 183 26 218 34 +170 234 197 169 70 50 41 233 154 22 234 92 145 93 155 81 186 243 208 200 248 48 +21 86 213 40 69 178 186 105 196 126 215 214 204 45 14 23 1 44 4 156 91 53 274 +199 51 205 88 282 151 130 232 144 34 32 222 123 136 236 112 34 137 246 100 31 +25 159 203 19 171 90 197 274 94 27 228 22 201 104 48 126 110 190 227 150 225 97 +90 230 262 20 286 102 84 39 26 31 58 147 8 278 216 273 35 75 77 251 94 132 252 +291 267 185 95 37 95 224 71 247 5 166 250 84 144 50 8 245 228 55 189 30 15 172 +149 28 133 157 134 29 110 36 239 53 87 223 28 100 169 37 62 236 266 280 131 104 +291 162 161 118 142 14 177 281 141 263 30 153 12 75 182 275 71 198 41 46 178 +291 129 173 192 4 261 115 30 48 280 98 116 194 24 116 227 12 213 194 57 104 153 +150 87 85 16 197 136 82 124 195 67 263 63 141 109 42 56 45 201 120 24 149 215 +109 180 68 240 63 246 133 19 122 126 248 202 9 183 180 206 252 137 279 88 128 +163 33 265 270 264 73 8 140 204 78 2 241 76 ^ +622 0 89 183 111 180 34 85 59 159 256 154 207 210 115 75 10 108 168 78 209 68 +103 176 269 272 55 35 10 51 33 38 87 31 123 258 69 36 172 202 161 171 277 169 3 +22 236 179 109 93 70 83 29 36 67 121 49 61 74 85 116 2 97 244 11 33 160 246 285 +1 42 89 118 87 260 99 159 134 289 247 38 152 55 222 14 110 255 42 211 277 226 +138 62 64 216 204 11 270 25 206 163 258 241 171 212 30 198 266 195 254 239 84 +69 28 283 143 54 167 153 217 194 142 64 151 65 206 220 99 281 293 249 125 116 +57 137 137 72 48 128 78 152 227 63 54 232 177 22 129 68 168 21 74 28 275 254 +174 60 149 93 242 218 184 158 37 162 39 249 3 251 212 80 59 52 260 34 20 214 60 +27 228 282 46 106 253 249 68 275 17 15 100 271 15 43 136 269 100 214 289 182 14 +53 120 2 89 240 246 220 156 122 39 77 162 96 90 43 79 134 60 92 252 202 96 147 +178 119 77 97 72 170 287 38 30 190 83 136 147 235 254 117 219 109 265 205 238 +266 73 95 100 206 285 123 201 49 290 50 280 66 253 192 227 235 189 93 5 59 224 +101 74 257 251 40 239 19 224 223 233 102 129 3 144 101 139 281 56 90 165 238 94 +232 55 157 284 11 205 1 107 113 217 22 7 203 29 143 111 8 193 45 116 122 276 +236 7 268 53 242 161 49 118 209 125 238 37 97 15 35 247 210 287 210 50 51 205 +173 127 153 45 59 102 121 114 85 288 135 157 219 166 106 66 66 188 53 13 185 +148 168 250 50 108 46 213 70 190 140 271 187 63 291 97 137 194 207 88 250 115 +132 145 263 290 115 10 280 9 118 37 105 198 94 60 214 117 47 268 110 83 201 171 +155 10 43 144 273 274 27 293 12 260 156 174 117 284 133 70 255 164 76 237 104 +101 261 146 16 262 243 143 176 32 113 95 157 47 31 245 123 29 208 135 222 243 +86 41 286 285 58 62 129 240 9 61 17 244 76 172 80 2 32 105 91 98 234 27 121 286 +220 34 257 79 199 84 191 8 128 21 17 187 235 17 252 259 231 187 6 156 57 15 272 +112 170 165 173 70 18 5 231 65 141 196 179 52 252 30 255 107 56 82 276 179 281 +228 225 26 66 131 33 267 63 226 73 38 259 166 163 86 106 16 90 108 103 54 110 +18 177 72 105 263 233 274 264 158 266 138 119 199 256 32 48 71 58 112 105 26 74 +20 92 80 67 56 25 141 24 44 191 130 108 275 189 150 140 99 52 23 54 175 42 276 +7 146 188 103 283 86 213 127 31 180 99 224 158 209 3 79 77 219 231 130 165 1 +229 272 177 194 264 223 111 237 169 240 181 196 57 72 113 152 292 87 268 282 +218 241 293 77 284 76 229 80 ^ +635 1 40 150 140 184 12 23 78 294 2 67 93 9 57 283 206 74 83 199 254 4 6 67 263 +120 61 113 156 181 257 79 284 46 191 213 251 273 100 271 100 186 138 184 223 61 +76 83 175 107 6 217 81 114 207 149 89 29 180 182 73 158 120 122 37 160 11 98 +295 162 35 221 146 249 123 88 19 139 48 191 189 213 275 15 98 60 273 39 51 96 +60 1 77 49 181 233 41 286 257 18 64 42 65 263 144 99 111 241 58 1 288 196 179 +22 214 30 170 226 197 169 66 42 41 225 146 14 234 92 145 89 155 69 178 243 208 +200 244 48 21 78 209 40 65 178 182 97 196 118 207 210 200 33 10 23 289 36 152 +79 49 266 195 43 201 84 274 151 130 228 136 34 24 214 115 132 228 112 292 26 +129 238 92 19 13 159 195 19 163 86 189 274 90 19 224 10 193 104 40 126 102 186 +223 146 225 85 90 230 262 8 278 90 80 39 14 23 54 147 4 278 216 265 35 75 73 +243 82 124 248 283 267 185 87 29 95 220 71 243 293 162 246 72 144 38 237 228 51 +181 22 3 288 172 141 24 129 153 130 17 98 36 235 41 75 219 20 88 165 25 54 232 +262 280 131 92 291 162 161 110 142 14 173 277 141 259 18 149 4 67 178 267 59 +198 33 34 170 287 121 173 192 288 257 103 26 44 276 90 104 186 12 108 227 213 +190 53 96 145 150 79 73 8 193 128 78 124 187 63 263 59 137 109 30 44 41 201 108 +16 149 215 105 176 56 232 51 242 133 7 118 122 248 198 9 183 172 202 244 133 +279 80 124 163 25 265 270 260 69 8 132 204 74 294 237 252 89 179 107 176 32 85 +53 157 256 154 205 210 115 71 8 108 166 76 209 64 103 176 267 270 49 31 10 47 +31 34 85 29 119 258 69 32 170 202 159 171 277 165 1 16 234 177 107 91 70 83 29 +34 67 117 47 55 72 83 114 292 2 91 240 7 33 160 246 283 291 36 85 114 81 260 93 +155 130 289 247 38 150 55 222 10 108 251 38 211 275 226 136 58 62 212 200 9 268 +25 204 159 256 239 167 212 30 194 264 195 254 239 82 63 28 279 141 48 167 151 +215 190 138 58 147 65 202 220 95 281 291 247 123 112 57 137 133 68 42 126 78 +148 225 61 52 232 177 22 129 68 168 15 74 22 275 250 174 56 147 89 240 218 180 +158 35 160 35 245 293 247 208 74 59 52 256 28 20 214 54 21 224 282 46 106 251 +249 62 273 15 13 98 271 15 37 136 269 100 210 285 182 12 47 116 292 87 240 242 +218 156 120 37 75 158 96 84 39 75 134 58 86 250 198 94 145 174 117 71 93 70 168 +287 36 24 190 77 134 143 235 252 113 217 105 261 205 234 262 69 93 94 206 285 +121 197 43 286 46 276 66 253 188 223 231 187 87 5 57 222 95 285 ^ +636 0 251 248 37 233 16 224 220 230 102 123 3 141 98 133 278 56 84 165 235 91 +229 49 157 278 2 202 295 98 110 217 19 1 203 20 137 108 5 193 42 116 122 270 +236 7 268 47 242 155 43 115 206 125 238 28 94 6 32 244 207 284 204 50 42 199 +167 127 153 45 53 93 121 111 79 282 129 151 213 166 97 57 60 188 53 10 182 148 +162 244 47 105 37 210 61 187 137 268 184 63 285 97 134 194 201 82 250 112 132 +142 257 290 109 4 277 3 118 37 96 195 94 60 211 114 47 265 110 80 198 168 149 1 +43 138 267 268 24 287 12 257 153 288 171 117 281 130 67 252 164 76 231 101 101 +261 143 13 256 237 143 173 32 107 89 154 44 31 245 123 26 202 135 216 240 80 38 +286 279 55 62 126 237 6 55 8 244 70 166 74 293 23 105 91 92 228 27 118 280 214 +28 254 79 199 84 188 296 128 15 11 181 232 17 246 259 228 187 150 54 9 266 109 +164 159 170 64 18 2 225 59 135 193 179 43 252 27 255 101 47 82 273 173 275 225 +219 17 63 125 24 264 57 220 70 29 253 163 160 86 103 16 87 102 100 48 104 15 +171 63 102 260 227 271 258 152 266 132 119 196 253 26 42 62 49 103 99 26 65 17 +86 80 61 50 19 138 24 44 191 127 99 269 183 147 140 99 49 20 54 169 42 276 4 +140 182 94 280 77 207 124 25 180 96 218 155 203 294 76 71 219 231 124 162 1 226 +272 174 191 264 217 102 237 166 234 175 190 51 72 104 152 289 87 262 279 215 +241 293 77 284 67 229 209 39 148 139 183 10 22 75 292 1 66 93 7 54 283 205 72 +81 197 252 4 3 64 261 120 58 113 154 181 255 78 283 45 190 211 251 271 98 270 +99 186 138 184 223 61 73 80 175 107 6 215 81 114 207 147 86 26 179 180 73 157 +118 120 35 158 11 98 293 160 32 221 146 247 121 88 18 139 46 189 189 212 273 13 +96 58 273 36 51 95 59 295 75 49 180 233 39 285 257 16 64 41 63 262 142 97 111 +239 58 296 288 194 178 21 213 29 170 224 197 169 65 40 41 223 144 12 234 92 145 +88 155 66 176 243 208 200 243 48 21 76 208 40 64 178 181 95 196 116 205 209 199 +30 9 23 288 34 296 151 76 48 264 194 41 200 83 272 151 130 227 134 34 22 212 +113 131 226 112 292 24 127 236 90 16 10 159 193 19 161 85 187 274 89 17 223 7 +191 104 38 126 100 185 222 145 225 82 90 230 262 5 276 87 79 39 11 21 53 147 3 +278 216 263 35 75 72 241 79 122 247 281 267 185 85 27 95 219 71 242 292 161 245 +69 144 35 295 235 228 50 179 20 287 172 139 23 128 152 129 14 95 36 234 38 72 +218 18 85 164 22 52 231 261 280 131 89 291 162 161 108 142 14 172 276 91 ^ +635 1 256 9 146 297 61 175 261 50 198 27 25 164 284 115 173 192 282 254 94 23 +41 273 84 95 180 3 102 227 290 213 187 50 90 139 150 73 64 2 190 122 75 124 181 +60 263 56 134 109 21 35 38 201 99 10 149 215 102 173 47 226 42 239 133 297 115 +119 248 195 9 183 166 199 238 130 279 74 121 163 19 265 270 257 66 8 126 204 71 +294 234 246 89 173 101 170 29 85 44 154 256 154 202 210 115 65 5 108 163 73 209 +58 103 176 264 267 40 25 10 41 28 28 82 26 113 258 69 26 167 202 156 171 277 +159 297 7 231 174 104 88 70 83 29 31 67 111 44 46 69 80 111 289 2 82 234 1 33 +160 246 280 285 27 79 108 72 260 84 149 124 289 247 38 147 55 222 4 105 245 32 +211 272 226 133 52 59 206 194 6 265 25 201 153 253 236 161 212 30 188 261 195 +254 239 79 54 28 273 138 39 167 148 212 184 132 49 141 65 196 220 89 281 288 +244 120 106 57 137 127 62 33 123 78 142 222 58 49 232 177 22 129 68 168 6 74 13 +275 244 174 50 144 83 237 218 174 158 32 157 29 239 287 241 202 65 59 52 250 19 +20 214 45 12 218 282 46 106 248 249 53 270 12 10 95 271 15 28 136 269 100 204 +279 182 9 38 110 286 84 240 236 215 156 117 34 72 152 96 75 33 69 134 55 77 247 +192 91 142 168 114 62 87 67 165 287 33 15 190 68 131 137 235 249 107 214 99 255 +205 228 256 63 90 85 206 285 118 191 34 280 40 270 66 253 182 217 225 184 78 5 +54 219 86 64 247 246 35 229 14 224 218 228 102 119 3 139 96 129 276 56 80 165 +233 89 227 45 157 274 295 200 295 92 108 217 17 296 203 14 133 106 3 193 40 116 +122 266 236 7 268 43 242 151 39 113 204 125 238 22 92 30 242 205 282 200 50 36 +195 163 127 153 45 49 87 121 109 75 278 125 147 209 166 91 51 56 188 53 8 180 +148 158 240 45 103 31 208 55 185 135 266 182 63 281 97 132 194 197 78 250 110 +132 140 253 290 105 275 298 118 37 90 193 94 60 209 112 47 263 110 78 196 166 +145 294 43 134 263 264 22 283 12 255 151 284 169 117 279 128 65 250 164 76 227 +99 101 261 141 11 252 233 143 171 32 103 85 152 42 31 245 123 24 198 135 212 +238 76 36 286 275 53 62 124 235 4 51 2 244 66 162 70 291 17 105 91 88 224 27 +116 276 210 24 252 79 199 84 186 292 128 11 7 177 230 17 242 259 226 187 295 +146 52 5 262 107 160 155 168 60 18 221 55 131 191 179 37 252 25 255 97 41 82 +271 169 271 223 215 11 61 121 18 262 53 216 68 23 249 161 158 86 101 16 85 98 +98 44 100 13 167 57 100 258 223 269 254 148 266 128 119 194 251 22 38 56 43 275 +^ +642 0 91 26 53 13 78 80 53 42 11 134 24 44 191 123 87 261 175 143 140 99 45 16 +54 161 42 276 132 174 82 276 65 199 120 17 180 92 210 151 195 290 72 63 219 231 +116 158 1 222 272 170 187 264 209 90 237 162 226 167 182 43 72 92 152 285 87 +254 275 211 241 293 77 284 55 229 201 35 140 135 179 2 18 63 284 298 62 93 300 +42 283 201 64 73 189 244 4 292 52 253 120 46 113 146 181 247 74 279 41 186 203 +251 263 90 266 95 186 138 184 223 61 61 68 175 107 6 207 81 114 207 139 74 14 +175 172 73 153 110 112 27 150 11 98 285 152 20 221 146 239 113 88 14 139 38 181 +189 208 265 5 88 50 273 24 51 91 55 287 67 49 176 233 31 281 257 8 64 37 55 258 +134 89 111 231 58 292 288 186 174 17 209 25 170 216 197 169 61 32 41 215 136 4 +234 92 145 84 155 54 168 243 208 200 239 48 21 68 204 40 60 178 177 87 196 108 +197 205 195 18 5 23 284 26 296 147 64 44 256 190 33 196 79 264 151 130 223 126 +34 14 204 105 127 218 112 292 16 119 228 82 4 299 159 185 19 153 81 179 274 85 +9 219 296 183 104 30 126 92 181 218 141 225 70 90 230 262 294 268 75 75 39 300 +13 49 147 300 278 216 255 35 75 68 233 67 114 243 273 267 185 77 19 95 215 71 +238 288 157 241 57 144 23 291 227 228 46 171 12 289 283 172 131 19 124 148 125 +2 83 36 230 26 60 214 10 73 160 10 44 227 257 280 131 77 291 162 161 100 142 14 +168 272 141 254 3 144 295 57 173 257 44 198 23 19 160 282 111 173 192 278 252 +88 21 39 271 80 89 176 298 98 227 286 213 185 48 86 135 150 69 58 299 188 118 +73 124 177 58 263 54 132 109 15 29 36 201 93 6 149 215 100 171 41 222 36 237 +133 293 113 117 248 193 9 183 162 197 234 128 279 70 119 163 15 265 270 255 64 +8 122 204 69 294 232 242 89 169 97 166 27 85 38 152 256 154 200 210 115 61 3 +108 161 71 209 54 103 176 262 265 34 21 10 37 26 24 80 24 109 258 69 22 165 202 +154 171 277 155 297 1 229 172 102 86 70 83 29 29 67 107 42 40 67 78 109 287 2 +76 230 298 33 160 246 278 281 21 75 104 66 260 78 145 120 289 247 38 145 55 222 +103 241 28 211 270 226 131 48 57 202 190 4 263 25 199 149 251 234 157 212 30 +184 259 195 254 239 77 48 28 269 136 33 167 146 210 180 128 43 137 65 192 220 +85 281 286 242 118 102 57 137 123 58 27 121 78 138 220 56 47 232 177 22 129 68 +168 74 7 275 240 174 46 142 79 235 218 170 158 30 155 25 235 283 237 198 59 59 +52 246 13 20 214 39 6 214 282 46 106 246 249 47 268 10 8 93 271 15 22 136 269 +100 200 275 42 ^ +644 0 6 29 104 280 81 240 230 212 156 114 31 69 146 96 66 27 63 134 52 68 244 +186 88 139 162 111 53 81 64 162 287 30 6 190 59 128 131 235 246 101 211 93 249 +205 222 250 57 87 76 206 285 115 185 25 274 34 264 66 253 176 211 219 181 69 5 +51 216 77 58 241 243 32 223 11 224 215 225 102 113 3 136 93 123 273 56 74 165 +230 86 224 39 157 268 289 197 295 83 105 217 14 293 203 5 127 103 193 37 116 +122 260 236 7 268 37 242 145 33 110 201 125 238 13 89 293 27 239 202 279 194 50 +27 189 157 127 153 45 43 78 121 106 69 272 119 141 203 166 82 42 50 188 53 5 +177 148 152 234 42 100 22 205 46 182 132 263 179 63 275 97 129 194 191 72 250 +107 132 137 247 290 99 296 272 295 118 37 81 190 94 60 206 109 47 260 110 75 +193 163 139 288 43 128 257 258 19 277 12 252 148 278 166 117 276 125 62 247 164 +76 221 96 101 261 138 8 246 227 143 168 32 97 79 149 39 31 245 123 21 192 135 +206 235 70 33 286 269 50 62 121 232 1 45 295 244 60 156 64 288 8 105 91 82 218 +27 113 270 204 18 249 79 199 84 183 286 128 5 1 171 227 17 236 259 223 187 292 +140 49 301 256 104 154 149 165 54 18 299 215 49 125 188 179 28 252 22 255 91 32 +82 268 163 265 220 209 2 58 115 9 259 47 210 65 14 243 158 155 86 98 16 82 92 +95 38 94 10 161 48 97 255 217 266 248 142 266 122 119 191 248 16 32 47 34 88 89 +26 50 12 76 80 51 40 9 133 24 44 191 122 84 259 173 142 140 99 44 15 54 159 42 +276 301 130 172 79 275 62 197 119 15 180 91 208 150 193 289 71 61 219 231 114 +157 1 221 272 169 186 264 207 87 237 161 224 165 180 41 72 89 152 284 87 252 +274 210 241 293 77 284 52 229 199 34 138 134 178 17 60 282 298 61 93 299 39 283 +200 62 71 187 242 4 290 49 251 120 43 113 144 181 245 73 278 40 185 201 251 261 +88 265 94 186 138 184 223 61 58 65 175 107 6 205 81 114 207 137 71 11 174 170 +73 152 108 110 25 148 11 98 283 150 17 221 146 237 111 88 13 139 36 179 189 207 +263 3 86 48 273 21 51 90 54 285 65 49 175 233 29 280 257 6 64 36 53 257 132 87 +111 229 58 291 288 184 173 16 208 24 170 214 197 169 60 30 41 213 134 2 234 92 +145 83 155 51 166 243 208 200 238 48 21 66 203 40 59 178 176 85 196 106 195 204 +194 15 4 23 283 24 296 146 61 43 254 189 31 195 78 262 151 130 222 124 34 12 +202 103 126 216 112 292 14 117 226 80 1 297 159 183 19 151 80 177 274 84 7 218 +294 181 104 28 126 90 180 217 140 225 67 90 230 262 292 266 72 74 39 298 11 48 +147 300 278 216 253 265 ^ +638 1 75 65 227 58 108 240 267 267 185 71 13 95 212 71 235 285 154 238 48 144 +14 288 221 228 43 165 6 283 280 172 125 16 121 145 122 297 74 36 227 17 51 211 +4 64 157 1 38 224 254 280 131 68 291 162 161 94 142 14 165 269 141 251 298 141 +292 51 170 251 35 198 17 10 154 279 105 173 192 272 249 79 18 36 268 74 80 170 +292 92 227 280 213 182 45 80 129 150 63 49 296 185 112 70 124 171 55 263 51 129 +109 6 20 33 201 84 149 215 97 168 32 216 27 234 133 287 110 114 248 190 9 183 +156 194 228 125 279 64 116 163 9 265 270 252 61 8 116 204 66 294 229 236 89 163 +91 160 24 85 29 149 256 154 197 210 115 55 108 158 68 209 48 103 176 259 262 25 +15 10 31 23 18 77 21 103 258 69 16 162 202 151 171 277 149 297 296 226 169 99 +83 70 83 29 26 67 101 39 31 64 75 106 284 2 67 224 295 33 160 246 275 275 12 69 +98 57 260 69 139 114 289 247 38 142 55 222 298 100 235 22 211 267 226 128 42 54 +196 184 1 260 25 196 143 248 231 151 212 30 178 256 195 254 239 74 39 28 263 +133 24 167 143 207 174 122 34 131 65 186 220 79 281 283 239 115 96 57 137 117 +52 18 118 78 132 217 53 44 232 177 22 129 68 168 295 74 302 275 234 174 40 139 +73 232 218 164 158 27 152 19 229 277 231 192 50 59 52 240 4 20 214 30 301 208 +282 46 106 243 249 38 265 7 5 90 271 15 13 136 269 100 194 269 182 4 23 100 276 +79 240 226 210 156 112 29 67 142 96 60 23 59 134 50 62 242 182 86 137 158 109 +47 77 62 160 287 28 190 53 126 127 235 244 97 209 89 245 205 218 246 53 85 70 +206 285 113 181 19 270 30 260 66 253 172 207 215 179 63 5 49 214 71 54 237 241 +30 219 9 224 213 223 102 109 3 134 91 119 271 56 70 165 228 84 222 35 157 264 +285 195 295 77 103 217 12 291 203 303 123 101 302 193 35 116 122 256 236 7 268 +33 242 141 29 108 199 125 238 7 87 289 25 237 200 277 190 50 21 185 153 127 153 +45 39 72 121 104 65 268 115 137 199 166 76 36 46 188 53 3 175 148 148 230 40 98 +16 203 40 180 130 261 177 63 271 97 127 194 187 68 250 105 132 135 243 290 95 +294 270 293 118 37 75 188 94 60 204 107 47 258 110 73 191 161 135 284 43 124 +253 254 17 273 12 250 146 274 164 117 274 123 60 245 164 76 217 94 101 261 136 +6 242 223 143 166 32 93 75 147 37 31 245 123 19 188 135 202 233 66 31 286 265 +48 62 119 230 303 41 291 244 56 152 60 286 2 105 91 78 214 27 111 266 200 14 +247 79 199 84 181 282 128 1 301 167 225 17 232 259 221 187 290 136 47 299 252 +102 150 145 163 157 ^ +653 0 18 299 207 41 117 184 179 16 252 18 255 83 20 82 264 155 257 216 201 296 +54 107 303 255 39 202 61 2 235 154 151 86 94 16 78 84 91 30 86 6 153 36 93 251 +209 262 240 134 266 114 119 187 244 8 24 35 22 76 81 26 38 8 68 80 43 32 1 129 +24 44 191 118 72 251 165 138 140 99 40 11 54 151 42 276 301 122 164 67 271 50 +189 115 7 180 87 200 146 185 285 67 53 219 231 106 153 1 217 272 165 182 264 +199 75 237 157 216 157 172 33 72 77 152 280 87 244 270 206 241 293 77 284 40 +229 191 30 130 130 174 298 13 48 274 298 57 93 295 27 283 196 54 63 179 234 4 +282 37 243 120 31 113 136 181 237 69 274 36 181 193 251 253 80 261 90 186 138 +184 223 61 46 53 175 107 6 197 81 114 207 129 59 305 170 162 73 148 100 102 17 +140 11 98 275 142 5 221 146 229 103 88 9 139 28 171 189 203 255 301 78 40 273 9 +51 86 50 277 57 49 171 233 21 276 257 304 64 32 45 253 124 79 111 221 58 287 +288 176 169 12 204 20 170 206 197 169 56 22 41 205 126 300 234 92 145 79 155 39 +158 243 208 200 234 48 21 58 199 40 55 178 172 77 196 98 187 200 190 3 23 279 +16 296 142 49 39 246 185 23 191 74 254 151 130 218 116 34 4 194 95 122 208 112 +292 6 109 218 72 295 289 159 175 19 143 76 169 274 80 305 214 286 173 104 20 +126 82 176 213 136 225 55 90 230 262 284 258 60 70 39 290 3 44 147 300 278 216 +245 35 75 63 223 52 104 238 263 267 185 67 9 95 210 71 233 283 152 236 42 144 8 +286 217 228 41 161 2 279 278 172 121 14 119 143 120 293 68 36 225 11 45 209 58 +155 301 34 222 252 280 131 62 291 162 161 90 142 14 163 267 141 249 294 139 290 +47 168 247 29 198 13 4 150 277 101 173 192 268 247 73 16 34 266 70 74 166 288 +88 227 276 213 180 43 76 125 150 59 43 294 183 108 68 124 167 53 263 49 127 109 +14 31 201 78 302 149 215 95 166 26 212 21 232 133 283 108 112 248 188 9 183 152 +192 224 123 279 60 114 163 5 265 270 250 59 8 112 204 64 294 227 232 89 159 87 +156 22 85 23 147 256 154 195 210 115 51 304 108 156 66 209 44 103 176 257 260 +19 11 10 27 21 14 75 19 99 258 69 12 160 202 149 171 277 145 297 292 224 167 97 +81 70 83 29 24 67 97 37 25 62 73 104 282 2 61 220 293 33 160 246 273 271 6 65 +94 51 260 63 135 110 289 247 38 140 55 222 296 98 231 18 211 265 226 126 38 52 +192 180 305 258 25 194 139 246 229 147 212 30 174 254 195 254 239 72 33 28 259 +131 18 167 141 205 170 118 28 127 65 182 220 75 281 281 237 113 92 57 137 113 +48 12 116 78 128 215 51 42 232 177 22 129 68 168 291 161 ^ +653 0 296 275 228 174 34 136 67 229 218 158 158 24 149 13 223 271 225 186 41 59 +52 234 302 20 214 21 295 202 282 46 106 240 249 29 262 4 2 87 271 15 4 136 269 +100 188 263 182 1 14 94 270 76 240 220 207 156 109 26 64 136 96 51 17 53 134 47 +53 239 176 83 134 152 106 38 71 59 157 287 25 298 190 44 123 121 235 241 91 206 +83 239 205 212 240 47 82 61 206 285 110 175 10 264 24 254 66 253 166 201 209 +176 54 5 46 211 62 48 231 238 27 213 6 224 210 220 102 103 3 131 88 113 268 56 +64 165 225 81 219 29 157 258 279 192 295 68 100 217 9 288 203 297 117 98 302 +193 32 116 122 250 236 7 268 27 242 135 23 105 196 125 238 305 84 283 22 234 +197 274 184 50 12 179 147 127 153 45 33 63 121 101 59 262 109 131 193 166 67 27 +40 188 53 172 148 142 224 37 95 7 200 31 177 127 258 174 63 265 97 124 194 181 +62 250 102 132 132 237 290 89 291 267 290 118 37 66 185 94 60 201 104 47 255 +110 70 188 158 129 278 43 118 247 248 14 267 12 247 143 268 161 117 271 120 57 +242 164 76 211 91 101 261 133 3 236 217 143 163 32 87 69 144 34 31 245 123 16 +182 135 196 230 60 28 286 259 45 62 116 227 303 35 285 244 50 146 54 283 300 +105 91 72 208 27 108 260 194 8 244 79 199 84 178 276 128 302 298 161 222 17 226 +259 218 187 287 130 44 296 246 99 144 139 160 44 18 299 205 39 115 183 179 13 +252 17 255 81 17 82 263 153 255 215 199 294 53 105 301 254 37 200 60 306 233 +153 150 86 93 16 77 82 90 28 84 5 151 33 92 250 207 261 238 132 266 112 119 186 +243 6 22 32 19 73 79 26 35 7 66 80 41 30 306 128 24 44 191 117 69 249 163 137 +140 99 39 10 54 149 42 276 301 120 162 64 270 47 187 114 5 180 86 198 145 183 +284 66 51 219 231 104 152 1 216 272 164 181 264 197 72 237 156 214 155 170 31 +72 74 152 279 87 242 269 205 241 293 77 284 37 229 189 29 128 129 173 297 12 45 +272 298 56 93 294 24 283 195 52 61 177 232 4 280 34 241 120 28 113 134 181 235 +68 273 35 180 191 251 251 78 260 89 186 138 184 223 61 43 50 175 107 6 195 81 +114 207 127 56 303 169 160 73 147 98 100 15 138 11 98 273 140 2 221 146 227 101 +88 8 139 26 169 189 202 253 300 76 38 273 6 51 85 49 275 55 49 170 233 19 275 +257 303 64 31 43 252 122 77 111 219 58 286 288 174 168 11 203 19 170 204 197 +169 55 20 41 203 124 299 234 92 145 78 155 36 156 243 208 200 233 48 21 56 198 +40 54 178 171 75 196 96 185 199 189 306 23 278 14 296 141 46 38 244 184 21 190 +73 252 151 130 217 114 34 2 192 93 121 206 112 292 4 107 216 70 293 112 ^ +646 1 159 169 19 137 73 163 274 77 302 211 280 167 104 14 126 76 173 210 133 +225 46 90 230 262 278 252 51 67 39 284 306 41 147 300 278 216 239 35 75 60 217 +43 98 235 257 267 185 61 3 95 207 71 230 280 149 233 33 144 308 283 211 228 38 +155 305 273 275 172 115 11 116 140 117 287 59 36 222 2 36 206 303 49 152 295 28 +219 249 280 131 53 291 162 161 84 142 14 160 264 141 246 288 136 287 41 165 241 +20 198 7 304 144 274 95 173 192 262 244 64 13 31 263 64 65 160 282 82 227 270 +213 177 40 70 119 150 53 34 291 180 102 65 124 161 50 263 46 124 109 300 5 28 +201 69 299 149 215 92 163 17 206 12 229 133 277 105 109 248 185 9 183 146 189 +218 120 279 54 111 163 308 265 270 247 56 8 106 204 61 294 224 226 89 153 81 +150 19 85 14 144 256 154 192 210 115 45 304 108 153 63 209 38 103 176 254 257 +10 5 10 21 18 8 72 16 93 258 69 6 157 202 146 171 277 139 297 286 221 164 94 78 +70 83 29 21 67 91 34 16 59 70 101 279 2 52 214 290 33 160 246 270 265 306 59 88 +42 260 54 129 104 289 247 38 137 55 222 293 95 225 12 211 262 226 123 32 49 186 +174 305 255 25 191 133 243 226 141 212 30 168 251 195 254 239 69 24 28 253 128 +9 167 138 202 164 112 19 121 65 176 220 69 281 278 234 110 86 57 137 107 42 3 +113 78 122 212 48 39 232 177 22 129 68 168 285 74 292 275 224 174 30 134 63 227 +218 154 158 22 147 9 219 267 221 182 35 59 52 230 298 20 214 15 291 198 282 46 +106 238 249 23 260 2 85 271 15 307 136 269 100 184 259 182 308 8 90 266 74 240 +216 205 156 107 24 62 132 96 45 13 49 134 45 47 237 172 81 132 148 104 32 67 57 +155 287 23 294 190 38 121 117 235 239 87 204 79 235 205 208 236 43 80 55 206 +285 108 171 4 260 20 250 66 253 162 197 205 174 48 5 44 209 56 44 227 236 25 +209 4 224 208 218 102 99 3 129 86 109 266 56 60 165 223 79 217 25 157 254 275 +190 295 62 98 217 7 286 203 293 113 96 302 193 30 116 122 246 236 7 268 23 242 +131 19 103 194 125 238 301 82 279 20 232 195 272 180 50 6 175 143 127 153 45 29 +57 121 99 55 258 105 127 189 166 61 21 36 188 53 307 170 148 138 220 35 93 1 +198 25 175 125 256 172 63 261 97 122 194 177 58 250 100 132 130 233 290 85 289 +265 288 118 37 60 183 94 60 199 102 47 253 110 68 186 156 125 274 43 114 243 +244 12 263 12 245 141 264 159 117 269 118 55 240 164 76 207 89 101 261 131 1 +232 213 143 161 32 83 65 142 32 31 245 123 14 178 135 192 228 56 26 286 255 43 +62 114 225 303 31 281 244 46 142 50 281 296 105 91 238 ^ +647 0 200 27 104 252 186 240 79 199 84 174 268 128 298 294 153 218 17 218 259 +214 187 283 122 40 292 238 95 136 131 156 36 18 299 197 31 107 179 179 1 252 13 +255 73 5 82 259 145 247 211 191 286 49 97 293 250 29 192 56 298 225 149 146 86 +89 16 73 74 86 20 76 1 143 21 88 246 199 257 230 124 266 104 119 182 239 309 14 +20 7 61 71 26 23 3 58 80 33 22 302 124 24 44 191 113 57 241 155 133 140 99 35 6 +54 141 42 276 301 112 154 52 266 35 179 110 308 180 82 190 141 175 280 62 43 +219 231 96 148 1 212 272 160 177 264 189 60 237 152 206 147 162 23 72 62 152 +275 87 234 265 201 241 293 77 284 25 229 181 25 120 125 169 293 8 33 264 298 52 +93 290 12 283 191 44 53 169 224 4 272 22 233 120 16 113 126 181 227 64 269 31 +176 183 251 243 70 256 85 186 138 184 223 61 31 38 175 107 6 187 81 114 207 119 +44 295 165 152 73 143 90 92 7 130 11 98 265 132 301 221 146 219 93 88 4 139 18 +161 189 198 245 296 68 30 273 305 51 81 45 267 47 49 166 233 11 271 257 299 64 +27 35 248 114 69 111 211 58 282 288 166 164 7 199 15 170 196 197 169 51 12 41 +195 116 295 234 92 145 74 155 24 148 243 208 200 229 48 21 48 194 40 50 178 167 +67 196 88 177 195 185 299 306 23 274 6 296 137 34 34 236 180 13 186 69 244 151 +130 213 106 34 305 184 85 117 198 112 292 307 99 208 62 285 279 159 165 19 133 +71 159 274 75 300 209 276 163 104 10 126 72 171 208 131 225 40 90 230 262 274 +248 45 65 39 280 304 39 147 300 278 216 235 35 75 58 213 37 94 233 253 267 185 +57 310 95 205 71 228 278 147 231 27 144 304 281 207 228 36 151 303 269 273 172 +111 9 114 138 115 283 53 36 220 307 30 204 301 43 150 291 24 217 247 280 131 47 +291 162 161 80 142 14 158 262 141 244 284 134 285 37 163 237 14 198 3 300 140 +272 91 173 192 258 242 58 11 29 261 60 59 156 278 78 227 266 213 175 38 66 115 +150 49 28 289 178 98 63 124 157 48 263 44 122 109 296 310 26 201 63 297 149 215 +90 161 11 202 6 227 133 273 103 107 248 183 9 183 142 187 214 118 279 50 109 +163 306 265 270 245 54 8 102 204 59 294 222 222 89 149 77 146 17 85 8 142 256 +154 190 210 115 41 304 108 151 61 209 34 103 176 252 255 4 1 10 17 16 4 70 14 +89 258 69 2 155 202 144 171 277 135 297 282 219 162 92 76 70 83 29 19 67 87 32 +10 57 68 99 277 2 46 210 288 33 160 246 268 261 302 55 84 36 260 48 125 100 289 +247 38 135 55 222 291 93 221 8 211 260 226 121 28 47 182 170 305 253 25 189 129 +241 224 137 212 30 164 249 195 254 239 86 ^ +665 0 15 28 247 125 167 135 199 158 106 10 115 65 170 220 63 281 275 231 107 80 +57 137 101 36 306 110 78 116 209 45 36 232 177 22 129 68 168 279 74 286 275 218 +174 24 131 57 224 218 148 158 19 144 3 213 261 215 176 26 59 52 224 292 20 214 +6 285 192 282 46 106 235 249 14 257 311 309 82 271 15 301 136 269 100 178 253 +182 308 311 84 260 71 240 210 202 156 104 21 59 126 96 36 7 43 134 42 38 234 +166 78 129 142 101 23 61 54 152 287 20 288 190 29 118 111 235 236 81 201 73 229 +205 202 230 37 77 46 206 285 105 165 307 254 14 244 66 253 156 191 199 171 39 5 +41 206 47 38 221 233 22 203 1 224 205 215 102 93 3 126 83 103 263 56 54 165 220 +76 214 19 157 248 269 187 295 53 95 217 4 283 203 287 107 93 302 193 27 116 122 +240 236 7 268 17 242 125 13 100 191 125 238 295 79 273 17 229 192 269 174 50 +309 169 137 127 153 45 23 48 121 96 49 252 99 121 183 166 52 12 30 188 53 307 +167 148 132 214 32 90 304 195 16 172 122 253 169 63 255 97 119 194 171 52 250 +97 132 127 227 290 79 286 262 285 118 37 51 180 94 60 196 99 47 250 110 65 183 +153 119 268 43 108 237 238 9 257 12 242 138 258 156 117 266 115 52 237 164 76 +201 86 101 261 128 310 226 207 143 158 32 77 59 139 29 31 245 123 11 172 135 +186 225 50 23 286 249 40 62 111 222 303 25 275 244 40 136 44 278 290 105 91 62 +198 27 103 250 184 310 239 79 199 84 173 266 128 297 293 151 217 17 216 259 213 +187 282 120 39 291 236 94 134 129 155 34 18 299 195 29 105 178 179 310 252 12 +255 71 2 82 258 143 245 210 189 284 48 95 291 249 27 190 55 296 223 148 145 86 +88 16 72 72 85 18 74 141 18 87 245 197 256 228 122 266 102 119 181 238 308 12 +17 4 58 69 26 20 2 56 80 31 20 301 123 24 44 191 112 54 239 153 132 140 99 34 5 +54 139 42 276 301 110 152 49 265 32 177 109 307 180 81 188 140 173 279 61 41 +219 231 94 147 1 211 272 159 176 264 187 57 237 151 204 145 160 21 72 59 152 +274 87 232 264 200 241 293 77 284 22 229 179 24 118 124 168 292 7 30 262 298 51 +93 289 9 283 190 42 51 167 222 4 270 19 231 120 13 113 124 181 225 63 268 30 +175 181 251 241 68 255 84 186 138 184 223 61 28 35 175 107 6 185 81 114 207 117 +41 293 164 150 73 142 88 90 5 128 11 98 263 130 299 221 146 217 91 88 3 139 16 +159 189 197 243 295 66 28 273 303 51 80 44 265 45 49 165 233 9 270 257 298 64 +26 33 247 112 67 111 209 58 281 288 164 163 6 198 14 170 194 197 169 50 10 41 +193 114 294 234 92 145 73 155 21 146 243 208 200 228 48 21 46 193 40 49 178 166 +65 196 86 175 194 184 297 306 23 273 206 ^ +641 0 296 134 25 31 230 177 7 183 66 238 151 130 210 100 34 302 178 79 114 192 +112 292 304 93 202 56 279 273 159 159 19 127 68 153 274 72 297 206 270 157 104 +4 126 66 168 205 128 225 31 90 230 262 268 242 36 62 39 274 301 36 147 300 278 +216 229 35 75 55 207 28 88 230 247 267 185 51 307 95 202 71 225 275 144 228 18 +144 298 278 201 228 33 145 300 263 270 172 105 6 111 135 112 277 44 36 217 301 +21 201 298 34 147 285 18 214 244 280 131 38 291 162 161 74 142 14 155 259 141 +241 278 131 282 31 160 231 5 198 311 294 134 269 85 173 192 252 239 49 8 26 258 +54 50 150 272 72 227 260 213 172 35 60 109 150 43 19 286 175 92 60 124 151 45 +263 41 119 109 290 304 23 201 54 294 149 215 87 158 2 196 311 224 133 267 100 +104 248 180 9 183 136 184 208 115 279 44 106 163 303 265 270 242 51 8 96 204 56 +294 219 216 89 143 71 140 14 85 313 139 256 154 187 210 115 35 304 108 148 58 +209 28 103 176 249 252 309 309 10 11 13 312 67 11 83 258 69 310 152 202 141 171 +277 129 297 276 216 159 89 73 70 83 29 16 67 81 29 1 54 65 96 274 2 37 204 285 +33 160 246 265 255 296 49 78 27 260 39 119 94 289 247 38 132 55 222 288 90 215 +2 211 257 226 118 22 44 176 164 305 250 25 186 123 238 221 131 212 30 158 246 +195 254 239 64 9 28 243 123 308 167 133 197 154 102 4 111 65 166 220 59 281 273 +229 105 76 57 137 97 32 302 108 78 112 207 43 34 232 177 22 129 68 168 275 74 +282 275 214 174 20 129 53 222 218 144 158 17 142 313 209 257 211 172 20 59 52 +220 288 20 214 281 188 282 46 106 233 249 8 255 311 309 80 271 15 297 136 269 +100 174 249 182 308 307 80 256 69 240 206 200 156 102 19 57 122 96 30 3 39 134 +40 32 232 162 76 127 138 99 17 57 52 150 287 18 284 190 23 116 107 235 234 77 +199 69 225 205 198 226 33 75 40 206 285 103 161 303 250 10 240 66 253 152 187 +195 169 33 5 39 204 41 34 217 231 20 199 313 224 203 213 102 89 3 124 81 99 261 +56 50 165 218 74 212 15 157 244 265 185 295 47 93 217 2 281 203 283 103 91 302 +193 25 116 122 236 236 7 268 13 242 121 9 98 189 125 238 291 77 269 15 227 190 +267 170 50 305 165 133 127 153 45 19 42 121 94 45 248 95 117 179 166 46 6 26 +188 53 307 165 148 128 210 30 88 300 193 10 170 120 251 167 63 251 97 117 194 +167 48 250 95 132 125 223 290 75 284 260 283 118 37 45 178 94 60 194 97 47 248 +110 63 181 151 115 264 43 104 233 234 7 253 12 240 136 254 154 117 264 113 50 +235 164 76 197 84 101 261 126 310 222 203 143 276 ^ +656 0 32 69 51 135 25 31 245 123 7 164 135 178 221 42 19 286 241 36 62 107 218 +303 17 267 244 32 128 36 274 282 105 91 54 190 27 99 242 176 306 235 79 199 84 +169 258 128 293 289 143 213 17 208 259 209 187 278 112 35 287 228 90 126 121 +151 26 18 299 187 21 97 174 179 302 252 8 255 63 306 82 254 135 237 206 181 276 +44 87 283 245 19 182 51 288 215 144 141 86 84 16 68 64 81 10 66 312 133 6 83 +241 189 252 220 114 266 94 119 177 234 304 4 5 308 46 61 26 8 314 48 80 23 12 +297 119 24 44 191 108 42 231 145 128 140 99 30 1 54 131 42 276 301 102 144 37 +261 20 169 105 303 180 77 180 136 165 275 57 33 219 231 86 143 1 207 272 155 +172 264 179 45 237 147 196 137 152 13 72 47 152 270 87 224 260 196 241 293 77 +284 10 229 171 20 110 120 164 288 3 18 254 298 47 93 285 313 283 186 34 43 159 +214 4 262 7 223 120 1 113 116 181 217 59 264 26 171 173 251 233 60 251 80 186 +138 184 223 61 16 23 175 107 6 177 81 114 207 109 29 285 160 142 73 138 80 82 +313 120 11 98 255 122 291 221 146 209 83 88 315 139 8 151 189 193 235 291 58 20 +273 295 51 76 40 257 37 49 161 233 1 266 257 294 64 22 25 243 104 59 111 201 58 +277 288 156 159 2 194 10 170 186 197 169 46 2 41 185 106 290 234 92 145 69 155 +9 138 243 208 200 224 48 21 38 189 40 45 178 162 57 196 78 167 190 180 289 306 +23 269 312 296 132 19 29 226 175 3 181 64 234 151 130 208 96 34 300 174 75 112 +188 112 292 302 89 198 52 275 269 159 155 19 123 66 149 274 70 295 204 266 153 +104 126 62 166 203 126 225 25 90 230 262 264 238 30 60 39 270 299 34 147 300 +278 216 225 35 75 53 203 22 84 228 243 267 185 47 305 95 200 71 223 273 142 226 +12 144 294 276 197 228 31 141 298 259 268 172 101 4 109 133 110 273 38 36 215 +297 15 199 296 28 145 281 14 212 242 280 131 32 291 162 161 70 142 14 153 257 +141 239 274 129 280 27 158 227 315 198 309 290 130 267 81 173 192 248 237 43 6 +24 256 50 44 146 268 68 227 256 213 170 33 56 105 150 39 13 284 173 88 58 124 +147 43 263 39 117 109 286 300 21 201 48 292 149 215 85 156 312 192 307 222 133 +263 98 102 248 178 9 183 132 182 204 113 279 40 104 163 301 265 270 240 49 8 92 +204 54 294 217 212 89 139 67 136 12 85 309 137 256 154 185 210 115 31 304 108 +146 56 209 24 103 176 247 250 305 307 10 7 11 310 65 9 79 258 69 308 150 202 +139 171 277 125 297 272 214 157 87 71 70 83 29 14 67 77 27 311 52 63 94 272 2 +31 200 283 33 160 246 263 251 292 45 74 21 260 33 115 90 289 247 38 130 55 222 +286 88 211 227 ^ +668 0 211 254 226 115 16 41 170 158 305 247 25 183 117 235 218 125 212 30 152 +243 195 254 239 61 28 237 120 302 167 130 194 148 96 312 105 65 160 220 53 281 +270 226 102 70 57 137 91 26 296 105 78 106 204 40 31 232 177 22 129 68 168 269 +74 276 275 208 174 14 126 47 219 218 138 158 14 139 310 203 251 205 166 11 59 +52 214 282 20 214 308 275 182 282 46 106 230 249 316 252 311 309 77 271 15 291 +136 269 100 168 243 182 308 301 74 250 66 240 200 197 156 99 16 54 116 96 21 +314 33 134 37 23 229 156 73 124 132 96 8 51 49 147 287 15 278 190 14 113 101 +235 231 71 196 63 219 205 192 220 27 72 31 206 285 100 155 297 244 4 234 66 253 +146 181 189 166 24 5 36 201 32 28 211 228 17 193 313 224 200 210 102 83 3 121 +78 93 258 56 44 165 215 71 209 9 157 238 259 182 295 38 90 217 316 278 203 277 +97 88 302 193 22 116 122 230 236 7 268 7 242 115 3 95 186 125 238 285 74 263 12 +224 187 264 164 50 299 159 127 127 153 45 13 33 121 91 39 242 89 111 173 166 37 +314 20 188 53 307 162 148 122 204 27 85 294 190 1 167 117 248 164 63 245 97 114 +194 161 42 250 92 132 122 217 290 69 281 257 280 118 37 36 175 94 60 191 94 47 +245 110 60 178 148 109 258 43 98 227 228 4 247 12 237 133 248 151 117 261 110 +47 232 164 76 191 81 101 261 123 310 216 197 143 153 32 67 49 134 24 31 245 123 +6 162 135 176 220 40 18 286 239 35 62 106 217 303 15 265 244 30 126 34 273 280 +105 91 52 188 27 98 240 174 305 234 79 199 84 168 256 128 292 288 141 212 17 +206 259 208 187 277 110 34 286 226 89 124 119 150 24 18 299 185 19 95 173 179 +300 252 7 255 61 304 82 253 133 235 205 179 274 43 85 281 244 17 180 50 286 213 +143 140 86 83 16 67 62 80 8 64 312 131 3 82 240 187 251 218 112 266 92 119 176 +233 303 2 2 306 43 59 26 5 314 46 80 21 10 296 118 24 44 191 107 39 229 143 127 +140 99 29 54 129 42 276 301 100 142 34 260 17 167 104 302 180 76 178 135 163 +274 56 31 219 231 84 142 1 206 272 154 171 264 177 42 237 146 194 135 150 11 72 +44 152 269 87 222 259 195 241 293 77 284 7 229 169 19 108 119 163 287 2 15 252 +298 46 93 284 311 283 185 32 41 157 212 4 260 4 221 120 315 113 114 181 215 58 +263 25 170 171 251 231 58 250 79 186 138 184 223 61 13 20 175 107 6 175 81 114 +207 107 26 283 159 140 73 137 78 80 312 118 11 98 253 120 289 221 146 207 81 88 +315 139 6 149 189 192 233 290 56 18 273 293 51 75 39 255 35 49 160 233 316 265 +257 293 64 21 23 242 102 57 111 199 58 276 288 154 158 1 193 9 170 184 197 169 +45 41 183 104 289 234 92 145 68 155 6 136 243 208 203 ^ +656 0 221 48 21 32 186 40 42 178 159 51 196 72 161 187 177 283 306 23 266 309 +296 129 10 26 220 172 316 178 61 228 151 130 205 90 34 297 168 69 109 182 112 +292 299 83 192 46 269 263 159 149 19 117 63 143 274 67 292 201 260 147 104 313 +126 56 163 200 123 225 16 90 230 262 258 232 21 57 39 264 296 31 147 300 278 +216 219 35 75 50 197 13 78 225 237 267 185 41 302 95 197 71 220 270 139 223 3 +144 288 273 191 228 28 135 295 253 265 172 95 1 106 130 107 267 29 36 212 291 6 +196 293 19 142 275 8 209 239 280 131 23 291 162 161 64 142 14 150 254 141 236 +268 126 277 21 155 221 309 198 306 284 124 264 75 173 192 242 234 34 3 21 253 +44 35 140 262 62 227 250 213 167 30 50 99 150 33 4 281 170 82 55 124 141 40 263 +36 114 109 280 294 18 201 39 289 149 215 82 153 306 186 301 219 133 257 95 99 +248 175 9 183 126 179 198 110 279 34 101 163 298 265 270 237 46 8 86 204 51 294 +214 206 89 133 61 130 9 85 303 134 256 154 182 210 115 25 304 108 143 53 209 18 +103 176 244 247 299 304 10 1 8 307 62 6 73 258 69 305 147 202 136 171 277 119 +297 266 211 154 84 68 70 83 29 11 67 71 24 305 49 60 91 269 2 22 194 280 33 160 +246 260 245 286 39 68 12 260 24 109 84 289 247 38 127 55 222 283 85 205 311 211 +252 226 113 12 39 166 154 305 245 25 181 113 233 216 121 212 30 148 241 195 254 +239 59 313 28 233 118 298 167 128 192 144 92 308 101 65 156 220 49 281 268 224 +100 66 57 137 87 22 292 103 78 102 202 38 29 232 177 22 129 68 168 265 74 272 +275 204 174 10 124 43 217 218 134 158 12 137 308 199 247 201 162 5 59 52 210 +278 20 214 304 271 178 282 46 106 228 249 312 250 311 309 75 271 15 287 136 269 +100 164 239 182 308 297 70 246 64 240 196 195 156 97 14 52 112 96 15 312 29 134 +35 17 227 152 71 122 128 94 2 47 47 145 287 13 274 190 8 111 97 235 229 67 194 +59 215 205 188 216 23 70 25 206 285 98 151 293 240 230 66 253 142 177 185 164 +18 5 34 199 26 24 207 226 15 189 313 224 198 208 102 79 3 119 76 89 256 56 40 +165 213 69 207 5 157 234 255 180 295 32 88 217 316 276 203 273 93 86 302 193 20 +116 122 226 236 7 268 3 242 111 318 93 184 125 238 281 72 259 10 222 185 262 +160 50 295 155 123 127 153 45 9 27 121 89 35 238 85 107 169 166 31 310 16 188 +53 307 160 148 118 200 25 83 290 188 314 165 115 246 162 63 241 97 112 194 157 +38 250 90 132 120 213 290 65 279 255 278 118 37 30 173 94 60 189 92 47 243 110 +58 176 146 105 254 43 94 223 224 2 243 12 235 131 244 149 117 259 108 45 230 +164 76 187 79 101 261 109 ^ +656 0 310 208 189 143 149 32 59 41 130 20 31 245 123 2 154 135 168 216 32 14 +286 231 31 62 102 213 303 7 257 244 22 118 26 269 272 105 91 44 180 27 94 232 +166 301 230 79 199 84 164 248 128 288 284 133 208 17 198 259 204 187 273 102 30 +282 218 85 116 111 146 16 18 299 177 11 87 169 179 292 252 3 255 53 296 82 249 +125 227 201 171 266 39 77 273 240 9 172 46 278 205 139 136 86 79 16 63 54 76 56 +312 123 312 78 236 179 247 210 104 266 84 119 172 229 299 315 311 298 31 51 26 +314 314 38 80 13 2 292 114 24 44 191 103 27 221 135 123 140 99 25 317 54 121 42 +276 301 92 134 22 256 5 159 100 298 180 72 170 131 155 270 52 23 219 231 76 138 +1 202 272 150 167 264 169 30 237 142 186 127 142 3 72 32 152 265 87 214 255 191 +241 293 77 284 316 229 161 15 100 115 159 283 319 3 244 298 42 93 280 303 283 +181 24 33 149 204 4 252 313 213 120 307 113 106 181 207 54 259 21 166 163 251 +223 50 246 75 186 138 184 223 61 1 8 175 107 6 167 81 114 207 99 14 275 155 132 +73 133 70 72 308 110 11 98 245 112 281 221 146 199 73 88 315 139 319 141 189 +188 225 286 48 10 273 285 51 71 35 247 27 49 156 233 312 261 257 289 64 17 15 +238 94 49 111 191 58 272 288 146 154 318 189 5 170 176 197 169 41 313 41 175 96 +285 234 92 145 64 155 315 128 243 208 200 219 48 21 28 184 40 40 178 157 47 196 +68 157 185 175 279 306 23 264 307 296 127 4 24 216 170 314 176 59 224 151 130 +203 86 34 295 164 65 107 178 112 292 297 79 188 42 265 259 159 145 19 113 61 +139 274 65 290 199 256 143 104 311 126 52 161 198 121 225 10 90 230 262 254 228 +15 55 39 260 294 29 147 300 278 216 215 35 75 48 193 7 74 223 233 267 185 37 +300 95 195 71 218 268 137 221 318 144 284 271 187 228 26 131 293 249 263 172 91 +320 104 128 105 263 23 36 210 287 194 291 13 140 271 4 207 237 280 131 17 291 +162 161 60 142 14 148 252 141 234 264 124 275 17 153 217 305 198 304 280 120 +262 71 173 192 238 232 28 1 19 251 40 29 136 258 58 227 246 213 165 28 46 95 +150 29 319 279 168 78 53 124 137 38 263 34 112 109 276 290 16 201 33 287 149 +215 80 151 302 182 297 217 133 253 93 97 248 173 9 183 122 177 194 108 279 30 +99 163 296 265 270 235 44 8 82 204 49 294 212 202 89 129 57 126 7 85 299 132 +256 154 180 210 115 21 304 108 141 51 209 14 103 176 242 245 295 302 10 318 6 +305 60 4 69 258 69 303 145 202 134 171 277 115 297 262 209 152 82 66 70 83 29 9 +67 67 22 301 47 58 89 267 2 16 190 278 33 160 246 258 241 282 35 64 6 260 18 +105 80 289 247 38 125 55 292 ^ +SHS Type 3 Strings +45 0 14 5 3 1 4 16 12 20 1 6 15 11 18 4 17 16 6 10 3 2 9 9 14 6 2 8 6 7 10 17 +12 20 6 7 5 16 1 4 2 17 10 15 8 20 1 ^ + + + + + debug-pipe:name=test-server + unix:tmpdir=/tmp + system + /src/jhbuild/checkout/dbus/bus/dbus-daemon-launch-helper-test + /src/jhbuild/checkout/dbus/test/data/invalid-service-files-system + + + + + + + diff --git a/test/data/valid-config-files-system/debug-allow-all-fail.conf.in b/test/data/valid-config-files-system/debug-allow-all-fail.conf.in new file mode 100644 index 00000000..93a548ce --- /dev/null +++ b/test/data/valid-config-files-system/debug-allow-all-fail.conf.in @@ -0,0 +1,17 @@ + + + + + debug-pipe:name=test-server + unix:tmpdir=@TEST_SOCKET_DIR@ + system + @TEST_LAUNCH_HELPER_BINARY@ + @TEST_INVALID_SERVICE_SYSTEM_DIR@ + + + + + + + diff --git a/test/data/valid-config-files-system/debug-allow-all-pass.conf b/test/data/valid-config-files-system/debug-allow-all-pass.conf new file mode 100644 index 00000000..cc8058cc --- /dev/null +++ b/test/data/valid-config-files-system/debug-allow-all-pass.conf @@ -0,0 +1,17 @@ + + + + + debug-pipe:name=test-server + unix:tmpdir=/tmp + system + /src/jhbuild/checkout/dbus/bus/dbus-daemon-launch-helper-test + /src/jhbuild/checkout/dbus/test/data/valid-service-files-system + + + + + + + diff --git a/test/data/valid-config-files-system/debug-allow-all-pass.conf.in b/test/data/valid-config-files-system/debug-allow-all-pass.conf.in new file mode 100644 index 00000000..5b7ffd1a --- /dev/null +++ b/test/data/valid-config-files-system/debug-allow-all-pass.conf.in @@ -0,0 +1,17 @@ + + + + + debug-pipe:name=test-server + unix:tmpdir=@TEST_SOCKET_DIR@ + system + @TEST_LAUNCH_HELPER_BINARY@ + @TEST_VALID_SERVICE_SYSTEM_DIR@ + + + + + + + diff --git a/test/data/valid-config-files/basic.conf b/test/data/valid-config-files/basic.conf new file mode 100644 index 00000000..5297097d --- /dev/null +++ b/test/data/valid-config-files/basic.conf @@ -0,0 +1,32 @@ + + + mybususer + unix:path=/foo/bar + tcp:port=1234 + basic.d + /usr/share/foo + nonexistent.conf + + + + + 5000 + 5000 + 300 + 5000 + 6000 + 50 + 80 + 64 + 64 + 256 + + + + + + + diff --git a/test/data/valid-config-files/basic.d/basic.conf b/test/data/valid-config-files/basic.d/basic.conf new file mode 100644 index 00000000..d109d71d --- /dev/null +++ b/test/data/valid-config-files/basic.d/basic.conf @@ -0,0 +1,13 @@ + + + mybususer + unix:path=/foo/bar + tcp:port=1234 + basic.d + /usr/share/foo + nonexistent.conf + + + + diff --git a/test/data/valid-config-files/debug-allow-all-sha1.conf b/test/data/valid-config-files/debug-allow-all-sha1.conf new file mode 100644 index 00000000..0323cc8f --- /dev/null +++ b/test/data/valid-config-files/debug-allow-all-sha1.conf @@ -0,0 +1,16 @@ + + + + + debug-pipe:name=test-server + unix:tmpdir=/tmp + /src/jhbuild/checkout/dbus/test/data/valid-service-files + DBUS_COOKIE_SHA1 + + + + + + + diff --git a/test/data/valid-config-files/debug-allow-all-sha1.conf.in b/test/data/valid-config-files/debug-allow-all-sha1.conf.in new file mode 100644 index 00000000..34c50856 --- /dev/null +++ b/test/data/valid-config-files/debug-allow-all-sha1.conf.in @@ -0,0 +1,16 @@ + + + + + debug-pipe:name=test-server + unix:tmpdir=@TEST_SOCKET_DIR@ + @TEST_VALID_SERVICE_DIR@ + DBUS_COOKIE_SHA1 + + + + + + + diff --git a/test/data/valid-config-files/debug-allow-all.conf b/test/data/valid-config-files/debug-allow-all.conf new file mode 100644 index 00000000..d6a3b28b --- /dev/null +++ b/test/data/valid-config-files/debug-allow-all.conf @@ -0,0 +1,15 @@ + + + + + debug-pipe:name=test-server + unix:tmpdir=/tmp + /src/jhbuild/checkout/dbus/test/data/valid-service-files + + + + + + + diff --git a/test/data/valid-config-files/debug-allow-all.conf.in b/test/data/valid-config-files/debug-allow-all.conf.in new file mode 100644 index 00000000..3514296f --- /dev/null +++ b/test/data/valid-config-files/debug-allow-all.conf.in @@ -0,0 +1,15 @@ + + + + + debug-pipe:name=test-server + unix:tmpdir=@TEST_SOCKET_DIR@ + @TEST_VALID_SERVICE_DIR@ + + + + + + + diff --git a/test/data/valid-config-files/entities.conf b/test/data/valid-config-files/entities.conf new file mode 100644 index 00000000..3d3cea79 --- /dev/null +++ b/test/data/valid-config-files/entities.conf @@ -0,0 +1,14 @@ + + + + mybususer + unix:path=/foo/<bar> + tcp:port=1234 + basic.d + /usr/&share/foo + nonexistent.confn + + + + diff --git a/test/data/valid-config-files/many-rules.conf b/test/data/valid-config-files/many-rules.conf new file mode 100644 index 00000000..0a15e83c --- /dev/null +++ b/test/data/valid-config-files/many-rules.conf @@ -0,0 +1,59 @@ + + + mybususer + unix:path=/foo/bar + tcp:port=1234 + basic.d + + /usr/share/foo + nonexistent.conf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5000 + 5000 + 300 + 5000 + 6000 + 50 + 80 + 64 + 64 + 256 + 512 + + diff --git a/test/data/valid-config-files/session.conf b/test/data/valid-config-files/session.conf new file mode 100644 index 00000000..9fd9f54c --- /dev/null +++ b/test/data/valid-config-files/session.conf @@ -0,0 +1,60 @@ + + + + + + session + + + + + unix:tmpdir=/tmp + + + + + + + + + + + + + + session.d + + + session-local.conf + + contexts/dbus_contexts + + + + + 1000000000 + 1000000000 + 1000000000 + 120000 + 240000 + 100000 + 10000 + 100000 + 10000 + 50000 + 50000 + 50000 + + diff --git a/test/data/valid-config-files/system.conf b/test/data/valid-config-files/system.conf new file mode 100644 index 00000000..298c5458 --- /dev/null +++ b/test/data/valid-config-files/system.conf @@ -0,0 +1,83 @@ + + + + + + + + + system + + + messagebus + + + + + + + + + /src/build/dbus/libexec/dbus-daemon-launch-helper + + + /src/build/dbus/var/run/messagebus.pid + + + + + + EXTERNAL + + + unix:path=/src/build/dbus/var/run/dbus/system_bus_socket + + + + + + + + + + + + + + + + + + + + + + + + + + + + system.d + + + system-local.conf + + contexts/dbus_contexts + + diff --git a/test/data/valid-config-files/system.d/test.conf b/test/data/valid-config-files/system.d/test.conf new file mode 100644 index 00000000..5b60a1fc --- /dev/null +++ b/test/data/valid-config-files/system.d/test.conf @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + diff --git a/test/data/valid-messages/array-of-array-of-uint32.message b/test/data/valid-messages/array-of-array-of-uint32.message new file mode 100644 index 00000000..e12186b1 --- /dev/null +++ b/test/data/valid-messages/array-of-array-of-uint32.message @@ -0,0 +1,33 @@ +# Message with an array of array of uint32 + +VALID_HEADER method_call +REQUIRED_FIELDS +ALIGN 8 +END_LENGTH Header +START_LENGTH Body + +TYPE ARRAY +TYPE ARRAY +TYPE UINT32 + +LENGTH Array +START_LENGTH Array + +## array of uint32 +LENGTH SubArray1 +START_LENGTH SubArray1 +UINT32 1 +UINT32 2 +UINT32 3 +END_LENGTH SubArray1 + +## array of uint32 +LENGTH SubArray2 +START_LENGTH SubArray2 +UINT32 4 +UINT32 5 +END_LENGTH SubArray2 + +END_LENGTH Array + +END_LENGTH Body diff --git a/test/data/valid-messages/dict-simple.message b/test/data/valid-messages/dict-simple.message new file mode 100644 index 00000000..fa6927df --- /dev/null +++ b/test/data/valid-messages/dict-simple.message @@ -0,0 +1,15 @@ +# A simple dict + +VALID_HEADER method_call +REQUIRED_FIELDS +ALIGN 8 +END_LENGTH Header +START_LENGTH Body +TYPE DICT +LENGTH Dict +START_LENGTH Dict +STRING 'int32' +TYPE INT32 +INT32 0x12345678 +END_LENGTH Dict +END_LENGTH Body diff --git a/test/data/valid-messages/dict.message b/test/data/valid-messages/dict.message new file mode 100644 index 00000000..0f997b1f --- /dev/null +++ b/test/data/valid-messages/dict.message @@ -0,0 +1,47 @@ +# Dict with different values + +VALID_HEADER method_call +REQUIRED_FIELDS +ALIGN 8 +END_LENGTH Header +START_LENGTH Body +TYPE DICT +LENGTH Dict +START_LENGTH Dict +STRING 'boolean' +TYPE BOOLEAN +BYTE 1 +STRING 'int32' +TYPE INT32 +INT32 0x12345678 +STRING 'uint32' +TYPE UINT32 +UINT32 0x8765432 +STRING 'double' +TYPE DOUBLE +DOUBLE 3.141592653589 +STRING 'string' +TYPE STRING +STRING 'This is a string' +STRING 'boolean_array' +TYPE ARRAY +TYPE BOOLEAN +BOOLEAN_ARRAY { true, false, false, true, false } +STRING 'int32_array' +TYPE ARRAY +TYPE INT32 +INT32_ARRAY { 1, -2, 3, -4, 5, -6, 7, -8, 9, -10 } +STRING 'uint32_array' +TYPE ARRAY +TYPE UINT32 +UINT32_ARRAY { 11, 12, 314, 1911, 57692, 1237, 2834 } +STRING 'double_array' +TYPE ARRAY +TYPE DOUBLE +DOUBLE_ARRAY { 0.1, 0.2, 3.1415926, 2.7183, 10.0, 9.99 } +STRING 'string_array' +TYPE ARRAY +TYPE STRING +STRING_ARRAY { 'Hello', 'This', 'Is', 'A', 'String', 'Array!' } +END_LENGTH Dict +END_LENGTH Body diff --git a/test/data/valid-messages/emptiness.message b/test/data/valid-messages/emptiness.message new file mode 100644 index 00000000..32042c01 --- /dev/null +++ b/test/data/valid-messages/emptiness.message @@ -0,0 +1,63 @@ +# Empty arrays and strings + +VALID_HEADER method_call +REQUIRED_FIELDS +ALIGN 8 +END_LENGTH Header +START_LENGTH Body +TYPE STRING +INT32 0 +BYTE 0 # Strings need to be NULL-terminated +TYPE ARRAY +TYPE BOOLEAN +INT32 0 +TYPE ARRAY +TYPE INT32 +INT32 0 +TYPE ARRAY +TYPE UINT32 +INT32 0 +TYPE ARRAY +TYPE DOUBLE +INT32 0 +TYPE ARRAY +TYPE BYTE +INT32 0 +TYPE ARRAY +TYPE STRING +INT32 0 +TYPE DICT +INT32 0 + +# A dict with empty arrays +TYPE DICT +LENGTH Dict +START_LENGTH Dict +STRING 'boolean_array' +TYPE ARRAY +TYPE BOOLEAN +INT32 0 +STRING 'int32_array' +TYPE ARRAY +TYPE INT32 +INT32 0 +STRING 'uint32_array' +TYPE ARRAY +TYPE UINT32 +INT32 0 +STRING 'double_array' +TYPE ARRAY +TYPE DOUBLE +INT32 0 +STRING 'byte_array' +TYPE ARRAY +TYPE BYTE +INT32 0 +STRING 'string_array' } +TYPE ARRAY +TYPE STRING +INT32 0 +END_LENGTH Dict + +END_LENGTH Body + diff --git a/test/data/valid-messages/lots-of-arguments.message b/test/data/valid-messages/lots-of-arguments.message new file mode 100644 index 00000000..bdaae0f8 --- /dev/null +++ b/test/data/valid-messages/lots-of-arguments.message @@ -0,0 +1,65 @@ +# Message with lots of different argument types + +VALID_HEADER method_call +REQUIRED_FIELDS +ALIGN 8 +END_LENGTH Header +START_LENGTH Body +TYPE NIL +TYPE BYTE +BYTE 42 +TYPE INT32 +INT32 0x12345678 +TYPE UINT32 +UINT32 0x8765432 +TYPE DOUBLE +DOUBLE 3.141592653589 +TYPE STRING +STRING 'This is a string' +TYPE ARRAY +TYPE BOOLEAN +BOOLEAN_ARRAY { true, false, false, true, false } +TYPE ARRAY +TYPE INT32 +INT32_ARRAY { 1, -2, 3, -4, 5, -6, 7, -8, 9, -10 } +TYPE ARRAY +TYPE UINT32 +UINT32_ARRAY { 11, 12, 314, 1911, 57692, 1237, 2834 } +TYPE ARRAY +TYPE DOUBLE +DOUBLE_ARRAY { 0.1, 0.2, 3.1415926, 2.7183, 10.0, 9.99 } +TYPE ARRAY +TYPE STRING +STRING_ARRAY { 'Hello', 'This', 'Is', 'A', 'String', 'Array!' } +TYPE CUSTOM +STRING 'named type' +BYTE_ARRAY { 'b', 'i', 'n', 'a', 'r', 'y', 'd', 'a', 't', 'a' } + +TYPE ARRAY +TYPE DICT +LENGTH Array +START_LENGTH Array + +LENGTH Dict1 +START_LENGTH Dict1 +STRING 'key1' +TYPE INT32 +INT32 0x12345678 +STRING 'key2' +TYPE UINT32 +UINT32 0x8765432 +END_LENGTH Dict1 + +LENGTH Dict2 +START_LENGTH Dict2 +STRING 'key1' +TYPE INT32 +INT32 0x12345678 +STRING 'key2' +TYPE UINT32 +UINT32 0x8765432 +END_LENGTH Dict2 + +END_LENGTH Array + +END_LENGTH Body diff --git a/test/data/valid-messages/no-padding.message b/test/data/valid-messages/no-padding.message new file mode 100644 index 00000000..94df4d45 --- /dev/null +++ b/test/data/valid-messages/no-padding.message @@ -0,0 +1,22 @@ +## Message with no header padding + +## VALID_HEADER includes a LENGTH Header and LENGTH Body +VALID_HEADER method_call + +REQUIRED_FIELDS + +## this byte array is filled with zeros to the natural length +## of the header +HEADER_FIELD UNKNOWN +TYPE ARRAY +TYPE BYTE +ALIGN 4 +LENGTH ThisByteArray +START_LENGTH ThisByteArray +BYTE 1 +ALIGN 8 1 +END_LENGTH ThisByteArray + +END_LENGTH Header +START_LENGTH Body +END_LENGTH Body diff --git a/test/data/valid-messages/opposite-endian.message b/test/data/valid-messages/opposite-endian.message new file mode 100644 index 00000000..90949dd2 --- /dev/null +++ b/test/data/valid-messages/opposite-endian.message @@ -0,0 +1,30 @@ +## Message of opposite endianness, with lots of random fields in it + +OPPOSITE_ENDIAN + +## VALID_HEADER includes a LENGTH Header and LENGTH Body +VALID_HEADER method_call + +REQUIRED_FIELDS + +HEADER_FIELD UNKNOWN +TYPE INT32 +INT32 0xfeeb + +ALIGN 8 +END_LENGTH Header + +START_LENGTH Body + +TYPE INT32 +INT32 89765432 +TYPE UINT32 +UINT32 0xfffffff +TYPE STRING +STRING 'Hello this is a string' +TYPE DOUBLE +DOUBLE 3.14159 + +TYPE NIL + +END_LENGTH Body diff --git a/test/data/valid-messages/recursive-types.message b/test/data/valid-messages/recursive-types.message new file mode 100644 index 00000000..e306fd1f --- /dev/null +++ b/test/data/valid-messages/recursive-types.message @@ -0,0 +1,99 @@ +## Message with recursive types + +## VALID_HEADER includes a LENGTH Header and LENGTH Body +VALID_HEADER method_call + +REQUIRED_FIELDS + +ALIGN 8 +END_LENGTH Header +START_LENGTH Body + +# Everything is inside a dict +TYPE DICT +LENGTH Dict1 +START_LENGTH Dict1 + +# first dict entry is an array of array of uint32 +STRING 'mega-uint-array' +TYPE ARRAY +TYPE ARRAY +TYPE ARRAY +TYPE UINT32 +LENGTH Array1 +START_LENGTH Array1 + +LENGTH Array1_1 +START_LENGTH Array1_1 +UINT32_ARRAY { 1, 2, 3, 4, 5} +UINT32_ARRAY { 2, 3, 4, 5, 1} +UINT32_ARRAY { 3, 4, 5, 1, 2} +END_LENGTH Array1_1 + +LENGTH Array1_2 +START_LENGTH Array1_2 +UINT32_ARRAY { 4, 5, 6, 7, 8} +UINT32_ARRAY { 5, 6, 7, 8, 4} +END_LENGTH Array1_2 + +END_LENGTH Array1 + +# second dict entry is an array of strings +STRING 'string-array' +TYPE ARRAY +TYPE STRING +STRING_ARRAY { 'a', 'string', 'array'} + +# third dict entry is another dict +STRING 'nested-dict' +TYPE DICT +LENGTH Dict2 +START_LENGTH Dict2 + +STRING 'string' +TYPE STRING +STRING 'a deeply nested string' + +STRING 'super-nested-dict' +TYPE DICT +LENGTH Dict3 +START_LENGTH Dict3 + +STRING 'double-array' +TYPE ARRAY +TYPE DOUBLE +DOUBLE_ARRAY {1.0, 2.0, 3.0} + +STRING 'dict-array' +TYPE ARRAY +TYPE DICT +LENGTH Array2 +START_LENGTH Array2 + +LENGTH Dict4 +START_LENGTH Dict4 +STRING 'key4' +TYPE BYTE +BYTE '4' +END_LENGTH Dict4 + +LENGTH Dict5 +START_LENGTH Dict5 +STRING 'key5' +TYPE BYTE +BYTE '5' +END_LENGTH Dict5 + +END_LENGTH Array2 + +STRING 'boolean' +TYPE BOOLEAN +BOOLEAN false + +END_LENGTH Dict3 + +END_LENGTH Dict2 + +END_LENGTH Dict1 + +END_LENGTH Body diff --git a/test/data/valid-messages/simplest-manual.message b/test/data/valid-messages/simplest-manual.message new file mode 100644 index 00000000..d6a960d6 --- /dev/null +++ b/test/data/valid-messages/simplest-manual.message @@ -0,0 +1,30 @@ +## like simplest.message, but doesn't use VALID_HEADER +## convenience command. mostly to test the test framework. + +LITTLE_ENDIAN +BYTE 'l' +BYTE 1 +BYTE 0 +BYTE 0 +LENGTH Header +LENGTH Body +## client serial +INT32 7 + +HEADER_FIELD PATH +TYPE OBJECT_PATH +OBJECT_PATH '/foo' +HEADER_FIELD INTERFACE +TYPE STRING +STRING 'org.freedesktop.Foo' +HEADER_FIELD MEMBER +TYPE STRING +STRING 'Bar' +HEADER_FIELD SIGNATURE +TYPE STRING +STRING '' + +ALIGN 8 +END_LENGTH Header +START_LENGTH Body +END_LENGTH Body diff --git a/test/data/valid-messages/simplest.message b/test/data/valid-messages/simplest.message new file mode 100644 index 00000000..b9ddaf6b --- /dev/null +++ b/test/data/valid-messages/simplest.message @@ -0,0 +1,10 @@ +## simplest possible valid message + +## VALID_HEADER includes a LENGTH Header and LENGTH Body +VALID_HEADER method_call +REQUIRED_FIELDS + +ALIGN 8 +END_LENGTH Header +START_LENGTH Body +END_LENGTH Body diff --git a/test/data/valid-messages/standard-acquire-service.message b/test/data/valid-messages/standard-acquire-service.message new file mode 100644 index 00000000..459f3bb4 --- /dev/null +++ b/test/data/valid-messages/standard-acquire-service.message @@ -0,0 +1,26 @@ +# Standard org.freedesktop.DBus.AcquireService message + +VALID_HEADER method_call +HEADER_FIELD PATH +TYPE OBJECT_PATH +OBJECT_PATH '/org/freedesktop/DBus' +HEADER_FIELD INTERFACE +TYPE STRING +STRING 'org.freedesktop.DBus' +HEADER_FIELD MEMBER +TYPE STRING +STRING 'AcquireService' +HEADER_FIELD DESTINATION +TYPE STRING +STRING 'org.freedesktop.DBus' +HEADER_FIELD SIGNATURE +TYPE STRING +STRING 'su' +ALIGN 8 +END_LENGTH Header +START_LENGTH Body +TYPE STRING +STRING 'org.freedesktop.DBus.Sample' +TYPE UINT32 +UINT32 0 +END_LENGTH Body diff --git a/test/data/valid-messages/standard-hello.message b/test/data/valid-messages/standard-hello.message new file mode 100644 index 00000000..a08835e0 --- /dev/null +++ b/test/data/valid-messages/standard-hello.message @@ -0,0 +1,22 @@ +# Standard org.freedesktop.DBus.Hello message + +VALID_HEADER method_call +HEADER_FIELD PATH +TYPE OBJECT_PATH +OBJECT_PATH '/org/freedesktop/DBus' +HEADER_FIELD INTERFACE +TYPE STRING +STRING 'org.freedesktop.DBus' +HEADER_FIELD MEMBER +TYPE STRING +STRING 'Hello' +HEADER_FIELD DESTINATION +TYPE STRING +STRING 'org.freedesktop.DBus' +HEADER_FIELD SIGNATURE +TYPE STRING +STRING '' +ALIGN 8 +END_LENGTH Header +START_LENGTH Body +END_LENGTH Body diff --git a/test/data/valid-messages/standard-list-services.message b/test/data/valid-messages/standard-list-services.message new file mode 100644 index 00000000..3e10aebe --- /dev/null +++ b/test/data/valid-messages/standard-list-services.message @@ -0,0 +1,22 @@ +# Standard org.freedesktop.DBus.ListServices message + +VALID_HEADER method_call +HEADER_FIELD PATH +TYPE OBJECT_PATH +OBJECT_PATH '/org/freedesktop/DBus' +HEADER_FIELD INTERFACE +TYPE STRING +STRING 'org.freedesktop.DBus' +HEADER_FIELD MEMBER +TYPE STRING +STRING 'ListServices' +HEADER_FIELD DESTINATION +TYPE STRING +STRING 'org.freedesktop.DBus' +HEADER_FIELD SIGNATURE +TYPE STRING +STRING '' +ALIGN 8 +END_LENGTH Header +START_LENGTH Body +END_LENGTH Body diff --git a/test/data/valid-messages/standard-service-exists.message b/test/data/valid-messages/standard-service-exists.message new file mode 100644 index 00000000..6b57eb50 --- /dev/null +++ b/test/data/valid-messages/standard-service-exists.message @@ -0,0 +1,24 @@ +# Standard org.freedesktop.DBus.ServiceExists message + +VALID_HEADER method_call +HEADER_FIELD PATH +TYPE OBJECT_PATH +OBJECT_PATH '/org/freedesktop/DBus' +HEADER_FIELD INTERFACE +TYPE STRING +STRING 'org.freedesktop.DBus' +HEADER_FIELD MEMBER +TYPE STRING +STRING 'ServiceExists' +HEADER_FIELD DESTINATION +TYPE STRING +STRING 'org.freedesktop.DBus' +HEADER_FIELD SIGNATURE +TYPE STRING +STRING 's' +ALIGN 8 +END_LENGTH Header +START_LENGTH Body +TYPE STRING +STRING 'org.freedesktop.DBus.Sample' +END_LENGTH Body diff --git a/test/data/valid-messages/unknown-header-field.message b/test/data/valid-messages/unknown-header-field.message new file mode 100644 index 00000000..ac7d624c --- /dev/null +++ b/test/data/valid-messages/unknown-header-field.message @@ -0,0 +1,19 @@ +## message with a 'name' header field and unknown 'unkn' field + +## VALID_HEADER includes a LENGTH Header and LENGTH Body +VALID_HEADER method_call +REQUIRED_FIELDS + +HEADER_FIELD UNKNOWN +TYPE DICT +LENGTH Dict +START_LENGTH Dict +STRING 'int32' +TYPE INT32 +INT32 0x12345678 +END_LENGTH Dict + +ALIGN 8 +END_LENGTH Header +START_LENGTH Body +END_LENGTH Body diff --git a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service new file mode 100644 index 00000000..ebbd4cfa --- /dev/null +++ b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteEchoService +Exec=/src/jhbuild/checkout/dbus/test/test-service +User=anyrandomuser + diff --git a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in new file mode 100644 index 00000000..bd0e58e5 --- /dev/null +++ b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteEchoService +Exec=@TEST_SERVICE_BINARY@ +User=anyrandomuser + diff --git a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service new file mode 100644 index 00000000..06168bf0 --- /dev/null +++ b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteSegfaultService +Exec=/src/jhbuild/checkout/dbus/test/test-segfault +User=anyrandomuser + diff --git a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in new file mode 100644 index 00000000..18d16d1b --- /dev/null +++ b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteSegfaultService +Exec=@TEST_SEGFAULT_BINARY@ +User=anyrandomuser + diff --git a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service new file mode 100644 index 00000000..6c6f3e72 --- /dev/null +++ b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteShellEchoServiceFail +Exec=/src/jhbuild/checkout/dbus/test/test-shell-service "this should 'fail' because of an unterminated quote +User=anyrandomuser + diff --git a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in new file mode 100644 index 00000000..9195e174 --- /dev/null +++ b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteShellEchoServiceFail +Exec=@TEST_SHELL_SERVICE_BINARY@ "this should 'fail' because of an unterminated quote +User=anyrandomuser + diff --git a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service new file mode 100644 index 00000000..6e0009b9 --- /dev/null +++ b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess +Exec=/src/jhbuild/checkout/dbus/test/test-shell-service -test "that" 'we get' back --what "we put in" +User=anyrandomuser + diff --git a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in new file mode 100644 index 00000000..2236ce55 --- /dev/null +++ b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in @@ -0,0 +1,5 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess +Exec=@TEST_SHELL_SERVICE_BINARY@ -test "that" 'we get' back --what "we put in" +User=anyrandomuser + diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service b/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service new file mode 100644 index 00000000..84e6026b --- /dev/null +++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuite.PrivServer +Exec=/src/jhbuild/checkout/dbus/test/name-test/test-privserver + diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in b/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in new file mode 100644 index 00000000..2cbdaa8b --- /dev/null +++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuite.PrivServer +Exec=@TEST_PRIVSERVER_BINARY@ + diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service new file mode 100644 index 00000000..5b4dd5f8 --- /dev/null +++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteEchoService +Exec=/src/jhbuild/checkout/dbus/test/test-service + diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in new file mode 100644 index 00000000..4202351d --- /dev/null +++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteEchoService +Exec=@TEST_SERVICE_BINARY@ + diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service new file mode 100644 index 00000000..64b20fb1 --- /dev/null +++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteForkingEchoService +Exec=/src/jhbuild/checkout/dbus/test/test-service org.freedesktop.DBus.TestSuiteForkingEchoService fork diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in new file mode 100644 index 00000000..49fcac39 --- /dev/null +++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteForkingEchoService +Exec=@TEST_SERVICE_BINARY@ org.freedesktop.DBus.TestSuiteForkingEchoService fork diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service new file mode 100644 index 00000000..a8c72df4 --- /dev/null +++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteSegfaultService +Exec=/src/jhbuild/checkout/dbus/test/test-segfault + diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in new file mode 100644 index 00000000..73c7b55b --- /dev/null +++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteSegfaultService +Exec=@TEST_SEGFAULT_BINARY@ + diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service new file mode 100644 index 00000000..91a8bef3 --- /dev/null +++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteShellEchoServiceFail +Exec=/src/jhbuild/checkout/dbus/test/test-shell-service "this should 'fail' because of an unterminated quote + diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in new file mode 100644 index 00000000..4404c78e --- /dev/null +++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteShellEchoServiceFail +Exec=@TEST_SHELL_SERVICE_BINARY@ "this should 'fail' because of an unterminated quote + diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service new file mode 100644 index 00000000..7c26e0d1 --- /dev/null +++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess +Exec=/src/jhbuild/checkout/dbus/test/test-shell-service -test "that" 'we get' back --what "we put in" + diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in new file mode 100644 index 00000000..e5688462 --- /dev/null +++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in @@ -0,0 +1,4 @@ +[D-BUS Service] +Name=org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess +Exec=@TEST_SHELL_SERVICE_BINARY@ -test "that" 'we get' back --what "we put in" + diff --git a/test/decode-gcov.c b/test/decode-gcov.c new file mode 100644 index 00000000..f26afd3e --- /dev/null +++ b/test/decode-gcov.c @@ -0,0 +1,2652 @@ + /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* decode-gcov.c gcov decoder program + * + * Copyright (C) 2003 Red Hat Inc. + * + * Partially derived from gcov, + * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, + * 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + * + * This file is NOT licensed under the Academic Free License + * as it is largely derived from gcov.c and gcov-io.h in the + * gcc source code. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define DBUS_COMPILATION /* cheat */ +#include +#include +#include +#include +#include +#undef DBUS_COMPILATION +#include +#include +#include + +#ifndef DBUS_HAVE_INT64 +#error "gcov support can't be built without 64-bit integer support" +#endif + +static void +die (const char *message) +{ + fprintf (stderr, "%s", message); + exit (1); +} + +/* This bizarro function is from gcov-io.h in gcc source tree */ +static int +fetch_long (long *dest, + const char *source, + size_t bytes) +{ + long value = 0; + int i; + + for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--) + if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 )) + return 1; + + for (; i >= 0; i--) + value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255)); + + if ((source[bytes - 1] & 128) && (value > 0)) + value = - value; + + *dest = value; + return 0; +} + +static int +fetch_long64 (dbus_int64_t *dest, + const char *source, + size_t bytes) +{ + dbus_int64_t value = 0; + int i; + + for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--) + if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 )) + return 1; + + for (; i >= 0; i--) + value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255)); + + if ((source[bytes - 1] & 128) && (value > 0)) + value = - value; + + *dest = value; + return 0; +} + +#define BB_FILENAME (-1) +#define BB_FUNCTION (-2) +#define BB_ENDOFLIST 0 + +static dbus_bool_t +string_get_int (const DBusString *str, + int start, + long *val) +{ + const char *p; + + if ((_dbus_string_get_length (str) - start) < 4) + return FALSE; + + p = _dbus_string_get_const_data (str); + + p += start; + + fetch_long (val, p, 4); + + return TRUE; +} + +static dbus_bool_t +string_get_int64 (const DBusString *str, + int start, + dbus_int64_t *val) +{ + const char *p; + + if ((_dbus_string_get_length (str) - start) < 8) + return FALSE; + + p = _dbus_string_get_const_data (str); + + p += start; + + fetch_long64 (val, p, 8); + + return TRUE; +} + +static dbus_bool_t +string_get_string (const DBusString *str, + int start, + long terminator, + DBusString *val, + int *end) +{ + int i; + long n; + + i = start; + while (string_get_int (str, i, &n)) + { + unsigned char b; + + i += 4; + + if (n == terminator) + break; + + b = n & 0xff; + if (b) + { + _dbus_string_append_byte (val, b); + b = (n >> 8) & 0xff; + if (b) + { + _dbus_string_append_byte (val, b); + b = (n >> 16) & 0xff; + if (b) + { + _dbus_string_append_byte (val, b); + b = (n >> 24) & 0xff; + if (b) + _dbus_string_append_byte (val, b); + } + } + } + } + + *end = i; + + return TRUE; +} + +#ifdef DBUS_HAVE_GCC33_GCOV +/* In gcc33 .bbg files, there's a function name of the form: + * -1, length, name (padded to 4), -1, checksum + */ +static dbus_bool_t +string_get_function (const DBusString *str, + int start, + DBusString *funcname, + int *checksum, + int *next) +{ + int end; + long val; + int i; + + i = start; + + if (!string_get_int (str, i, &val)) + die ("no room for -1 before function name\n"); + + i += 4; + + if (val != -1) + die ("value before function name is not -1\n"); + + if (!string_get_int (str, i, &val)) + die ("no length found for function name\n"); + + i += 4; + + end = i + val; + if (end > _dbus_string_get_length (str)) + die ("Function name length points past end of file\n"); + + if (!_dbus_string_append (funcname, + _dbus_string_get_const_data (str) + i)) + die ("no memory\n"); + + /* skip alignment padding the length doesn't include the nul so add 1 + */ + i = _DBUS_ALIGN_VALUE (end + 1, 4); + + if (!string_get_int (str, i, &val) || + val != -1) + die ("-1 at end of function name not found\n"); + + i += 4; + + if (!string_get_int (str, i, &val)) + die ("no checksum found at end of function name\n"); + + i += 4; + + *checksum = val; + + *next = i; + + return TRUE; +} +#endif /* DBUS_HAVE_GCC33_GCOV */ + +static void +dump_bb_file (const DBusString *contents) +{ + int i; + long val; + int n_functions; + + n_functions = 0; + i = 0; + while (string_get_int (contents, i, &val)) + { + i += 4; + + switch (val) + { + case BB_FILENAME: + { + DBusString f; + + if (!_dbus_string_init (&f)) + die ("no memory\n"); + + if (string_get_string (contents, i, + BB_FILENAME, + &f, &i)) + { + printf ("File %s\n", _dbus_string_get_const_data (&f)); + } + _dbus_string_free (&f); + } + break; + case BB_FUNCTION: + { + DBusString f; + if (!_dbus_string_init (&f)) + die ("no memory\n"); + + if (string_get_string (contents, i, + BB_FUNCTION, + &f, &i)) + { + printf ("Function %s\n", _dbus_string_get_const_data (&f)); + } + _dbus_string_free (&f); + + n_functions += 1; + } + break; + case BB_ENDOFLIST: + printf ("End of block\n"); + break; + default: + printf ("Line %ld\n", val); + break; + } + } + + printf ("%d functions in file\n", n_functions); +} + +#define FLAG_ON_TREE 0x1 +#define FLAG_FAKE 0x2 +#define FLAG_FALL_THROUGH 0x4 + +static void +dump_bbg_file (const DBusString *contents) +{ + int i; + long val; + int n_functions; + int n_arcs; + int n_blocks; + int n_arcs_off_tree; + + n_arcs_off_tree = 0; + n_blocks = 0; + n_arcs = 0; + n_functions = 0; + i = 0; + while (i < _dbus_string_get_length (contents)) + { + long n_blocks_in_func; + long n_arcs_in_func; + int j; + +#ifdef DBUS_HAVE_GCC33_GCOV + /* In gcc33 .bbg files, there's a function name of the form: + * -1, length, name (padded to 4), -1, checksum + * after that header on each function description, it's + * the same as in gcc32 + */ + + { + DBusString funcname; + int checksum; + + if (!_dbus_string_init (&funcname)) + die ("no memory\n"); + + if (!string_get_function (contents, i, + &funcname, &checksum, &i)) + die ("could not read function name\n"); + + printf ("Function name is \"%s\" checksum %d\n", + _dbus_string_get_const_data (&funcname), + checksum); + + _dbus_string_free (&funcname); + } +#endif /* DBUS_HAVE_GCC33_GCOV */ + + if (!string_get_int (contents, i, &val)) + die ("no count of blocks in func found\n"); + + i += 4; + + n_blocks_in_func = val; + + if (!string_get_int (contents, i, &n_arcs_in_func)) + break; + + i += 4; + + printf ("Function has %ld blocks and %ld arcs\n", + n_blocks_in_func, n_arcs_in_func); + + n_functions += 1; + n_blocks += n_blocks_in_func; + n_arcs += n_arcs_in_func; + + j = 0; + while (j < n_blocks_in_func) + { + long n_arcs_in_block; + int k; + + if (!string_get_int (contents, i, &n_arcs_in_block)) + break; + + i += 4; + + printf (" Block has %ld arcs\n", n_arcs_in_block); + + k = 0; + while (k < n_arcs_in_block) + { + long destination_block; + long flags; + + if (!string_get_int (contents, i, &destination_block)) + break; + + i += 4; + + if (!string_get_int (contents, i, &flags)) + break; + + i += 4; + + printf (" Arc has destination block %ld flags 0x%lx\n", + destination_block, flags); + + if ((flags & FLAG_ON_TREE) == 0) + n_arcs_off_tree += 1; + + ++k; + } + + if (k < n_arcs_in_block) + break; + + ++j; + } + + if (j < n_blocks_in_func) + break; + + if (!string_get_int (contents, i, &val)) + break; + + i += 4; + + if (val != -1) + die ("-1 separator not found\n"); + } + + printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n", + n_functions, n_blocks, n_arcs, n_arcs_off_tree); +} + +#ifndef DBUS_HAVE_GCC33_GCOV + +/* gcc 3.2 version: + * The da file contains first a count of arcs in the file, + * then a count of executions for all "off tree" arcs + * in the file. + */ +static void +dump_da_file (const DBusString *contents) +{ + int i; + dbus_int64_t val; + int n_arcs; + int claimed_n_arcs; + + i = 0; + if (!string_get_int64 (contents, i, &val)) + return; + + i += 8; + + printf ("%ld arcs in file\n", (long) val); + claimed_n_arcs = val; + + n_arcs = 0; + while (string_get_int64 (contents, i, &val)) + { + i += 8; + + printf ("%ld executions of arc %d\n", + (long) val, n_arcs); + + ++n_arcs; + } + + if (n_arcs != claimed_n_arcs) + { + printf ("File claimed to have %d arcs but only had %d\n", + claimed_n_arcs, n_arcs); + } +} + +#else /* DBUS_HAVE_GCC33_GCOV */ + +/* gcc 3.3 version: + * The da file is more complex than 3.2. + * + * We have a magic value of "-123" only it isn't really + * -123, it's -123 as encoded by the crackass gcov-io.h + * routines. Anyway, 4 bytes. + * + * We then have: + * + * - 4 byte count of how many functions in the following list + * - 4 byte length of random extra data + * - the random extra data, just skip it, info pages have some + * details on what might be in there or see __bb_exit_func in gcc + * - then for each function (number of functions given above): + * . -1, length, funcname, alignment padding, -1 + * . checksum + * . 4 byte number of arcs in function + * . 8 bytes each, a count of execution for each arc + * + * Now, the whole thing *starting with the magic* can repeat. + * This is caused by multiple runs of the profiled app appending + * to the file. + */ +static void +dump_da_file (const DBusString *contents) +{ + int i; + dbus_int64_t v64; + long val; + int n_sections; + int total_functions; + + total_functions = 0; + n_sections = 0; + + i = 0; + while (i < _dbus_string_get_length (contents)) + { + int claimed_n_functions; + int n_functions; + int total_arcs; + + printf (".da file section %d\n", n_sections); + + if (!string_get_int (contents, i, &val)) + die ("no magic found in .da file\n"); + + i += 4; + + if (val != -123) + die ("wrong file magic in .da file\n"); + + if (!string_get_int (contents, i, &val)) + die ("no function count in .da file\n"); + i += 4; + claimed_n_functions = val; + + printf ("%d functions expected in section %d of .da file\n", + claimed_n_functions, n_sections); + + if (!string_get_int (contents, i, &val)) + die ("no extra data length in .da file\n"); + + i += 4; + + i += val; + + total_arcs = 0; + n_functions = 0; + while (n_functions < claimed_n_functions) + { + DBusString funcname; + int checksum; + int claimed_n_arcs; + int n_arcs; + + if (!_dbus_string_init (&funcname)) + die ("no memory\n"); + + if (!string_get_function (contents, i, + &funcname, &checksum, &i)) + die ("could not read function name\n"); + + if (!string_get_int (contents, i, &val)) + die ("no arc count for function\n"); + + i += 4; + claimed_n_arcs = val; + + printf (" %d arcs in function %d %s checksum %d\n", + claimed_n_arcs, n_functions, + _dbus_string_get_const_data (&funcname), + checksum); + + n_arcs = 0; + while (n_arcs < claimed_n_arcs) + { + if (!string_get_int64 (contents, i, &v64)) + die ("did not get execution count for arc\n"); + + i += 8; + + printf (" %ld executions of arc %d (total arcs %d)\n", + (long) v64, n_arcs, total_arcs + n_arcs); + + ++n_arcs; + } + + _dbus_string_free (&funcname); + + total_arcs += n_arcs; + ++n_functions; + } + + printf ("total of %d functions and %d arcs in section %d\n", + n_functions, total_arcs, n_sections); + + total_functions += n_functions; + ++n_sections; + } + + printf ("%d total function sections in %d total .da file sections\n", + total_functions, n_sections); +} + +#endif /* DBUS_HAVE_GCC33_GCOV */ + +typedef struct Arc Arc; +typedef struct Block Block; +typedef struct Function Function; +typedef struct File File; +typedef struct Line Line; + +struct Arc +{ + int source; + int target; + dbus_int64_t arc_count; + unsigned int count_valid : 1; + unsigned int on_tree : 1; + unsigned int fake : 1; + unsigned int fall_through : 1; + Arc *pred_next; + Arc *succ_next; +}; + +struct Block +{ + Arc *succ; + Arc *pred; + dbus_int64_t succ_count; + dbus_int64_t pred_count; + dbus_int64_t exec_count; + DBusList *lines; + unsigned int count_valid : 1; + unsigned int on_tree : 1; + unsigned int inside_dbus_build_tests : 1; +}; + +struct Function +{ + char *name; + int checksum; + Block *block_graph; + int n_blocks; + /* number of blocks in DBUS_BUILD_TESTS */ + int n_test_blocks; + int n_test_blocks_executed; + /* number of blocks outside DBUS_BUILD_TESTS */ + int n_nontest_blocks; + int n_nontest_blocks_executed; + /* Summary result flags */ + unsigned int unused : 1; + unsigned int inside_dbus_build_tests : 1; + unsigned int partial : 1; /* only some of the blocks were executed */ +}; + +struct Line +{ + int number; + char *text; + DBusList *blocks; + unsigned int inside_dbus_build_tests : 1; + unsigned int partial : 1; /* only some of the blocks were executed */ +}; + +struct File +{ + char *name; + Line *lines; + int n_lines; + DBusList *functions; +}; + +static void +function_add_arc (Function *function, + long source, + long target, + long flags) +{ + Arc *arc; + + arc = dbus_new0 (Arc, 1); + if (arc == NULL) + die ("no memory\n"); + + arc->target = target; + arc->source = source; + + arc->succ_next = function->block_graph[source].succ; + function->block_graph[source].succ = arc; + function->block_graph[source].succ_count += 1; + + arc->pred_next = function->block_graph[target].pred; + function->block_graph[target].pred = arc; + function->block_graph[target].pred_count += 1; + + if ((flags & FLAG_ON_TREE) != 0) + arc->on_tree = TRUE; + + if ((flags & FLAG_FAKE) != 0) + arc->fake = TRUE; + + if ((flags & FLAG_FALL_THROUGH) != 0) + arc->fall_through = TRUE; +} + + +static Arc* +reverse_arcs (Arc *arc) +{ + struct Arc *prev = 0; + struct Arc *next; + + for ( ; arc; arc = next) + { + next = arc->succ_next; + arc->succ_next = prev; + prev = arc; + } + + return prev; +} + +static void +function_reverse_succ_arcs (Function *func) +{ + /* Must reverse the order of all succ arcs, to ensure that they match + * the order of the data in the .da file. + */ + int i; + + for (i = 0; i < func->n_blocks; i++) + if (func->block_graph[i].succ) + func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ); +} + +static void +get_functions_from_bbg (const DBusString *contents, + DBusList **functions) +{ + int i; + long val; + int n_functions; + int n_arcs; + int n_blocks; + int n_arcs_off_tree; + +#if 0 + printf ("Loading arcs and blocks from .bbg file\n"); +#endif + + n_arcs_off_tree = 0; + n_blocks = 0; + n_arcs = 0; + n_functions = 0; + i = 0; + while (i < _dbus_string_get_length (contents)) + { + Function *func; + long n_blocks_in_func; + long n_arcs_in_func; + int j; + +#ifdef DBUS_HAVE_GCC33_GCOV + DBusString funcname; + int checksum; + + /* In gcc33 .bbg files, there's a function name of the form: + * -1, length, name (padded to 4), -1, checksum + * after that header on each function description, it's + * the same as in gcc32 + */ + if (!_dbus_string_init (&funcname)) + die ("no memory\n"); + + if (!string_get_function (contents, i, + &funcname, &checksum, &i)) + die ("could not read function name\n"); +#endif /* DBUS_HAVE_GCC33_GCOV */ + + if (!string_get_int (contents, i, &val)) + break; + + n_blocks_in_func = val; + + i += 4; + + if (!string_get_int (contents, i, &n_arcs_in_func)) + break; + + i += 4; + + n_functions += 1; + n_blocks += n_blocks_in_func; + n_arcs += n_arcs_in_func; + + func = dbus_new0 (Function, 1); + if (func == NULL) + die ("no memory\n"); + +#ifdef DBUS_HAVE_GCC33_GCOV + func->name = _dbus_strdup (_dbus_string_get_const_data (&funcname)); + func->checksum = checksum; + _dbus_string_free (&funcname); +#endif + + func->block_graph = dbus_new0 (Block, n_blocks_in_func); + func->n_blocks = n_blocks_in_func; + + j = 0; + while (j < n_blocks_in_func) + { + long n_arcs_in_block; + int k; + + if (!string_get_int (contents, i, &n_arcs_in_block)) + break; + + i += 4; + + k = 0; + while (k < n_arcs_in_block) + { + long destination_block; + long flags; + + if (!string_get_int (contents, i, &destination_block)) + break; + + i += 4; + + if (!string_get_int (contents, i, &flags)) + break; + + i += 4; + + if ((flags & FLAG_ON_TREE) == 0) + n_arcs_off_tree += 1; + + function_add_arc (func, j, destination_block, + flags); + + ++k; + } + + if (k < n_arcs_in_block) + break; + + ++j; + } + + if (j < n_blocks_in_func) + break; + + function_reverse_succ_arcs (func); + + if (!_dbus_list_append (functions, func)) + die ("no memory\n"); + + if (!string_get_int (contents, i, &val)) + break; + + i += 4; + + if (val != -1) + die ("-1 separator not found in .bbg file\n"); + } + +#if 0 + printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n", + n_functions, n_blocks, n_arcs, n_arcs_off_tree); +#endif + + _dbus_assert (n_functions == _dbus_list_get_length (functions)); +} + +#ifdef DBUS_HAVE_GCC33_GCOV +static void +add_counts_from_da (const DBusString *contents, + DBusList **functions) +{ + int i; + dbus_int64_t v64; + long val; + int n_sections; + DBusList *link; + Function *current_func; + int current_block; + Arc *current_arc; + + n_sections = 0; + + i = 0; + while (i < _dbus_string_get_length (contents)) + { + int claimed_n_functions; + int n_functions; + + if (!string_get_int (contents, i, &val)) + die ("no magic found in .da file\n"); + + i += 4; + + if (val != -123) + die ("wrong file magic in .da file\n"); + + if (!string_get_int (contents, i, &val)) + die ("no function count in .da file\n"); + i += 4; + claimed_n_functions = val; + + if (!string_get_int (contents, i, &val)) + die ("no extra data length in .da file\n"); + + i += 4; + + i += val; + + link = _dbus_list_get_first_link (functions); + if (link == NULL) + goto no_more_functions; + + n_functions = 0; + while (n_functions < claimed_n_functions && link != NULL) + { + DBusString funcname; + int checksum; + int claimed_n_arcs; + int n_arcs; + + current_func = link->data; + current_block = 0; + current_arc = current_func->block_graph[current_block].succ; + + if (!_dbus_string_init (&funcname)) + die ("no memory\n"); + + if (!string_get_function (contents, i, + &funcname, &checksum, &i)) + die ("could not read function name\n"); + + if (!_dbus_string_equal_c_str (&funcname, current_func->name)) + { + fprintf (stderr, "Expecting .da info for %s but got %s\n", + current_func->name, + _dbus_string_get_const_data (&funcname)); + exit (1); + } + + if (checksum != current_func->checksum) + die (".da file checksum doesn't match checksum from .bbg file\n"); + + if (!string_get_int (contents, i, &val)) + die ("no arc count for function\n"); + + i += 4; + claimed_n_arcs = val; + + /* For each arc in the profile, find the corresponding + * arc in the function and increment its count + */ + n_arcs = 0; + while (n_arcs < claimed_n_arcs) + { + if (!string_get_int64 (contents, i, &v64)) + die ("did not get execution count for arc\n"); + + i += 8; + + /* Find the next arc in the function that isn't on tree */ + while (current_arc == NULL || + current_arc->on_tree) + { + if (current_arc == NULL) + { + ++current_block; + + if (current_block >= current_func->n_blocks) + die ("too many blocks in function\n"); + + current_arc = current_func->block_graph[current_block].succ; + } + else + { + current_arc = current_arc->succ_next; + } + } + + _dbus_assert (current_arc != NULL); + _dbus_assert (!current_arc->on_tree); + + current_arc->arc_count = v64; + current_arc->count_valid = TRUE; + current_func->block_graph[current_block].succ_count -= 1; + current_func->block_graph[current_arc->target].pred_count -= 1; + + ++n_arcs; + + current_arc = current_arc->succ_next; + } + + _dbus_string_free (&funcname); + + link = _dbus_list_get_next_link (functions, link); + ++n_functions; + + if (link == NULL && n_functions < claimed_n_functions) + { + fprintf (stderr, "Ran out of functions loading .da file\n"); + goto no_more_functions; + } + } + + no_more_functions: + + ++n_sections; + } +} +#else /* DBUS_HAVE_GCC33_GCOV */ +static void +add_counts_from_da (const DBusString *contents, + DBusList **functions) +{ + int i; + dbus_int64_t val; + int n_arcs; + int claimed_n_arcs; + DBusList *link; + Function *current_func; + int current_block; + Arc *current_arc; + +#if 0 + printf ("Loading execution count for each arc from .da file\n"); +#endif + + i = 0; + if (!string_get_int64 (contents, i, &val)) + return; + + i += 8; + + claimed_n_arcs = val; + + link = _dbus_list_get_first_link (functions); + if (link == NULL) + goto done; + + current_func = link->data; + current_block = 0; + current_arc = current_func->block_graph[current_block].succ; + + n_arcs = 0; + while (string_get_int64 (contents, i, &val)) + { + i += 8; + + while (current_arc == NULL || + current_arc->on_tree) + { + if (current_arc == NULL) + { + ++current_block; + + if (current_block == current_func->n_blocks) + { + link = _dbus_list_get_next_link (functions, link); + if (link == NULL) + { + fprintf (stderr, "Ran out of functions loading .da file\n"); + goto done; + } + current_func = link->data; + current_block = 0; + } + + current_arc = current_func->block_graph[current_block].succ; + } + else + { + current_arc = current_arc->succ_next; + } + } + + _dbus_assert (current_arc != NULL); + _dbus_assert (!current_arc->on_tree); + + current_arc->arc_count = val; + current_arc->count_valid = TRUE; + current_func->block_graph[current_block].succ_count -= 1; + current_func->block_graph[current_arc->target].pred_count -= 1; + + ++n_arcs; + + current_arc = current_arc->succ_next; + } + + done: + + if (n_arcs != claimed_n_arcs) + { + fprintf (stderr, "File claimed to have %d arcs but only had %d\n", + claimed_n_arcs, n_arcs); + exit (1); + } + +#if 0 + printf ("%d arcs in file\n", n_arcs); +#endif +} +#endif + +static void +function_solve_graph (Function *func) +{ + int passes, changes; + dbus_int64_t total; + int i; + Arc *arc; + Block *block_graph; + int n_blocks; + +#if 0 + printf ("Solving function graph\n"); +#endif + + n_blocks = func->n_blocks; + block_graph = func->block_graph; + + /* For every block in the file, + - if every exit/entrance arc has a known count, then set the block count + - if the block count is known, and every exit/entrance arc but one has + a known execution count, then set the count of the remaining arc + + As arc counts are set, decrement the succ/pred count, but don't delete + the arc, that way we can easily tell when all arcs are known, or only + one arc is unknown. */ + + /* The order that the basic blocks are iterated through is important. + Since the code that finds spanning trees starts with block 0, low numbered + arcs are put on the spanning tree in preference to high numbered arcs. + Hence, most instrumented arcs are at the end. Graph solving works much + faster if we propagate numbers from the end to the start. + + This takes an average of slightly more than 3 passes. */ + + changes = 1; + passes = 0; + while (changes) + { + passes++; + changes = 0; + + for (i = n_blocks - 1; i >= 0; i--) + { + if (! block_graph[i].count_valid) + { + if (block_graph[i].succ_count == 0) + { + total = 0; + for (arc = block_graph[i].succ; arc; + arc = arc->succ_next) + total += arc->arc_count; + block_graph[i].exec_count = total; + block_graph[i].count_valid = 1; + changes = 1; + } + else if (block_graph[i].pred_count == 0) + { + total = 0; + for (arc = block_graph[i].pred; arc; + arc = arc->pred_next) + total += arc->arc_count; + block_graph[i].exec_count = total; + block_graph[i].count_valid = 1; + changes = 1; + } + } + if (block_graph[i].count_valid) + { + if (block_graph[i].succ_count == 1) + { + total = 0; + /* One of the counts will be invalid, but it is zero, + so adding it in also doesn't hurt. */ + for (arc = block_graph[i].succ; arc; + arc = arc->succ_next) + total += arc->arc_count; + /* Calculate count for remaining arc by conservation. */ + total = block_graph[i].exec_count - total; + /* Search for the invalid arc, and set its count. */ + for (arc = block_graph[i].succ; arc; + arc = arc->succ_next) + if (! arc->count_valid) + break; + if (! arc) + die ("arc == NULL\n"); + arc->count_valid = 1; + arc->arc_count = total; + block_graph[i].succ_count -= 1; + + block_graph[arc->target].pred_count -= 1; + changes = 1; + } + if (block_graph[i].pred_count == 1) + { + total = 0; + /* One of the counts will be invalid, but it is zero, + so adding it in also doesn't hurt. */ + for (arc = block_graph[i].pred; arc; + arc = arc->pred_next) + total += arc->arc_count; + /* Calculate count for remaining arc by conservation. */ + total = block_graph[i].exec_count - total; + /* Search for the invalid arc, and set its count. */ + for (arc = block_graph[i].pred; arc; + arc = arc->pred_next) + if (! arc->count_valid) + break; + if (! arc) + die ("arc == NULL\n"); + arc->count_valid = 1; + arc->arc_count = total; + block_graph[i].pred_count -= 1; + + block_graph[arc->source].succ_count -= 1; + changes = 1; + } + } + } + } + + /* If the graph has been correctly solved, every block will have a + * succ and pred count of zero. + */ + { + dbus_bool_t header = FALSE; + for (i = 0; i < n_blocks; i++) + { + if (block_graph[i].succ_count || block_graph[i].pred_count) + { + if (!header) + { + fprintf (stderr, "WARNING: Block graph solved incorrectly for function %s\n", + func->name); + fprintf (stderr, " this error reflects a bug in decode-gcov.c or perhaps bogus data\n"); + header = TRUE; + } + fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n", + i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count); + } + } + } +} + +static void +solve_graphs (DBusList **functions) +{ + DBusList *link; + + link = _dbus_list_get_first_link (functions); + while (link != NULL) + { + Function *func = link->data; + + function_solve_graph (func); + + link = _dbus_list_get_next_link (functions, link); + } +} + +static void +load_functions_for_c_file (const DBusString *filename, + DBusList **functions) +{ + DBusString bbg_filename; + DBusString da_filename; + DBusString gcno_filename; + DBusString gcda_filename; + DBusString contents; + DBusString *name; + DBusError error; + + /* With latest gcc it's .gcno instead of .bbg and + * gcda instead of .da + */ + + dbus_error_init (&error); + + if (!_dbus_string_init (&bbg_filename) || + !_dbus_string_init (&da_filename) || + !_dbus_string_init (&gcno_filename) || + !_dbus_string_init (&gcda_filename) || + !_dbus_string_copy (filename, 0, &bbg_filename, 0) || + !_dbus_string_copy (filename, 0, &da_filename, 0) || + !_dbus_string_copy (filename, 0, &gcno_filename, 0) || + !_dbus_string_copy (filename, 0, &gcda_filename, 0) || + !_dbus_string_init (&contents)) + die ("no memory\n"); + + _dbus_string_shorten (&bbg_filename, 2); + _dbus_string_shorten (&da_filename, 2); + + if (!_dbus_string_append (&bbg_filename, ".bbg") || + !_dbus_string_append (&da_filename, ".da") || + !_dbus_string_append (&bbg_filename, ".gcno") || + !_dbus_string_append (&bbg_filename, ".gcda")) + die ("no memory\n"); + + if (_dbus_file_exists (_dbus_string_get_const_data (&gcno_filename))) + name = &gcno_filename; + else + name = &bbg_filename; + + if (!_dbus_file_get_contents (&contents, name, + &error)) + { + fprintf (stderr, "Could not open file: %s\n", + error.message); + exit (1); + } + + get_functions_from_bbg (&contents, functions); + + _dbus_string_set_length (&contents, 0); + + if (_dbus_file_exists (_dbus_string_get_const_data (&gcda_filename))) + name = &gcda_filename; + else + name = &da_filename; + + if (!_dbus_file_get_contents (&contents, name, + &error)) + { + /* Try .libs/file.da */ + int slash; + + if (_dbus_string_find_byte_backward (name, + _dbus_string_get_length (name), + '/', + &slash)) + { + DBusString libs; + _dbus_string_init_const (&libs, "/.libs"); + + if (!_dbus_string_copy (&libs, 0, name, slash)) + die ("no memory"); + + dbus_error_free (&error); + if (!_dbus_file_get_contents (&contents, name, + &error)) + { + fprintf (stderr, "Could not open file: %s\n", + error.message); + exit (1); + } + } + else + { + fprintf (stderr, "Could not open file: %s\n", + error.message); + exit (1); + } + } + + add_counts_from_da (&contents, functions); + + solve_graphs (functions); + + _dbus_string_free (&contents); + _dbus_string_free (&da_filename); + _dbus_string_free (&bbg_filename); +} + +static void +get_lines_from_bb_file (const DBusString *contents, + File *fl) +{ + int i; + long val; + int n_functions; + dbus_bool_t in_our_file; + DBusList *link; + Function *func; + int block; + +#if 0 + printf ("Getting line numbers for blocks from .bb file\n"); +#endif + + /* There's this "filename" field in the .bb file which + * mysteriously comes *after* the first function in the + * file in the .bb file; and every .bb file seems to + * have only one filename. I don't understand + * what's going on here, so just set in_our_file = TRUE + * at the start categorically. + */ + + block = 0; + func = NULL; + in_our_file = TRUE; + link = _dbus_list_get_first_link (&fl->functions); + n_functions = 0; + i = 0; + while (string_get_int (contents, i, &val)) + { + i += 4; + + switch (val) + { + case BB_FILENAME: + { + DBusString f; + + if (!_dbus_string_init (&f)) + die ("no memory\n"); + + if (string_get_string (contents, i, + BB_FILENAME, + &f, &i)) + { + /* fl->name is a full path and the filename in .bb is + * not. + */ + DBusString tmp_str; + + _dbus_string_init_const (&tmp_str, fl->name); + + if (_dbus_string_ends_with_c_str (&tmp_str, + _dbus_string_get_const_data (&f))) + in_our_file = TRUE; + else + in_our_file = FALSE; + +#if 0 + fprintf (stderr, + "File %s in .bb, looking for %s, in_our_file = %d\n", + _dbus_string_get_const_data (&f), + fl->name, + in_our_file); +#endif + } + _dbus_string_free (&f); + } + break; + case BB_FUNCTION: + { + DBusString f; + if (!_dbus_string_init (&f)) + die ("no memory\n"); + + if (string_get_string (contents, i, + BB_FUNCTION, + &f, &i)) + { +#if 0 + fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f)); +#endif + + block = 0; + + if (in_our_file) + { + if (link == NULL) + { + fprintf (stderr, "No function object for function %s\n", + _dbus_string_get_const_data (&f)); + } + else + { + func = link->data; + link = _dbus_list_get_next_link (&fl->functions, link); + + if (func->name == NULL) + { + if (!_dbus_string_copy_data (&f, &func->name)) + die ("no memory\n"); + } + else + { + if (!_dbus_string_equal_c_str (&f, func->name)) + { + fprintf (stderr, "got function name \"%s\" (%d) from .bbg file, but \"%s\" (%d) from .bb file\n", + func->name, strlen (func->name), + _dbus_string_get_const_data (&f), + _dbus_string_get_length (&f)); + + } + } + } + } + } + _dbus_string_free (&f); + + n_functions += 1; + } + break; + case BB_ENDOFLIST: + block += 1; + break; + default: +#if 0 + fprintf (stderr, "Line %ld\n", val); +#endif + + if (val >= fl->n_lines) + { + fprintf (stderr, "Line %ld but file only has %d lines\n", + val, fl->n_lines); + } + else if (func != NULL) + { + val -= 1; /* To convert the 1-based line number to 0-based */ + _dbus_assert (val >= 0); + + if (block < func->n_blocks) + { + if (!_dbus_list_append (&func->block_graph[block].lines, + &fl->lines[val])) + die ("no memory\n"); + + + if (!_dbus_list_append (&fl->lines[val].blocks, + &func->block_graph[block])) + die ("no memory\n"); + } + else + { + fprintf (stderr, "Line number for block %d but function only has %d blocks\n", + block, func->n_blocks); + } + } + else + { + fprintf (stderr, "Line %ld given outside of any function\n", + val); + } + + break; + } + } + +#if 0 + printf ("%d functions in file\n", n_functions); +#endif +} + + +static void +load_block_line_associations (const DBusString *filename, + File *f) +{ + DBusString bb_filename; + DBusString contents; + DBusError error; + + dbus_error_init (&error); + + if (!_dbus_string_init (&bb_filename) || + !_dbus_string_copy (filename, 0, &bb_filename, 0) || + !_dbus_string_init (&contents)) + die ("no memory\n"); + + _dbus_string_shorten (&bb_filename, 2); + + if (!_dbus_string_append (&bb_filename, ".bb")) + die ("no memory\n"); + + if (!_dbus_file_get_contents (&contents, &bb_filename, + &error)) + { + fprintf (stderr, "Could not open file: %s\n", + error.message); + exit (1); + } + + get_lines_from_bb_file (&contents, f); + + _dbus_string_free (&contents); + _dbus_string_free (&bb_filename); +} + +static int +count_lines_in_string (const DBusString *str) +{ + int n_lines; + const char *p; + const char *prev; + const char *end; + const char *last_line_end; + +#if 0 + printf ("Counting lines in source file\n"); +#endif + + n_lines = 0; + prev = NULL; + p = _dbus_string_get_const_data (str); + end = p + _dbus_string_get_length (str); + last_line_end = p; + while (p != end) + { + /* too lazy to handle \r\n as one linebreak */ + if (*p == '\n' || *p == '\r') + { + ++n_lines; + last_line_end = p + 1; + } + + prev = p; + ++p; + } + + if (last_line_end != p) + ++n_lines; + + return n_lines; +} + +static void +fill_line_content (const DBusString *str, + Line *lines) +{ + int n_lines; + const char *p; + const char *prev; + const char *end; + const char *last_line_end; + +#if 0 + printf ("Saving contents of each line in source file\n"); +#endif + + n_lines = 0; + prev = NULL; + p = _dbus_string_get_const_data (str); + end = p + _dbus_string_get_length (str); + last_line_end = p; + while (p != end) + { + if (*p == '\n' || *p == '\r') + { + lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1); + if (lines[n_lines].text == NULL) + die ("no memory\n"); + + memcpy (lines[n_lines].text, last_line_end, p - last_line_end); + lines[n_lines].number = n_lines + 1; + + ++n_lines; + + last_line_end = p + 1; + } + + prev = p; + ++p; + } + + if (p != last_line_end) + { + memcpy (lines[n_lines].text, last_line_end, p - last_line_end); + ++n_lines; + } +} + +static void +mark_inside_dbus_build_tests (File *f) +{ + int i; + DBusList *link; + int inside_depth; + + inside_depth = 0; + i = 0; + while (i < f->n_lines) + { + Line *l = &f->lines[i]; + dbus_bool_t is_verbose; + + is_verbose = strstr (l->text, "_dbus_verbose") != NULL; + + if (inside_depth == 0) + { + const char *a, *b; + + a = strstr (l->text, "#if"); + b = strstr (l->text, "DBUS_BUILD_TESTS"); + if (a && b && (a < b)) + inside_depth += 1; + } + else + { + if (strstr (l->text, "#if") != NULL) + inside_depth += 1; + else if (strstr (l->text, "#endif") != NULL) + inside_depth -= 1; + } + + if (inside_depth > 0 || is_verbose) + { + /* Mark the line and its blocks */ + DBusList *blink; + + l->inside_dbus_build_tests = TRUE; + + blink = _dbus_list_get_first_link (&l->blocks); + while (blink != NULL) + { + Block *b = blink->data; + + b->inside_dbus_build_tests = TRUE; + + blink = _dbus_list_get_next_link (&l->blocks, blink); + } + } + + ++i; + } + + /* Now mark functions where for all blocks that are associated + * with a source line, the block is inside_dbus_build_tests. + */ + link = _dbus_list_get_first_link (&f->functions); + while (link != NULL) + { + Function *func = link->data; + + /* The issue is that some blocks aren't associated with a source line. + * Assume they are inside/outside tests according to the source + * line of the preceding block. For the first block, make it + * match the first following block with a line associated. + */ + if (func->block_graph[0].lines == NULL) + { + /* find first following line */ + i = 1; + while (i < func->n_blocks) + { + if (func->block_graph[i].lines != NULL) + { + func->block_graph[0].inside_dbus_build_tests = + func->block_graph[i].inside_dbus_build_tests; + break; + } + + ++i; + } + } + + /* Now mark all blocks but the first */ + i = 1; + while (i < func->n_blocks) + { + if (func->block_graph[i].lines == NULL) + { + func->block_graph[i].inside_dbus_build_tests = + func->block_graph[i-1].inside_dbus_build_tests; + } + + ++i; + } + + i = 0; + while (i < func->n_blocks) + { + /* Break as soon as any block is not a test block */ + if (func->block_graph[i].lines != NULL && + !func->block_graph[i].inside_dbus_build_tests) + break; + + ++i; + } + + if (i == func->n_blocks) + func->inside_dbus_build_tests = TRUE; + + link = _dbus_list_get_next_link (&f->functions, link); + } +} + +static void +mark_coverage (File *f) +{ + int i; + DBusList *link; + + i = 0; + while (i < f->n_lines) + { + Line *l = &f->lines[i]; + DBusList *blink; + int n_blocks; + int n_blocks_executed; + + n_blocks = 0; + n_blocks_executed = 0; + blink = _dbus_list_get_first_link (&l->blocks); + while (blink != NULL) + { + Block *b = blink->data; + + if (b->exec_count > 0) + n_blocks_executed += 1; + + n_blocks += 1; + + blink = _dbus_list_get_next_link (&l->blocks, blink); + } + + if (n_blocks_executed > 0 && + n_blocks_executed < n_blocks) + l->partial = TRUE; + + ++i; + } + + link = _dbus_list_get_first_link (&f->functions); + while (link != NULL) + { + Function *func = link->data; + int i; + int n_test_blocks; + int n_test_blocks_executed; + int n_nontest_blocks; + int n_nontest_blocks_executed; + + n_test_blocks = 0; + n_test_blocks_executed = 0; + n_nontest_blocks = 0; + n_nontest_blocks_executed = 0; + + i = 0; + while (i < func->n_blocks) + { + if (!func->block_graph[i].inside_dbus_build_tests) + { + n_nontest_blocks += 1; + + if (func->block_graph[i].exec_count > 0) + n_nontest_blocks_executed += 1; + } + else + { + n_test_blocks += 1; + + if (func->block_graph[i].exec_count > 0) + n_test_blocks_executed += 1; + } + + ++i; + } + + if (n_nontest_blocks_executed > 0 && + n_nontest_blocks_executed < n_nontest_blocks) + func->partial = TRUE; + + if (n_nontest_blocks_executed == 0 && + n_nontest_blocks > 0) + func->unused = TRUE; + + func->n_test_blocks = n_test_blocks; + func->n_test_blocks_executed = n_test_blocks_executed; + func->n_nontest_blocks = n_nontest_blocks; + func->n_nontest_blocks_executed = n_nontest_blocks_executed; + + link = _dbus_list_get_next_link (&f->functions, link); + } +} + +static File* +load_c_file (const DBusString *filename) +{ + DBusString contents; + DBusError error; + File *f; + + f = dbus_new0 (File, 1); + if (f == NULL) + die ("no memory\n"); + + if (!_dbus_string_copy_data (filename, &f->name)) + die ("no memory\n"); + + if (!_dbus_string_init (&contents)) + die ("no memory\n"); + + dbus_error_init (&error); + + if (!_dbus_file_get_contents (&contents, filename, + &error)) + { + fprintf (stderr, "Could not open file: %s\n", + error.message); + dbus_error_free (&error); + exit (1); + } + + load_functions_for_c_file (filename, &f->functions); + + f->n_lines = count_lines_in_string (&contents); + f->lines = dbus_new0 (Line, f->n_lines); + if (f->lines == NULL) + die ("no memory\n"); + + fill_line_content (&contents, f->lines); + + _dbus_string_free (&contents); + + load_block_line_associations (filename, f); + + mark_inside_dbus_build_tests (f); + mark_coverage (f); + + return f; +} + +typedef struct Stats Stats; + +struct Stats +{ + int n_blocks; + int n_blocks_executed; + int n_blocks_inside_dbus_build_tests; + + int n_lines; /* lines that have blocks on them */ + int n_lines_executed; + int n_lines_partial; + int n_lines_inside_dbus_build_tests; + + int n_functions; + int n_functions_executed; + int n_functions_partial; + int n_functions_inside_dbus_build_tests; +}; + +static dbus_bool_t +line_was_executed (Line *l) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&l->blocks); + while (link != NULL) + { + Block *b = link->data; + + if (b->exec_count > 0) + return TRUE; + + link = _dbus_list_get_next_link (&l->blocks, link); + } + + return FALSE; +} + + +static int +line_exec_count (Line *l) +{ + DBusList *link; + dbus_int64_t total; + + total = 0; + link = _dbus_list_get_first_link (&l->blocks); + while (link != NULL) + { + Block *b = link->data; + + total += b->exec_count; + + link = _dbus_list_get_next_link (&l->blocks, link); + } + + return total; +} + +static void +merge_stats_for_file (Stats *stats, + File *f) +{ + int i; + DBusList *link; + + for (i = 0; i < f->n_lines; ++i) + { + Line *l = &f->lines[i]; + + if (l->inside_dbus_build_tests) + { + stats->n_lines_inside_dbus_build_tests += 1; + continue; + } + + if (line_was_executed (l)) + stats->n_lines_executed += 1; + + if (l->blocks != NULL) + stats->n_lines += 1; + + if (l->partial) + stats->n_lines_partial += 1; + } + + link = _dbus_list_get_first_link (&f->functions); + while (link != NULL) + { + Function *func = link->data; + + if (func->inside_dbus_build_tests) + stats->n_functions_inside_dbus_build_tests += 1; + else + { + stats->n_functions += 1; + + if (!func->unused) + stats->n_functions_executed += 1; + + if (func->partial) + stats->n_functions_partial += 1; + } + + stats->n_blocks_inside_dbus_build_tests += + func->n_test_blocks; + + stats->n_blocks_executed += + func->n_nontest_blocks_executed; + + stats->n_blocks += + func->n_nontest_blocks; + + link = _dbus_list_get_next_link (&f->functions, link); + } +} + +/* The output of this matches gcov exactly ("diff" shows no difference) */ +static void +print_annotated_source_gcov_format (File *f) +{ + int i; + + i = 0; + while (i < f->n_lines) + { + Line *l = &f->lines[i]; + + if (l->blocks != NULL) + { + int exec_count; + + exec_count = line_exec_count (l); + + if (exec_count > 0) + printf ("%12d %s\n", + exec_count, l->text); + else + printf (" ###### %s\n", l->text); + } + else + { + printf ("\t\t%s\n", l->text); + } + + ++i; + } +} + +static void +print_annotated_source (File *f) +{ + int i; + + i = 0; + while (i < f->n_lines) + { + Line *l = &f->lines[i]; + + if (l->inside_dbus_build_tests) + printf ("*"); + else + printf (" "); + + if (l->blocks != NULL) + { + int exec_count; + + exec_count = line_exec_count (l); + + if (exec_count > 0) + printf ("%12d %s\n", + exec_count, l->text); + else + printf (" ###### %s\n", l->text); + } + else + { + printf ("\t\t%s\n", l->text); + } + + ++i; + } +} + +static void +print_block_superdetails (File *f) +{ + DBusList *link; + int i; + + link = _dbus_list_get_first_link (&f->functions); + while (link != NULL) + { + Function *func = link->data; + + printf ("=== %s():\n", func->name); + + i = 0; + while (i < func->n_blocks) + { + Block *b = &func->block_graph[i]; + DBusList *l; + + printf (" %5d executed %d times%s\n", i, + (int) b->exec_count, + b->inside_dbus_build_tests ? + " [inside DBUS_BUILD_TESTS]" : ""); + + l = _dbus_list_get_first_link (&b->lines); + while (l != NULL) + { + Line *line = l->data; + + printf ("4%d\t%s\n", line->number, line->text); + + l = _dbus_list_get_next_link (&b->lines, l); + } + + ++i; + } + + link = _dbus_list_get_next_link (&f->functions, link); + } +} + +static void +print_one_file (const DBusString *filename) +{ + if (_dbus_string_ends_with_c_str (filename, ".bb")) + { + DBusString contents; + DBusError error; + + if (!_dbus_string_init (&contents)) + die ("no memory\n"); + + dbus_error_init (&error); + + if (!_dbus_file_get_contents (&contents, filename, + &error)) + { + fprintf (stderr, "Could not open file: %s\n", + error.message); + dbus_error_free (&error); + exit (1); + } + + dump_bb_file (&contents); + + _dbus_string_free (&contents); + } + else if (_dbus_string_ends_with_c_str (filename, ".bbg")) + { + DBusString contents; + DBusError error; + + if (!_dbus_string_init (&contents)) + die ("no memory\n"); + + dbus_error_init (&error); + + if (!_dbus_file_get_contents (&contents, filename, + &error)) + { + fprintf (stderr, "Could not open file: %s\n", + error.message); + dbus_error_free (&error); + exit (1); + } + + dump_bbg_file (&contents); + + _dbus_string_free (&contents); + } + else if (_dbus_string_ends_with_c_str (filename, ".da")) + { + DBusString contents; + DBusError error; + + if (!_dbus_string_init (&contents)) + die ("no memory\n"); + + dbus_error_init (&error); + + if (!_dbus_file_get_contents (&contents, filename, + &error)) + { + fprintf (stderr, "Could not open file: %s\n", + error.message); + dbus_error_free (&error); + exit (1); + } + + dump_da_file (&contents); + + _dbus_string_free (&contents); + } + else if (_dbus_string_ends_with_c_str (filename, ".c")) + { + File *f; + + f = load_c_file (filename); + + print_annotated_source (f); + } + else + { + fprintf (stderr, "Unknown file type %s\n", + _dbus_string_get_const_data (filename)); + exit (1); + } +} + +static void +print_untested_functions (File *f) +{ + DBusList *link; + dbus_bool_t found; + + found = FALSE; + link = _dbus_list_get_first_link (&f->functions); + while (link != NULL) + { + Function *func = link->data; + + if (func->unused && + !func->inside_dbus_build_tests) + found = TRUE; + + link = _dbus_list_get_next_link (&f->functions, link); + } + + if (!found) + return; + + printf ("Untested functions in %s\n", f->name); + printf ("=======\n"); + + link = _dbus_list_get_first_link (&f->functions); + while (link != NULL) + { + Function *func = link->data; + + if (func->unused && + !func->inside_dbus_build_tests) + printf (" %s\n", func->name); + + link = _dbus_list_get_next_link (&f->functions, link); + } + + printf ("\n"); +} + +static void +print_poorly_tested_functions (File *f, + Stats *stats) +{ + DBusList *link; + dbus_bool_t found; + +#define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks) + +#define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks) + +#define POORLY_TESTED(function) (!(function)->unused && \ + (function)->n_nontest_blocks > 0 && \ + TEST_FRACTION (function) < AVERAGE_COVERAGE) + + found = FALSE; + link = _dbus_list_get_first_link (&f->functions); + while (link != NULL) + { + Function *func = link->data; + + if (POORLY_TESTED (func)) + found = TRUE; + + link = _dbus_list_get_next_link (&f->functions, link); + } + + if (!found) + return; + + printf ("Below average functions in %s\n", f->name); + printf ("=======\n"); + + link = _dbus_list_get_first_link (&f->functions); + while (link != NULL) + { + Function *func = link->data; + + if (POORLY_TESTED (func)) + printf (" %s (%d%%)\n", func->name, + (int) (TEST_FRACTION (func) * 100)); + + link = _dbus_list_get_next_link (&f->functions, link); + } + + printf ("\n"); +} + +static int +func_cmp (const void *a, + const void *b) +{ + Function *af = *(Function**) a; + Function *bf = *(Function**) b; + int a_untested = af->n_nontest_blocks - af->n_nontest_blocks_executed; + int b_untested = bf->n_nontest_blocks - bf->n_nontest_blocks_executed; + + /* Sort by number of untested blocks */ + return b_untested - a_untested; +} + +static void +print_n_untested_blocks_by_function (File *f, + Stats *stats) +{ + DBusList *link; + Function **funcs; + int n_found; + int i; + + n_found = 0; + link = _dbus_list_get_first_link (&f->functions); + while (link != NULL) + { + Function *func = link->data; + + if (func->n_nontest_blocks_executed < + func->n_nontest_blocks) + n_found += 1; + + link = _dbus_list_get_next_link (&f->functions, link); + } + + if (n_found == 0) + return; + + /* make an array so we can use qsort */ + + funcs = dbus_new (Function*, n_found); + if (funcs == NULL) + return; + + i = 0; + link = _dbus_list_get_first_link (&f->functions); + while (link != NULL) + { + Function *func = link->data; + + if (func->n_nontest_blocks_executed < + func->n_nontest_blocks) + { + funcs[i] = func; + ++i; + } + + link = _dbus_list_get_next_link (&f->functions, link); + } + + _dbus_assert (i == n_found); + + qsort (funcs, n_found, sizeof (Function*), + func_cmp); + + printf ("Incomplete functions in %s\n", f->name); + printf ("=======\n"); + + i = 0; + while (i < n_found) + { + Function *func = funcs[i]; + + printf (" %s (%d/%d untested blocks)\n", + func->name, + func->n_nontest_blocks - func->n_nontest_blocks_executed, + func->n_nontest_blocks); + + ++i; + } + + dbus_free (funcs); + + printf ("\n"); +} + +static void +print_stats (Stats *stats, + const char *of_what) +{ + int completely; + + printf ("Summary (%s)\n", of_what); + printf ("=======\n"); + printf (" %g%% blocks executed (%d of %d)\n", + (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0, + stats->n_blocks_executed, + stats->n_blocks); + + printf (" (ignored %d blocks of test-only/debug-only code)\n", + stats->n_blocks_inside_dbus_build_tests); + + printf (" %g%% functions executed (%d of %d)\n", + (stats->n_functions_executed / (double) stats->n_functions) * 100.0, + stats->n_functions_executed, + stats->n_functions); + + completely = stats->n_functions_executed - stats->n_functions_partial; + printf (" %g%% functions completely executed (%d of %d)\n", + (completely / (double) stats->n_functions) * 100.0, + completely, + stats->n_functions); + + printf (" (ignored %d functions of test-only/debug-only code)\n", + stats->n_functions_inside_dbus_build_tests); + + printf (" %g%% lines executed (%d of %d)\n", + (stats->n_lines_executed / (double) stats->n_lines) * 100.0, + stats->n_lines_executed, + stats->n_lines); + + completely = stats->n_lines_executed - stats->n_lines_partial; + printf (" %g%% lines completely executed (%d of %d)\n", + (completely / (double) stats->n_lines) * 100.0, + completely, + stats->n_lines); + + printf (" (ignored %d lines of test-only/debug-only code)\n", + stats->n_lines_inside_dbus_build_tests); + + printf ("\n"); +} + +typedef enum +{ + MODE_PRINT, + MODE_REPORT, + MODE_BLOCKS, + MODE_GCOV +} Mode; + +int +main (int argc, char **argv) +{ + DBusString filename; + int i; + Mode m; + + if (argc < 2) + { + fprintf (stderr, "Must specify files on command line\n"); + return 1; + } + + m = MODE_PRINT; + i = 1; + + if (strcmp (argv[i], "--report") == 0) + { + m = MODE_REPORT; + ++i; + } + else if (strcmp (argv[i], "--blocks") == 0) + { + m = MODE_BLOCKS; + ++i; + } + else if (strcmp (argv[i], "--gcov") == 0) + { + m = MODE_GCOV; + ++i; + } + + + if (i == argc) + { + fprintf (stderr, "Must specify files on command line\n"); + return 1; + } + + if (m == MODE_PRINT) + { + while (i < argc) + { + _dbus_string_init_const (&filename, argv[i]); + + print_one_file (&filename); + + ++i; + } + } + else if (m == MODE_BLOCKS || m == MODE_GCOV) + { + while (i < argc) + { + File *f; + + _dbus_string_init_const (&filename, argv[i]); + + f = load_c_file (&filename); + + if (m == MODE_BLOCKS) + print_block_superdetails (f); + else if (m == MODE_GCOV) + print_annotated_source_gcov_format (f); + + ++i; + } + } + else if (m == MODE_REPORT) + { + Stats stats = { 0, }; + DBusList *files; + DBusList *link; + DBusHashTable *stats_by_dir; + DBusHashIter iter; + + files = NULL; + while (i < argc) + { + _dbus_string_init_const (&filename, argv[i]); + + if (_dbus_string_ends_with_c_str (&filename, ".c")) + { + File *f; + + f = load_c_file (&filename); + + if (!_dbus_list_append (&files, f)) + die ("no memory\n"); + } + else + { + fprintf (stderr, "Unknown file type %s\n", + _dbus_string_get_const_data (&filename)); + exit (1); + } + + ++i; + } + + link = _dbus_list_get_first_link (&files); + while (link != NULL) + { + File *f = link->data; + + merge_stats_for_file (&stats, f); + + link = _dbus_list_get_next_link (&files, link); + } + + print_stats (&stats, "all files"); + + stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING, + dbus_free, dbus_free); + + link = _dbus_list_get_first_link (&files); + while (link != NULL) + { + File *f = link->data; + DBusString dirname; + char *dirname_c; + Stats *dir_stats; + + _dbus_string_init_const (&filename, f->name); + + if (!_dbus_string_init (&dirname)) + die ("no memory\n"); + + if (!_dbus_string_get_dirname (&filename, &dirname) || + !_dbus_string_copy_data (&dirname, &dirname_c)) + die ("no memory\n"); + + dir_stats = _dbus_hash_table_lookup_string (stats_by_dir, + dirname_c); + + if (dir_stats == NULL) + { + dir_stats = dbus_new0 (Stats, 1); + if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c, + dir_stats)) + die ("no memory\n"); + } + else + dbus_free (dirname_c); + + merge_stats_for_file (dir_stats, f); + + link = _dbus_list_get_next_link (&files, link); + } + + _dbus_hash_iter_init (stats_by_dir, &iter); + while (_dbus_hash_iter_next (&iter)) + { + const char *dirname = _dbus_hash_iter_get_string_key (&iter); + Stats *dir_stats = _dbus_hash_iter_get_value (&iter); + + print_stats (dir_stats, dirname); + } + + _dbus_hash_table_unref (stats_by_dir); + + link = _dbus_list_get_first_link (&files); + while (link != NULL) + { + File *f = link->data; + + print_untested_functions (f); + + link = _dbus_list_get_next_link (&files, link); + } + + link = _dbus_list_get_first_link (&files); + while (link != NULL) + { + File *f = link->data; + + print_poorly_tested_functions (f, &stats); + + link = _dbus_list_get_next_link (&files, link); + } + + link = _dbus_list_get_first_link (&files); + while (link != NULL) + { + File *f = link->data; + + print_n_untested_blocks_by_function (f, &stats); + + link = _dbus_list_get_next_link (&files, link); + } + } + + return 0; +} diff --git a/test/name-test/Makefile.am b/test/name-test/Makefile.am new file mode 100644 index 00000000..9a508a12 --- /dev/null +++ b/test/name-test/Makefile.am @@ -0,0 +1,66 @@ +INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_TEST_CFLAGS) -DDBUS_COMPILATION + +## note that TESTS has special meaning (stuff to use in make check) +## so if adding tests not to be run in make check, don't add them to +## TESTS +if DBUS_BUILD_TESTS +TESTS_ENVIRONMENT=DBUS_TOP_BUILDDIR=@abs_top_builddir@ DBUS_TOP_SRCDIR=@abs_top_srcdir@ +TESTS=run-test.sh run-test-systemserver.sh +else +TESTS= +endif + +EXTRA_DIST=run-test.sh run-test-systemserver.sh test-wait-for-echo.py test-activation-forking.py + +if DBUS_BUILD_TESTS + +## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we +## build even when not doing "make check" +noinst_PROGRAMS=test-pending-call-dispatch test-pending-call-timeout test-threads-init test-ids test-shutdown test-privserver test-privserver-client + +test_pending_call_dispatch_SOURCES = \ + test-pending-call-dispatch.c + +test_pending_call_dispatch_LDADD=$(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS) +test_pending_call_dispatch_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +test_pending_call_timeout_SOURCES = \ + test-pending-call-timeout.c + +test_pending_call_timeout_LDADD=$(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS) +test_pending_call_timeout_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +test_threads_init_SOURCES = \ + test-threads-init.c + +test_threads_init_LDADD=$(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS) +test_threads_init_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +test_ids_SOURCES = \ + test-ids.c + +test_ids_LDADD=$(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS) +test_ids_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +test_shutdown_SOURCES = \ + test-shutdown.c + +test_shutdown_CFLAGS= +test_shutdown_LDADD=$(top_builddir)/dbus/libdbus-convenience.la ../libdbus-testutils.la $(DBUS_TEST_LIBS) +test_shutdown_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +test_privserver_SOURCES = \ + test-privserver.c + +test_privserver_CFLAGS= +test_privserver_LDADD=$(top_builddir)/dbus/libdbus-convenience.la ../libdbus-testutils.la $(DBUS_TEST_LIBS) +test_privserver_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +test_privserver_client_SOURCES = \ + test-privserver-client.c + +test_privserver_client_CFLAGS= +test_privserver_client_LDADD=$(top_builddir)/dbus/libdbus-convenience.la ../libdbus-testutils.la $(DBUS_TEST_LIBS) +test_privserver_client_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +endif diff --git a/test/name-test/Makefile.in b/test/name-test/Makefile.in new file mode 100644 index 00000000..077ab22e --- /dev/null +++ b/test/name-test/Makefile.in @@ -0,0 +1,857 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@DBUS_BUILD_TESTS_TRUE@TESTS = run-test.sh run-test-systemserver.sh +@DBUS_BUILD_TESTS_TRUE@noinst_PROGRAMS = \ +@DBUS_BUILD_TESTS_TRUE@ test-pending-call-dispatch$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ test-pending-call-timeout$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ test-threads-init$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ test-ids$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ test-shutdown$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ test-privserver$(EXEEXT) \ +@DBUS_BUILD_TESTS_TRUE@ test-privserver-client$(EXEEXT) +subdir = test/name-test +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +PROGRAMS = $(noinst_PROGRAMS) +am__test_ids_SOURCES_DIST = test-ids.c +@DBUS_BUILD_TESTS_TRUE@am_test_ids_OBJECTS = test-ids.$(OBJEXT) +test_ids_OBJECTS = $(am_test_ids_OBJECTS) +am__DEPENDENCIES_1 = +@DBUS_BUILD_TESTS_TRUE@test_ids_DEPENDENCIES = $(top_builddir)/dbus/libdbus-convenience.la \ +@DBUS_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +test_ids_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(test_ids_LDFLAGS) $(LDFLAGS) -o $@ +am__test_pending_call_dispatch_SOURCES_DIST = \ + test-pending-call-dispatch.c +@DBUS_BUILD_TESTS_TRUE@am_test_pending_call_dispatch_OBJECTS = \ +@DBUS_BUILD_TESTS_TRUE@ test-pending-call-dispatch.$(OBJEXT) +test_pending_call_dispatch_OBJECTS = \ + $(am_test_pending_call_dispatch_OBJECTS) +@DBUS_BUILD_TESTS_TRUE@test_pending_call_dispatch_DEPENDENCIES = $(top_builddir)/dbus/libdbus-convenience.la \ +@DBUS_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) +test_pending_call_dispatch_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(test_pending_call_dispatch_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__test_pending_call_timeout_SOURCES_DIST = \ + test-pending-call-timeout.c +@DBUS_BUILD_TESTS_TRUE@am_test_pending_call_timeout_OBJECTS = \ +@DBUS_BUILD_TESTS_TRUE@ test-pending-call-timeout.$(OBJEXT) +test_pending_call_timeout_OBJECTS = \ + $(am_test_pending_call_timeout_OBJECTS) +@DBUS_BUILD_TESTS_TRUE@test_pending_call_timeout_DEPENDENCIES = $(top_builddir)/dbus/libdbus-convenience.la \ +@DBUS_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) +test_pending_call_timeout_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(test_pending_call_timeout_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__test_privserver_SOURCES_DIST = test-privserver.c +@DBUS_BUILD_TESTS_TRUE@am_test_privserver_OBJECTS = test_privserver-test-privserver.$(OBJEXT) +test_privserver_OBJECTS = $(am_test_privserver_OBJECTS) +@DBUS_BUILD_TESTS_TRUE@test_privserver_DEPENDENCIES = $(top_builddir)/dbus/libdbus-convenience.la \ +@DBUS_BUILD_TESTS_TRUE@ ../libdbus-testutils.la \ +@DBUS_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) +test_privserver_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(test_privserver_CFLAGS) $(CFLAGS) $(test_privserver_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__test_privserver_client_SOURCES_DIST = test-privserver-client.c +@DBUS_BUILD_TESTS_TRUE@am_test_privserver_client_OBJECTS = test_privserver_client-test-privserver-client.$(OBJEXT) +test_privserver_client_OBJECTS = $(am_test_privserver_client_OBJECTS) +@DBUS_BUILD_TESTS_TRUE@test_privserver_client_DEPENDENCIES = $(top_builddir)/dbus/libdbus-convenience.la \ +@DBUS_BUILD_TESTS_TRUE@ ../libdbus-testutils.la \ +@DBUS_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) +test_privserver_client_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(test_privserver_client_CFLAGS) $(CFLAGS) \ + $(test_privserver_client_LDFLAGS) $(LDFLAGS) -o $@ +am__test_shutdown_SOURCES_DIST = test-shutdown.c +@DBUS_BUILD_TESTS_TRUE@am_test_shutdown_OBJECTS = \ +@DBUS_BUILD_TESTS_TRUE@ test_shutdown-test-shutdown.$(OBJEXT) +test_shutdown_OBJECTS = $(am_test_shutdown_OBJECTS) +@DBUS_BUILD_TESTS_TRUE@test_shutdown_DEPENDENCIES = $(top_builddir)/dbus/libdbus-convenience.la \ +@DBUS_BUILD_TESTS_TRUE@ ../libdbus-testutils.la \ +@DBUS_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) +test_shutdown_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(test_shutdown_CFLAGS) \ + $(CFLAGS) $(test_shutdown_LDFLAGS) $(LDFLAGS) -o $@ +am__test_threads_init_SOURCES_DIST = test-threads-init.c +@DBUS_BUILD_TESTS_TRUE@am_test_threads_init_OBJECTS = \ +@DBUS_BUILD_TESTS_TRUE@ test-threads-init.$(OBJEXT) +test_threads_init_OBJECTS = $(am_test_threads_init_OBJECTS) +@DBUS_BUILD_TESTS_TRUE@test_threads_init_DEPENDENCIES = $(top_builddir)/dbus/libdbus-convenience.la \ +@DBUS_BUILD_TESTS_TRUE@ $(am__DEPENDENCIES_1) +test_threads_init_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(test_threads_init_LDFLAGS) $(LDFLAGS) \ + -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(test_ids_SOURCES) $(test_pending_call_dispatch_SOURCES) \ + $(test_pending_call_timeout_SOURCES) \ + $(test_privserver_SOURCES) $(test_privserver_client_SOURCES) \ + $(test_shutdown_SOURCES) $(test_threads_init_SOURCES) +DIST_SOURCES = $(am__test_ids_SOURCES_DIST) \ + $(am__test_pending_call_dispatch_SOURCES_DIST) \ + $(am__test_pending_call_timeout_SOURCES_DIST) \ + $(am__test_privserver_SOURCES_DIST) \ + $(am__test_privserver_client_SOURCES_DIST) \ + $(am__test_shutdown_SOURCES_DIST) \ + $(am__test_threads_init_SOURCES_DIST) +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DBUS_BINDIR = @DBUS_BINDIR@ +DBUS_BUS_CFLAGS = @DBUS_BUS_CFLAGS@ +DBUS_BUS_LIBS = @DBUS_BUS_LIBS@ +DBUS_CLIENT_CFLAGS = @DBUS_CLIENT_CFLAGS@ +DBUS_CLIENT_LIBS = @DBUS_CLIENT_LIBS@ +DBUS_CONSOLE_AUTH_DIR = @DBUS_CONSOLE_AUTH_DIR@ +DBUS_CONSOLE_OWNER_FILE = @DBUS_CONSOLE_OWNER_FILE@ +DBUS_DAEMONDIR = @DBUS_DAEMONDIR@ +DBUS_DATADIR = @DBUS_DATADIR@ +DBUS_HAVE_INT64 = @DBUS_HAVE_INT64@ +DBUS_INT16_TYPE = @DBUS_INT16_TYPE@ +DBUS_INT32_TYPE = @DBUS_INT32_TYPE@ +DBUS_INT64_CONSTANT = @DBUS_INT64_CONSTANT@ +DBUS_INT64_TYPE = @DBUS_INT64_TYPE@ +DBUS_LAUNCHER_CFLAGS = @DBUS_LAUNCHER_CFLAGS@ +DBUS_LAUNCHER_LIBS = @DBUS_LAUNCHER_LIBS@ +DBUS_LIBEXECDIR = @DBUS_LIBEXECDIR@ +DBUS_MAJOR_VERSION = @DBUS_MAJOR_VERSION@ +DBUS_MICRO_VERSION = @DBUS_MICRO_VERSION@ +DBUS_MINOR_VERSION = @DBUS_MINOR_VERSION@ +DBUS_PATH_OR_ABSTRACT = @DBUS_PATH_OR_ABSTRACT@ +DBUS_SESSION_SOCKET_DIR = @DBUS_SESSION_SOCKET_DIR@ +DBUS_SYSTEM_BUS_DEFAULT_ADDRESS = @DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ +DBUS_SYSTEM_PID_FILE = @DBUS_SYSTEM_PID_FILE@ +DBUS_SYSTEM_SOCKET = @DBUS_SYSTEM_SOCKET@ +DBUS_TEST_CFLAGS = @DBUS_TEST_CFLAGS@ +DBUS_TEST_LIBS = @DBUS_TEST_LIBS@ +DBUS_UINT64_CONSTANT = @DBUS_UINT64_CONSTANT@ +DBUS_USER = @DBUS_USER@ +DBUS_VERSION = @DBUS_VERSION@ +DBUS_X_CFLAGS = @DBUS_X_CFLAGS@ +DBUS_X_LIBS = @DBUS_X_LIBS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPANDED_BINDIR = @EXPANDED_BINDIR@ +EXPANDED_DATADIR = @EXPANDED_DATADIR@ +EXPANDED_LIBDIR = @EXPANDED_LIBDIR@ +EXPANDED_LIBEXECDIR = @EXPANDED_LIBEXECDIR@ +EXPANDED_LOCALSTATEDIR = @EXPANDED_LOCALSTATEDIR@ +EXPANDED_SYSCONFDIR = @EXPANDED_SYSCONFDIR@ +FGREP = @FGREP@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML_CFLAGS = @LIBXML_CFLAGS@ +LIBXML_LIBS = @LIBXML_LIBS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_AGE = @LT_AGE@ +LT_CURRENT = @LT_CURRENT@ +LT_REVISION = @LT_REVISION@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIC_CFLAGS = @PIC_CFLAGS@ +PIC_LDFLAGS = @PIC_LDFLAGS@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +R_DYNAMIC_LDFLAG = @R_DYNAMIC_LDFLAG@ +SECTION_FLAGS = @SECTION_FLAGS@ +SECTION_LDFLAGS = @SECTION_LDFLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TEST_BUS_BINARY = @TEST_BUS_BINARY@ +TEST_EXIT_BINARY = @TEST_EXIT_BINARY@ +TEST_INVALID_SERVICE_DIR = @TEST_INVALID_SERVICE_DIR@ +TEST_INVALID_SERVICE_SYSTEM_DIR = @TEST_INVALID_SERVICE_SYSTEM_DIR@ +TEST_LAUNCH_HELPER_BINARY = @TEST_LAUNCH_HELPER_BINARY@ +TEST_PRIVSERVER_BINARY = @TEST_PRIVSERVER_BINARY@ +TEST_SEGFAULT_BINARY = @TEST_SEGFAULT_BINARY@ +TEST_SERVICE_BINARY = @TEST_SERVICE_BINARY@ +TEST_SHELL_SERVICE_BINARY = @TEST_SHELL_SERVICE_BINARY@ +TEST_SLEEP_FOREVER_BINARY = @TEST_SLEEP_FOREVER_BINARY@ +TEST_SOCKET_DIR = @TEST_SOCKET_DIR@ +TEST_VALID_SERVICE_DIR = @TEST_VALID_SERVICE_DIR@ +TEST_VALID_SERVICE_SYSTEM_DIR = @TEST_VALID_SERVICE_SYSTEM_DIR@ +VERSION = @VERSION@ +XMKMF = @XMKMF@ +XMLTO = @XMLTO@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_TEST_CFLAGS) -DDBUS_COMPILATION +@DBUS_BUILD_TESTS_TRUE@TESTS_ENVIRONMENT = DBUS_TOP_BUILDDIR=@abs_top_builddir@ DBUS_TOP_SRCDIR=@abs_top_srcdir@ +EXTRA_DIST = run-test.sh run-test-systemserver.sh test-wait-for-echo.py test-activation-forking.py +@DBUS_BUILD_TESTS_TRUE@test_pending_call_dispatch_SOURCES = \ +@DBUS_BUILD_TESTS_TRUE@ test-pending-call-dispatch.c + +@DBUS_BUILD_TESTS_TRUE@test_pending_call_dispatch_LDADD = $(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS) +@DBUS_BUILD_TESTS_TRUE@test_pending_call_dispatch_LDFLAGS = @R_DYNAMIC_LDFLAG@ +@DBUS_BUILD_TESTS_TRUE@test_pending_call_timeout_SOURCES = \ +@DBUS_BUILD_TESTS_TRUE@ test-pending-call-timeout.c + +@DBUS_BUILD_TESTS_TRUE@test_pending_call_timeout_LDADD = $(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS) +@DBUS_BUILD_TESTS_TRUE@test_pending_call_timeout_LDFLAGS = @R_DYNAMIC_LDFLAG@ +@DBUS_BUILD_TESTS_TRUE@test_threads_init_SOURCES = \ +@DBUS_BUILD_TESTS_TRUE@ test-threads-init.c + +@DBUS_BUILD_TESTS_TRUE@test_threads_init_LDADD = $(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS) +@DBUS_BUILD_TESTS_TRUE@test_threads_init_LDFLAGS = @R_DYNAMIC_LDFLAG@ +@DBUS_BUILD_TESTS_TRUE@test_ids_SOURCES = \ +@DBUS_BUILD_TESTS_TRUE@ test-ids.c + +@DBUS_BUILD_TESTS_TRUE@test_ids_LDADD = $(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS) +@DBUS_BUILD_TESTS_TRUE@test_ids_LDFLAGS = @R_DYNAMIC_LDFLAG@ +@DBUS_BUILD_TESTS_TRUE@test_shutdown_SOURCES = \ +@DBUS_BUILD_TESTS_TRUE@ test-shutdown.c + +@DBUS_BUILD_TESTS_TRUE@test_shutdown_CFLAGS = +@DBUS_BUILD_TESTS_TRUE@test_shutdown_LDADD = $(top_builddir)/dbus/libdbus-convenience.la ../libdbus-testutils.la $(DBUS_TEST_LIBS) +@DBUS_BUILD_TESTS_TRUE@test_shutdown_LDFLAGS = @R_DYNAMIC_LDFLAG@ +@DBUS_BUILD_TESTS_TRUE@test_privserver_SOURCES = \ +@DBUS_BUILD_TESTS_TRUE@ test-privserver.c + +@DBUS_BUILD_TESTS_TRUE@test_privserver_CFLAGS = +@DBUS_BUILD_TESTS_TRUE@test_privserver_LDADD = $(top_builddir)/dbus/libdbus-convenience.la ../libdbus-testutils.la $(DBUS_TEST_LIBS) +@DBUS_BUILD_TESTS_TRUE@test_privserver_LDFLAGS = @R_DYNAMIC_LDFLAG@ +@DBUS_BUILD_TESTS_TRUE@test_privserver_client_SOURCES = \ +@DBUS_BUILD_TESTS_TRUE@ test-privserver-client.c + +@DBUS_BUILD_TESTS_TRUE@test_privserver_client_CFLAGS = +@DBUS_BUILD_TESTS_TRUE@test_privserver_client_LDADD = $(top_builddir)/dbus/libdbus-convenience.la ../libdbus-testutils.la $(DBUS_TEST_LIBS) +@DBUS_BUILD_TESTS_TRUE@test_privserver_client_LDFLAGS = @R_DYNAMIC_LDFLAG@ +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/name-test/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu test/name-test/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +test-ids$(EXEEXT): $(test_ids_OBJECTS) $(test_ids_DEPENDENCIES) + @rm -f test-ids$(EXEEXT) + $(AM_V_CCLD)$(test_ids_LINK) $(test_ids_OBJECTS) $(test_ids_LDADD) $(LIBS) +test-pending-call-dispatch$(EXEEXT): $(test_pending_call_dispatch_OBJECTS) $(test_pending_call_dispatch_DEPENDENCIES) + @rm -f test-pending-call-dispatch$(EXEEXT) + $(AM_V_CCLD)$(test_pending_call_dispatch_LINK) $(test_pending_call_dispatch_OBJECTS) $(test_pending_call_dispatch_LDADD) $(LIBS) +test-pending-call-timeout$(EXEEXT): $(test_pending_call_timeout_OBJECTS) $(test_pending_call_timeout_DEPENDENCIES) + @rm -f test-pending-call-timeout$(EXEEXT) + $(AM_V_CCLD)$(test_pending_call_timeout_LINK) $(test_pending_call_timeout_OBJECTS) $(test_pending_call_timeout_LDADD) $(LIBS) +test-privserver$(EXEEXT): $(test_privserver_OBJECTS) $(test_privserver_DEPENDENCIES) + @rm -f test-privserver$(EXEEXT) + $(AM_V_CCLD)$(test_privserver_LINK) $(test_privserver_OBJECTS) $(test_privserver_LDADD) $(LIBS) +test-privserver-client$(EXEEXT): $(test_privserver_client_OBJECTS) $(test_privserver_client_DEPENDENCIES) + @rm -f test-privserver-client$(EXEEXT) + $(AM_V_CCLD)$(test_privserver_client_LINK) $(test_privserver_client_OBJECTS) $(test_privserver_client_LDADD) $(LIBS) +test-shutdown$(EXEEXT): $(test_shutdown_OBJECTS) $(test_shutdown_DEPENDENCIES) + @rm -f test-shutdown$(EXEEXT) + $(AM_V_CCLD)$(test_shutdown_LINK) $(test_shutdown_OBJECTS) $(test_shutdown_LDADD) $(LIBS) +test-threads-init$(EXEEXT): $(test_threads_init_OBJECTS) $(test_threads_init_DEPENDENCIES) + @rm -f test-threads-init$(EXEEXT) + $(AM_V_CCLD)$(test_threads_init_LINK) $(test_threads_init_OBJECTS) $(test_threads_init_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-ids.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-pending-call-dispatch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-pending-call-timeout.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-threads-init.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_privserver-test-privserver.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_privserver_client-test-privserver-client.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_shutdown-test-shutdown.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +test_privserver-test-privserver.o: test-privserver.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_privserver_CFLAGS) $(CFLAGS) -MT test_privserver-test-privserver.o -MD -MP -MF $(DEPDIR)/test_privserver-test-privserver.Tpo -c -o test_privserver-test-privserver.o `test -f 'test-privserver.c' || echo '$(srcdir)/'`test-privserver.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_privserver-test-privserver.Tpo $(DEPDIR)/test_privserver-test-privserver.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-privserver.c' object='test_privserver-test-privserver.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_privserver_CFLAGS) $(CFLAGS) -c -o test_privserver-test-privserver.o `test -f 'test-privserver.c' || echo '$(srcdir)/'`test-privserver.c + +test_privserver-test-privserver.obj: test-privserver.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_privserver_CFLAGS) $(CFLAGS) -MT test_privserver-test-privserver.obj -MD -MP -MF $(DEPDIR)/test_privserver-test-privserver.Tpo -c -o test_privserver-test-privserver.obj `if test -f 'test-privserver.c'; then $(CYGPATH_W) 'test-privserver.c'; else $(CYGPATH_W) '$(srcdir)/test-privserver.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_privserver-test-privserver.Tpo $(DEPDIR)/test_privserver-test-privserver.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-privserver.c' object='test_privserver-test-privserver.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_privserver_CFLAGS) $(CFLAGS) -c -o test_privserver-test-privserver.obj `if test -f 'test-privserver.c'; then $(CYGPATH_W) 'test-privserver.c'; else $(CYGPATH_W) '$(srcdir)/test-privserver.c'; fi` + +test_privserver_client-test-privserver-client.o: test-privserver-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_privserver_client_CFLAGS) $(CFLAGS) -MT test_privserver_client-test-privserver-client.o -MD -MP -MF $(DEPDIR)/test_privserver_client-test-privserver-client.Tpo -c -o test_privserver_client-test-privserver-client.o `test -f 'test-privserver-client.c' || echo '$(srcdir)/'`test-privserver-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_privserver_client-test-privserver-client.Tpo $(DEPDIR)/test_privserver_client-test-privserver-client.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-privserver-client.c' object='test_privserver_client-test-privserver-client.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_privserver_client_CFLAGS) $(CFLAGS) -c -o test_privserver_client-test-privserver-client.o `test -f 'test-privserver-client.c' || echo '$(srcdir)/'`test-privserver-client.c + +test_privserver_client-test-privserver-client.obj: test-privserver-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_privserver_client_CFLAGS) $(CFLAGS) -MT test_privserver_client-test-privserver-client.obj -MD -MP -MF $(DEPDIR)/test_privserver_client-test-privserver-client.Tpo -c -o test_privserver_client-test-privserver-client.obj `if test -f 'test-privserver-client.c'; then $(CYGPATH_W) 'test-privserver-client.c'; else $(CYGPATH_W) '$(srcdir)/test-privserver-client.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_privserver_client-test-privserver-client.Tpo $(DEPDIR)/test_privserver_client-test-privserver-client.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-privserver-client.c' object='test_privserver_client-test-privserver-client.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_privserver_client_CFLAGS) $(CFLAGS) -c -o test_privserver_client-test-privserver-client.obj `if test -f 'test-privserver-client.c'; then $(CYGPATH_W) 'test-privserver-client.c'; else $(CYGPATH_W) '$(srcdir)/test-privserver-client.c'; fi` + +test_shutdown-test-shutdown.o: test-shutdown.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_shutdown_CFLAGS) $(CFLAGS) -MT test_shutdown-test-shutdown.o -MD -MP -MF $(DEPDIR)/test_shutdown-test-shutdown.Tpo -c -o test_shutdown-test-shutdown.o `test -f 'test-shutdown.c' || echo '$(srcdir)/'`test-shutdown.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_shutdown-test-shutdown.Tpo $(DEPDIR)/test_shutdown-test-shutdown.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-shutdown.c' object='test_shutdown-test-shutdown.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_shutdown_CFLAGS) $(CFLAGS) -c -o test_shutdown-test-shutdown.o `test -f 'test-shutdown.c' || echo '$(srcdir)/'`test-shutdown.c + +test_shutdown-test-shutdown.obj: test-shutdown.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_shutdown_CFLAGS) $(CFLAGS) -MT test_shutdown-test-shutdown.obj -MD -MP -MF $(DEPDIR)/test_shutdown-test-shutdown.Tpo -c -o test_shutdown-test-shutdown.obj `if test -f 'test-shutdown.c'; then $(CYGPATH_W) 'test-shutdown.c'; else $(CYGPATH_W) '$(srcdir)/test-shutdown.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_shutdown-test-shutdown.Tpo $(DEPDIR)/test_shutdown-test-shutdown.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-shutdown.c' object='test_shutdown-test-shutdown.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(test_shutdown_CFLAGS) $(CFLAGS) -c -o test_shutdown-test-shutdown.obj `if test -f 'test-shutdown.c'; then $(CYGPATH_W) 'test-shutdown.c'; else $(CYGPATH_W) '$(srcdir)/test-shutdown.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + echo "$$grn$$dashes"; \ + else \ + echo "$$red$$dashes"; \ + fi; \ + echo "$$banner"; \ + test -z "$$skipped" || echo "$$skipped"; \ + test -z "$$report" || echo "$$report"; \ + echo "$$dashes$$std"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-generic clean-libtool clean-noinstPROGRAMS ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/test/name-test/run-test-systemserver.sh b/test/name-test/run-test-systemserver.sh new file mode 100755 index 00000000..34dd6487 --- /dev/null +++ b/test/name-test/run-test-systemserver.sh @@ -0,0 +1,50 @@ +#! /bin/sh +die() +{ + if ! test -z "$DBUS_SESSION_BUS_PID" ; then + echo "killing message bus "$DBUS_SESSION_BUS_PID >&2 + kill -9 $DBUS_SESSION_BUS_PID + fi + echo $SCRIPTNAME: $* >&2 + + exit 1 +} + +SCRIPTNAME=$0 +MODE=$1 + +## so the tests can complain if you fail to use the script to launch them +DBUS_TEST_NAME_RUN_TEST_SCRIPT=1 +export DBUS_TEST_NAME_RUN_TEST_SCRIPT + +SOURCE_CONFIG_FILE=$DBUS_TOP_SRCDIR/test/name-test/tmp-session-like-system.conf +export SOURCE_CONFIG_FILE +# Rerun ourselves with tmp session bus if we're not already +if test -z "$DBUS_TEST_NAME_IN_SYS_RUN_TEST"; then + DBUS_TEST_NAME_IN_SYS_RUN_TEST=1 + export DBUS_TEST_NAME_IN_SYS_RUN_TEST + exec $DBUS_TOP_SRCDIR/tools/run-with-tmp-session-bus.sh $SCRIPTNAME $MODE +fi + +if test -n "$DBUS_TEST_MONITOR"; then + dbus-monitor --session & +fi + +echo "running test-expected-echo-fail" +${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/tools/dbus-send --print-reply --dest=org.freedesktop.DBus.TestSuiteEchoService /org/freedesktop/TestSuite org.freedesktop.TestSuite.Echo string:hi >echo-error-output.tmp 2>&1 +if ! grep -q 'DBus.Error' echo-error-output.tmp; then + echo "Didn't get expected failure; output was:" + echo "=====" + cat echo-error-output.tmp + echo "=====" + exit 1 +fi + +echo "running test echo signal" +if ! python ./test-wait-for-echo.py; then + echo "Failed test-wait-for-echo" + exit 1 +fi + + +exit 0 diff --git a/test/name-test/run-test.sh b/test/name-test/run-test.sh new file mode 100755 index 00000000..832ce0a5 --- /dev/null +++ b/test/name-test/run-test.sh @@ -0,0 +1,55 @@ +#! /bin/sh + +die() +{ + if ! test -z "$DBUS_SESSION_BUS_PID" ; then + echo "killing message bus "$DBUS_SESSION_BUS_PID >&2 + kill -9 $DBUS_SESSION_BUS_PID + fi + echo $SCRIPTNAME: $* >&2 + + exit 1 +} + + +SCRIPTNAME=$0 +MODE=$1 + +## so the tests can complain if you fail to use the script to launch them +DBUS_TEST_NAME_RUN_TEST_SCRIPT=1 +export DBUS_TEST_NAME_RUN_TEST_SCRIPT + +# Rerun ourselves with tmp session bus if we're not already +if test -z "$DBUS_TEST_NAME_IN_RUN_TEST"; then + DBUS_TEST_NAME_IN_RUN_TEST=1 + export DBUS_TEST_NAME_IN_RUN_TEST + exec $DBUS_TOP_SRCDIR/tools/run-with-tmp-session-bus.sh $SCRIPTNAME $MODE +fi + +if test -n "$DBUS_TEST_MONITOR"; then + dbus-monitor --session & +fi + +echo "running test-ids" +${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-ids || die "test-ids failed" + +echo "running test-pending-call-dispatch" +${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-pending-call-dispatch || die "test-pending-call-dispatch failed" + +echo "running test-pending-call-timeout" +${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-pending-call-timeout || die "test-pending-call-timeout failed" + +echo "running test-threads-init" +${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-threads-init || die "test-threads-init failed" + +echo "running test-privserver-client" +${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-privserver-client || die "test-privserver-client failed" + +echo "running test-shutdown" +${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-shutdown || die "test-shutdown failed" + +echo "running test activation forking" +if ! python $DBUS_TOP_SRCDIR/test/name-test/test-activation-forking.py; then + echo "Failed test-activation-forking" + exit 1 +fi diff --git a/test/name-test/run-with-tmp-session-bus.conf b/test/name-test/run-with-tmp-session-bus.conf new file mode 100644 index 00000000..41f6856c --- /dev/null +++ b/test/name-test/run-with-tmp-session-bus.conf @@ -0,0 +1,87 @@ + + + + + + session + + + + unix:tmpdir=/tmp + + /src/jhbuild/checkout/dbus/test/data/valid-service-files + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1000000000 + 1000000000 + 1000000000 + 120000 + 240000 + 100000 + 10000 + 100000 + 10000 + 50000 + 50000 + 50000 + 300000 + + diff --git a/test/name-test/test-activation-forking.py b/test/name-test/test-activation-forking.py new file mode 100644 index 00000000..0d820754 --- /dev/null +++ b/test/name-test/test-activation-forking.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +import os,sys + +try: + import gobject + import dbus + import dbus.mainloop.glib +except: + print "Failed import, aborting test" + sys.exit(0) + +dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) +loop = gobject.MainLoop() + +exitcode = 0 + +bus = dbus.SessionBus() +bus_iface = dbus.Interface(bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus'), 'org.freedesktop.DBus') + +o = bus.get_object('org.freedesktop.DBus.TestSuiteForkingEchoService', '/org/freedesktop/TestSuite') +i = dbus.Interface(o, 'org.freedesktop.TestSuite') + +# Start it up +reply = i.Echo("hello world") +print "TestSuiteForkingEchoService initial reply OK" + +def ignore(*args, **kwargs): + pass + +# Now monitor for exits, when that happens, start it up again. +# The goal here is to try to hit any race conditions in activation. +counter = 0 +def on_forking_echo_owner_changed(name, old, new): + global counter + global o + global i + if counter > 10: + print "Activated 10 times OK, TestSuiteForkingEchoService pass" + loop.quit() + return + counter += 1 + if new == '': + o = bus.get_object('org.freedesktop.DBus.TestSuiteForkingEchoService', '/org/freedesktop/TestSuite') + i = dbus.Interface(o, 'org.freedesktop.TestSuite') + i.Echo("counter %r" % counter) + i.Exit(reply_handler=ignore, error_handler=ignore) + +bus_iface.connect_to_signal('NameOwnerChanged', on_forking_echo_owner_changed, arg0='org.freedesktop.DBus.TestSuiteForkingEchoService') + +i.Exit(reply_handler=ignore, error_handler=ignore) + +def check_counter(): + if counter == 0: + print "Failed to get NameOwnerChanged for TestSuiteForkingEchoService" + sys.exit(1) +gobject.timeout_add(15000, check_counter) + +loop.run() +sys.exit(0) diff --git a/test/name-test/test-ids.c b/test/name-test/test-ids.c new file mode 100644 index 00000000..f08d4ac9 --- /dev/null +++ b/test/name-test/test-ids.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +static void +die (const char *message) +{ + fprintf (stderr, "*** test-ids: %s", message); + exit (1); +} + +int +main (int argc, + char **argv) +{ + DBusError error; + DBusConnection *connection; + char *id; + char *server_id; + + dbus_error_init (&error); + connection = dbus_bus_get (DBUS_BUS_SESSION, &error); + if (connection == NULL) + { + fprintf (stderr, "*** Failed to open connection to system bus: %s\n", + error.message); + dbus_error_free (&error); + return 1; + } + + server_id = dbus_connection_get_server_id (connection); + if (server_id == NULL) + die ("No bus server ID retrieved\n"); + /* printf("'%s'\n", server_id); */ + if (strlen (server_id) != 32) + die ("Bus server id should have length 32\n"); + dbus_free (server_id); + + id = dbus_bus_get_id (connection, NULL); + if (id == NULL) + die ("No bus ID retrieved\n"); + /* printf("'%s'\n", id); */ + if (strlen (id) != 32) + die ("Bus ID should have length 32\n"); + dbus_free (id); + + _dbus_verbose ("*** Test IDs exiting\n"); + + return 0; +} diff --git a/test/name-test/test-pending-call-dispatch.c b/test/name-test/test-pending-call-dispatch.c new file mode 100644 index 00000000..54726498 --- /dev/null +++ b/test/name-test/test-pending-call-dispatch.c @@ -0,0 +1,123 @@ +/** +* Test to make sure we don't get stuck polling a dbus connection +* which has no data on the socket. This was an issue where +* one pending call would read all the data off the bus +* and the second pending call would not check to see +* if its data had already been read before polling the connection +* and blocking. +**/ + +#include +#include +#include +#include + +static void +_run_iteration (DBusConnection *conn) +{ + DBusPendingCall *echo_pending; + DBusPendingCall *dbus_pending; + DBusMessage *method; + DBusMessage *reply; + char *echo = "echo"; + + /* send the first message */ + method = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteEchoService", + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Echo"); + + dbus_message_append_args (method, DBUS_TYPE_STRING, &echo, NULL); + dbus_connection_send_with_reply (conn, method, &echo_pending, -1); + dbus_message_unref (method); + + /* send the second message */ + method = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + "org.freedesktop.Introspectable", + "Introspect"); + + dbus_connection_send_with_reply (conn, method, &dbus_pending, -1); + dbus_message_unref (method); + + /* block on the second message (should return immediately) */ + dbus_pending_call_block (dbus_pending); + + /* block on the first message */ + /* if it does not return immediately chances + are we hit the block in poll bug */ + dbus_pending_call_block (echo_pending); + + /* check the reply only to make sure we + are not getting errors unrelated + to the block in poll bug */ + reply = dbus_pending_call_steal_reply (echo_pending); + + if (reply == NULL) + { + printf ("Failed: Reply is NULL ***\n"); + exit (1); + } + + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) + { + printf ("Failed: Reply is error: %s ***\n", dbus_message_get_error_name (reply)); + exit (1); + } + + dbus_message_unref (reply); + dbus_pending_call_unref (dbus_pending); + dbus_pending_call_unref (echo_pending); + +} + +int +main (int argc, char *argv[]) +{ + long start_tv_sec, start_tv_usec; + long end_tv_sec, end_tv_usec; + int i; + DBusMessage *method; + DBusConnection *conn; + DBusError error; + + /* Time each iteration and make sure it doesn't take more than 5 seconds + to complete. Outside influences may cause connections to take longer + but if it does and we are stuck in a poll call then we know the + stuck in poll bug has come back to haunt us */ + + printf ("*** Testing stuck in poll\n"); + + dbus_error_init (&error); + + conn = dbus_bus_get (DBUS_BUS_SESSION, &error); + + /* run 100 times to make sure */ + for (i = 0; i < 100; i++) + { + long delta; + + _dbus_get_current_time (&start_tv_sec, &start_tv_usec); + _run_iteration (conn); + _dbus_get_current_time (&end_tv_sec, &end_tv_usec); + + /* we just care about seconds */ + delta = end_tv_sec - start_tv_sec; + printf ("Iter %i: %lis\n", i, delta); + if (delta >= 5) + { + printf ("Failed: looks like we might have been be stuck in poll ***\n"); + exit (1); + } + } + + method = dbus_message_new_method_call ("org.freedesktop.TestSuiteEchoService", + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Exit"); + dbus_connection_send (conn, method, NULL); + dbus_message_unref (method); + + printf ("Success ***\n"); + exit (0); +} diff --git a/test/name-test/test-pending-call-timeout.c b/test/name-test/test-pending-call-timeout.c new file mode 100644 index 00000000..53a0c3a7 --- /dev/null +++ b/test/name-test/test-pending-call-timeout.c @@ -0,0 +1,102 @@ +/** +* Test to make sure that pending calls succeed when given a default, +* specific and infinite timeout. +**/ + +#include +#include +#include +#include +#include + +static void +_method_call (DBusConnection *conn, + int timeout_milliseconds) +{ + DBusPendingCall *pending; + DBusMessage *method; + DBusMessage *reply; + char *echo = "echo"; + + /* send the message */ + method = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteEchoService", + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "DelayEcho"); + + dbus_message_append_args (method, DBUS_TYPE_STRING, &echo, NULL); + dbus_connection_send_with_reply (conn, method, &pending, timeout_milliseconds); + dbus_message_unref (method); + + /* block on the message */ + dbus_pending_call_block (pending); + + /* check the reply only to make sure we + are not getting errors unrelated + to the block in poll bug */ + reply = dbus_pending_call_steal_reply (pending); + + if (reply == NULL) + { + printf ("Failed: Reply is NULL ***\n"); + exit (1); + } + + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) + { + printf ("Failed: Reply is error: %s ***\n", dbus_message_get_error_name (reply)); + exit (1); + } + + dbus_message_unref (reply); + dbus_pending_call_unref (pending); +} + +static void +_run_iteration (DBusConnection *conn) +{ + _method_call (conn, -1); + _method_call (conn, 10000); + _method_call (conn, INT_MAX); +} + +int +main (int argc, char *argv[]) +{ + long start_tv_sec, start_tv_usec; + long end_tv_sec, end_tv_usec; + int i; + DBusMessage *method; + DBusConnection *conn; + DBusError error; + + printf ("*** Testing pending call timeouts\n"); + + dbus_error_init (&error); + + conn = dbus_bus_get (DBUS_BUS_SESSION, &error); + + /* run 100 times to make sure */ + for (i = 0; i < 100; i++) + { + long delta; + + _dbus_get_current_time (&start_tv_sec, &start_tv_usec); + _run_iteration (conn); + _dbus_get_current_time (&end_tv_sec, &end_tv_usec); + + /* we just care about seconds */ + delta = end_tv_sec - start_tv_sec; + printf ("Iter %i: %lis\n", i, delta); + } + + method = dbus_message_new_method_call ("org.freedesktop.TestSuiteEchoService", + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Exit"); + dbus_connection_send (conn, method, NULL); + dbus_message_unref (method); + + printf ("Success ***\n"); + exit (0); +} diff --git a/test/name-test/test-privserver-client.c b/test/name-test/test-privserver-client.c new file mode 100644 index 00000000..5af470ae --- /dev/null +++ b/test/name-test/test-privserver-client.c @@ -0,0 +1,116 @@ +#include "../test-utils.h" + +static void +die (const char *message, ...) +{ + va_list args; + va_start (args, message); + vfprintf (stderr, message, args); + va_end (args); + exit (1); +} + +static DBusHandlerResult +filter_private_message (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + if (dbus_message_is_signal (message, + DBUS_INTERFACE_LOCAL, + "Disconnected")) + { + DBusLoop *loop = user_data; + _dbus_loop_quit (loop); + return DBUS_HANDLER_RESULT_HANDLED; + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void +open_shutdown_private_connection (dbus_bool_t use_guid) +{ + DBusError error; + DBusLoop *loop; + DBusConnection *session; + DBusMessage *msg; + DBusMessage *reply; + DBusConnection *privconn; + char *addr; + char *comma; + + dbus_error_init (&error); + + loop = _dbus_loop_new (); + + session = dbus_bus_get (DBUS_BUS_SESSION, &error); + if (!session) + die ("couldn't access session bus\n"); + dbus_connection_set_exit_on_disconnect (session, FALSE); + msg = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuite.PrivServer", + "/", + "org.freedesktop.DBus.TestSuite.PrivServer", + "GetPrivateAddress"); + if (!(reply = dbus_connection_send_with_reply_and_block (session, msg, -1, &error))) + die ("couldn't send message: %s\n", error.message); + dbus_message_unref (msg); + if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &addr, DBUS_TYPE_INVALID)) + die ("couldn't parse message replym\n"); + printf ("got private temp address %s\n", addr); + addr = strdup (addr); + if (!use_guid) + { + char *comma = strrchr (addr, ','); + if (comma) + *comma = '\0'; + } + privconn = dbus_connection_open (addr, &error); + free (addr); + if (!privconn) + die ("couldn't connect to server direct connection: %s\n", error.message); + dbus_message_unref (reply); + + dbus_connection_set_exit_on_disconnect (privconn, FALSE); + dbus_connection_add_filter (privconn, filter_private_message, loop, NULL); + test_connection_setup (loop, privconn); + + msg = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuite.PrivServer", + "/", + "org.freedesktop.DBus.TestSuite.PrivServer", + "Quit"); + if (!dbus_connection_send (session, msg, NULL)) + die ("couldn't send Quit message\n"); + dbus_message_unref (msg); + + _dbus_loop_run (loop); + + test_connection_shutdown (loop, session); + dbus_connection_unref (session); + + test_connection_shutdown (loop, privconn); + dbus_connection_remove_filter (privconn, filter_private_message, loop); + dbus_connection_unref (privconn); + + _dbus_loop_unref (loop); +} + +int +main (int argc, char *argv[]) +{ + open_shutdown_private_connection (TRUE); + + dbus_shutdown (); + + open_shutdown_private_connection (TRUE); + + dbus_shutdown (); + + open_shutdown_private_connection (FALSE); + + dbus_shutdown (); + + open_shutdown_private_connection (FALSE); + + dbus_shutdown (); + + return 0; +} diff --git a/test/name-test/test-privserver.c b/test/name-test/test-privserver.c new file mode 100644 index 00000000..c814001c --- /dev/null +++ b/test/name-test/test-privserver.c @@ -0,0 +1,118 @@ +#include "../test-utils.h" + +static void +die (const char *message, ...) +{ + va_list args; + va_start (args, message); + vfprintf (stderr, message, args); + va_end (args); + exit (1); +} + +typedef struct TestServiceData TestServiceData; + +struct TestServiceData +{ + DBusLoop *loop; + char *private_addr; +}; + +static void +new_connection_callback (DBusServer *server, + DBusConnection *new_connection, + void *data) +{ + TestServiceData *testdata = data; + + if (!test_connection_setup (testdata->loop, new_connection)) + dbus_connection_close (new_connection); +} + +static DBusHandlerResult +filter_session_message (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + TestServiceData *testdata = user_data; + + if (dbus_message_is_method_call (message, + "org.freedesktop.DBus.TestSuite.PrivServer", + "GetPrivateAddress")) + { + DBusMessage *reply; + reply = dbus_message_new_method_return (message); + dbus_message_append_args (reply, DBUS_TYPE_STRING, + &(testdata->private_addr), DBUS_TYPE_INVALID); + dbus_connection_send (connection, reply, NULL); + dbus_message_unref (reply); + return DBUS_HANDLER_RESULT_HANDLED; + } + else if (dbus_message_is_method_call (message, + "org.freedesktop.DBus.TestSuite.PrivServer", + "Quit")) + { + fprintf (stderr, "server exiting loop\n"); + _dbus_loop_quit (testdata->loop); + return DBUS_HANDLER_RESULT_HANDLED; + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +int +main (int argc, char *argv[]) +{ + DBusServer *server; + DBusError error; + DBusLoop *loop; + DBusConnection *session; + TestServiceData *testdata; + + dbus_error_init (&error); + + loop = _dbus_loop_new (); + + testdata = dbus_new (TestServiceData, 1); + testdata->loop = loop; + + session = dbus_bus_get (DBUS_BUS_SESSION, &error); + if (!session) + die ("couldn't access session bus"); + + test_connection_setup (loop, session); + + dbus_bus_request_name (session, "org.freedesktop.DBus.TestSuite.PrivServer", 0, &error); + if (dbus_error_is_set (&error)) + die ("couldn't request name: %s", error.message); + + if (!dbus_connection_add_filter (session, filter_session_message, testdata, NULL)) + die ("couldn't add filter"); + + server = dbus_server_listen ("unix:tmpdir=/tmp", &error); + if (!server) + die (error.message); + testdata->private_addr = dbus_server_get_address (server); + printf ("test server listening on %s\n", testdata->private_addr); + + dbus_server_set_new_connection_function (server, new_connection_callback, + testdata, NULL); + + if (!test_server_setup (loop, server)) + die ("server setup failed"); + + fprintf (stderr, "server running mainloop\n"); + _dbus_loop_run (loop); + fprintf (stderr, "server mainloop quit\n"); + + test_server_shutdown (loop, server); + + test_connection_shutdown (loop, session); + + dbus_connection_unref (session); + + _dbus_loop_unref (loop); + + dbus_free (testdata); + + return 0; +} diff --git a/test/name-test/test-shutdown.c b/test/name-test/test-shutdown.c new file mode 100644 index 00000000..e76c1ea2 --- /dev/null +++ b/test/name-test/test-shutdown.c @@ -0,0 +1,67 @@ + +#include "../test-utils.h" + +static DBusLoop *loop; + +static void +die (const char *message) +{ + fprintf (stderr, "*** test-shutdown: %s", message); + exit (1); +} + +static void +open_destroy_shared_session_bus_connection (void) +{ + DBusError error; + DBusConnection *connection; + char *session_addr_no_guid; + char *comma; + + dbus_error_init (&error); + + session_addr_no_guid = strdup (getenv ("DBUS_SESSION_BUS_ADDRESS")); + comma = strchr (session_addr_no_guid, ','); + if (comma == NULL) + die ("Couldn't find GUID in session bus address"); + *comma = '\0'; + + connection = dbus_connection_open (session_addr_no_guid, &error); + free (session_addr_no_guid); + if (connection == NULL) + die ("Failed to open connection to temp session bus\n"); + + loop = _dbus_loop_new (); + if (loop == NULL) + die ("No memory\n"); + + if (!test_connection_setup (loop, connection)) + die ("No memory\n"); + + test_connection_shutdown (loop, connection); + + _dbus_loop_unref (loop); + + dbus_connection_unref (connection); +} + +int +main (int argc, + char **argv) +{ + open_destroy_shared_session_bus_connection (); + + dbus_shutdown (); + + open_destroy_shared_session_bus_connection (); + + dbus_shutdown (); + + open_destroy_shared_session_bus_connection (); + + dbus_shutdown (); + + _dbus_verbose ("*** Test shutdown exiting\n"); + + return 0; +} diff --git a/test/name-test/test-threads-init.c b/test/name-test/test-threads-init.c new file mode 100644 index 00000000..8cda413c --- /dev/null +++ b/test/name-test/test-threads-init.c @@ -0,0 +1,179 @@ +/** + * Test to make sure late thread initialization works + */ + +#include +#include +#include +#include + +#include +#include + +static void +_run_iteration (DBusConnection *conn) +{ + DBusPendingCall *echo_pending; + DBusPendingCall *dbus_pending; + DBusMessage *method; + DBusMessage *reply; + char *echo = "echo"; + + /* send the first message */ + method = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteEchoService", + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Echo"); + + dbus_message_append_args (method, DBUS_TYPE_STRING, &echo, NULL); + dbus_connection_send_with_reply (conn, method, &echo_pending, -1); + dbus_message_unref (method); + + /* send the second message */ + method = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + "org.freedesktop.Introspectable", + "Introspect"); + + dbus_connection_send_with_reply (conn, method, &dbus_pending, -1); + dbus_message_unref (method); + + /* block on the second message (should return immediately) */ + dbus_pending_call_block (dbus_pending); + + /* block on the first message */ + /* if it does not return immediately chances + are we hit the block in poll bug */ + dbus_pending_call_block (echo_pending); + + /* check the reply only to make sure we + are not getting errors unrelated + to the block in poll bug */ + reply = dbus_pending_call_steal_reply (echo_pending); + + if (reply == NULL) + { + printf ("Failed: Reply is NULL ***\n"); + exit (1); + } + + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) + { + printf ("Failed: Reply is error: %s ***\n", dbus_message_get_error_name (reply)); + exit (1); + } + + dbus_message_unref (reply); + dbus_pending_call_unref (dbus_pending); + dbus_pending_call_unref (echo_pending); + +} +static void +check_mutex_lock (DBusMutex *mutex1, + DBusMutex *mutex2, + dbus_bool_t is_same) +{ + _dbus_assert (mutex1 != NULL); + _dbus_assert (mutex2 != NULL); + + if (is_same) + { + _dbus_assert (mutex1 == mutex2); + } + else + { + _dbus_assert (mutex1 != mutex2); + } +} + +static void +check_condvar_lock (DBusCondVar *condvar1, + DBusCondVar *condvar2, + dbus_bool_t is_same) +{ + _dbus_assert (condvar1 != NULL); + _dbus_assert (condvar2 != NULL); + + if (is_same) + { + _dbus_assert (condvar1 == condvar2); + } + else + { + _dbus_assert (condvar1 != condvar2); + } +} + + +int +main (int argc, char *argv[]) +{ + DBusMessage *method; + DBusConnection *conn; + DBusError error; + DBusMutex *mutex1, *dispatch_mutex1, *io_path_mutex1; + DBusCondVar *dispatch_cond1, *io_path_cond1; + DBusMutex *mutex2, *dispatch_mutex2, *io_path_mutex2; + DBusCondVar *dispatch_cond2, *io_path_cond2; + + printf ("*** Testing late thread init\n"); + + dbus_error_init (&error); + + conn = dbus_bus_get (DBUS_BUS_SESSION, &error); + + _dbus_connection_test_get_locks (conn, &mutex1, + &dispatch_mutex1, + &io_path_mutex1, + &dispatch_cond1, + &io_path_cond1); + _run_iteration (conn); + _dbus_connection_test_get_locks (conn, &mutex2, + &dispatch_mutex2, + &io_path_mutex2, + &dispatch_cond2, + &io_path_cond2); + + check_mutex_lock (mutex1, mutex2, TRUE); + check_mutex_lock (dispatch_mutex1, dispatch_mutex2, TRUE); + check_mutex_lock (io_path_mutex1, io_path_mutex2, TRUE); + check_condvar_lock (dispatch_cond1, dispatch_cond2, TRUE); + check_condvar_lock (io_path_cond1, io_path_cond2, TRUE); + + dbus_threads_init_default (); + + _dbus_connection_test_get_locks (conn, &mutex1, + &dispatch_mutex1, + &io_path_mutex1, + &dispatch_cond1, + &io_path_cond1); + + check_mutex_lock (mutex1, mutex2, FALSE); + check_mutex_lock (dispatch_mutex1, dispatch_mutex2, FALSE); + check_mutex_lock (io_path_mutex1, io_path_mutex2, FALSE); + check_condvar_lock (dispatch_cond1, dispatch_cond2, FALSE); + check_condvar_lock (io_path_cond1, io_path_cond2, FALSE); + + _run_iteration (conn); + _dbus_connection_test_get_locks (conn, &mutex2, + &dispatch_mutex2, + &io_path_mutex2, + &dispatch_cond2, + &io_path_cond2); + + check_mutex_lock (mutex1, mutex2, TRUE); + check_mutex_lock (dispatch_mutex1, dispatch_mutex2, TRUE); + check_mutex_lock (io_path_mutex1, io_path_mutex2, TRUE); + check_condvar_lock (dispatch_cond1, dispatch_cond2, TRUE); + check_condvar_lock (io_path_cond1, io_path_cond2, TRUE); + + method = dbus_message_new_method_call ("org.freedesktop.TestSuiteEchoService", + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Exit"); + dbus_connection_send (conn, method, NULL); + dbus_message_unref (method); + + printf ("Success ***\n"); + exit (0); +} diff --git a/test/name-test/test-wait-for-echo.py b/test/name-test/test-wait-for-echo.py new file mode 100755 index 00000000..bd09e459 --- /dev/null +++ b/test/name-test/test-wait-for-echo.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +import os,sys + +try: + import gobject + import dbus + import dbus.mainloop.glib +except: + print "Failed import, aborting test" + sys.exit(0) + +dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) +loop = gobject.MainLoop() + +exitcode = 0 + +def handle_noreceipt(): + print "Failed to get signal" + global exitcode + exitcode = 1 + loop.quit() + +gobject.timeout_add(7000, handle_noreceipt) + +bus = dbus.SessionBus() + +def sighandler(*args, **kwargs): + print "got signal" + loop.quit() + +bus.add_signal_receiver(sighandler, dbus_interface='org.freedesktop.TestSuite', signal_name='Foo') + +o = bus.get_object('org.freedesktop.DBus.TestSuiteEchoService', '/org/freedesktop/TestSuite') +i = dbus.Interface(o, 'org.freedesktop.TestSuite') +def nullhandler(*args, **kwargs): + pass +i.EmitFoo(reply_handler=nullhandler, error_handler=nullhandler) + +loop.run() +sys.exit(exitcode) diff --git a/test/name-test/tmp-session-like-system.conf b/test/name-test/tmp-session-like-system.conf new file mode 100644 index 00000000..0818109a --- /dev/null +++ b/test/name-test/tmp-session-like-system.conf @@ -0,0 +1,87 @@ + + + + + + session + + + + unix:tmpdir=/tmp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1000000000 + 1000000000 + 1000000000 + 120000 + 240000 + 100000 + 10000 + 100000 + 10000 + 50000 + 50000 + 50000 + 300000 + + diff --git a/test/shell-test.c b/test/shell-test.c new file mode 100644 index 00000000..c0134677 --- /dev/null +++ b/test/shell-test.c @@ -0,0 +1,108 @@ +#include +#include +#define DBUS_COMPILATION +#include +#include +#include +#include +#include +#include + +static dbus_bool_t +test_command_line (const char *arg1, ...) +{ + int i, original_argc, shell_argc; + char **shell_argv; + char **original_argv; + char *command_line, *tmp; + DBusString str; + DBusList *list = NULL, *node; + va_list var_args; + DBusError error; + + va_start (var_args, arg1); + _dbus_list_append (&list, (char *)arg1); + do + { + tmp = va_arg (var_args, char *); + if (!tmp) + break; + _dbus_list_append (&list, tmp); + } while (tmp); + va_end (var_args); + + original_argc = _dbus_list_get_length (&list); + original_argv = dbus_new (char *, original_argc); + _dbus_string_init (&str); + for (i = 0, node = _dbus_list_get_first_link (&list); i < original_argc && node; + i++, node = _dbus_list_get_next_link (&list, node)) + { + original_argv[i] = node->data; + if (i > 0) + _dbus_string_append_byte (&str, ' '); + _dbus_string_append (&str, original_argv[i]); + } + + _dbus_list_clear (&list); + command_line = _dbus_string_get_data (&str); + printf ("\n\nTesting command line '%s'\n", command_line); + + dbus_error_init (&error); + if (!_dbus_shell_parse_argv (command_line, &shell_argc, &shell_argv, &error)) + { + fprintf (stderr, "Error parsing command line: %s\n", error.message ? error.message : ""); + return FALSE; + } + else + { + if (shell_argc != original_argc) + { + printf ("Number of arguments returned (%d) don't match original (%d)\n", + shell_argc, original_argc); + return FALSE; + } + printf ("Number of arguments: %d\n", shell_argc); + for (i = 0; i < shell_argc; i++) + { + char *unquoted; + + unquoted = _dbus_shell_unquote (original_argv[i]); + if (strcmp (unquoted ? unquoted : "", + shell_argv[i] ? shell_argv[i] : "")) + { + printf ("Position %d, returned argument (%s) does not match original (%s)\n", + i, shell_argv[i], unquoted); + dbus_free (unquoted); + return FALSE; + } + dbus_free (unquoted); + if (shell_argv[i]) + printf ("Argument %d = %s\n", i, shell_argv[i]); + } + + dbus_free_string_array (shell_argv); + } + + _dbus_string_free (&str); + + return TRUE; +} + +int +main (int argc, char **argv) +{ + if (!test_command_line ("command", "-s", "--force-shutdown", "\"a string\"", "123", NULL) + || !test_command_line ("command", "-s", NULL) + || !test_command_line ("/opt/gnome/bin/service-start", NULL) + || !test_command_line ("grep", "-l", "-r", "-i", "'whatever'", "files*.c", NULL) + || !test_command_line ("/home/boston/johnp/devel-local/dbus/test/test-segfault", NULL) + || !test_command_line ("ls", "-l", "-a", "--colors", _dbus_get_tmpdir(), NULL) + || !test_command_line ("rsync-to-server", NULL) + || !test_command_line ("test-segfault", "--no-segfault", NULL) + || !test_command_line ("evolution", "mailto:pepe@cuco.com", NULL) + || !test_command_line ("run", "\"a \n multiline\"", NULL) + || test_command_line ("ls", "\"a wrong string'", NULL) /* invalid command line */ ) + return -1; + + return 0; +} diff --git a/test/spawn-test.c b/test/spawn-test.c new file mode 100644 index 00000000..991a5e83 --- /dev/null +++ b/test/spawn-test.c @@ -0,0 +1,41 @@ +#include + +#define DBUS_COMPILATION /* cheat and use dbus-sysdeps */ +#include +#include +#undef DBUS_COMPILATION +#include + +static void +setup_func (void *data) +{ + printf ("entering setup func.\n"); +} + +int +main (int argc, char **argv) +{ + char **argv_copy; + int i; + DBusError error; + + if (argc < 2) + { + fprintf (stderr, "You need to specify a program to launch.\n"); + + return -1; + } + + argv_copy = dbus_new (char *, argc); + for (i = 0; i < argc - 1; i++) + argv_copy [i] = argv[i + 1]; + argv_copy[argc - 1] = NULL; + + if (!_dbus_spawn_async_with_babysitter (NULL, argv_copy, NULL, setup_func, NULL, &error)) + { + fprintf (stderr, "Could not launch application: \"%s\"\n", + error.message); + } + + return 0; +} diff --git a/test/test-exit.c b/test/test-exit.c new file mode 100644 index 00000000..abb95865 --- /dev/null +++ b/test/test-exit.c @@ -0,0 +1,8 @@ +/* This is a process that just exits with a failure code */ + +int +main (int argc, char **argv) +{ + + return 1; +} diff --git a/test/test-names.c b/test/test-names.c new file mode 100644 index 00000000..e618e99b --- /dev/null +++ b/test/test-names.c @@ -0,0 +1,78 @@ + +#include "test-utils.h" + +static DBusLoop *loop; + +static void +die (const char *message) +{ + fprintf (stderr, "*** test-names: %s", message); + exit (1); +} + +static void +TestName(DBusConnection *connection, const char *name, int expectedSuccess) +{ + DBusError error; + dbus_error_init (&error); + + (void) dbus_bus_request_name (connection, name, 0, &error); + if (dbus_error_is_set (&error)) + { + if (expectedSuccess) + fprintf (stderr, "Error acquiring name '%s': %s\n", name, error.message); + else + fprintf (stdout, "Expected Error acquiring name '%s': %s\n", name, error.message); + _dbus_verbose ("*** Failed to acquire name '%s': %s\n", name, + error.message); + dbus_error_free (&error); + if (expectedSuccess) + exit (1); + } + else + { + if (!expectedSuccess) + fprintf (stderr, "Unexpected Success acquiring name '%s'\n", name); + else + fprintf (stdout, "Successfully acquired name '%s'\n", name); + _dbus_verbose ("*** Managed to acquire name '%s'\n", name); + if (!expectedSuccess) + exit (1); + } +} + +int +main (int argc, + char **argv) +{ + DBusError error; + DBusConnection *connection; + + dbus_error_init (&error); + connection = dbus_bus_get (DBUS_BUS_SESSION, &error); + if (connection == NULL) + { + fprintf (stderr, "*** Failed to open connection to system bus: %s\n", + error.message); + dbus_error_free (&error); + return 1; + } + + loop = _dbus_loop_new (); + if (loop == NULL) + die ("No memory\n"); + + if (!test_connection_setup (loop, connection)) + die ("No memory\n"); + + TestName(connection, "org.freedesktop.DBus.Test", TRUE); + TestName(connection, "org.freedesktop.DBus.Test-2", TRUE); + TestName(connection, "org.freedesktop.DBus.Test_2", TRUE); +#if 0 + TestName(connection, "Test_2", TRUE); +#endif + + _dbus_verbose ("*** Test service name exiting\n"); + + return 0; +} diff --git a/test/test-segfault.c b/test/test-segfault.c new file mode 100644 index 00000000..bf4d964b --- /dev/null +++ b/test/test-segfault.c @@ -0,0 +1,28 @@ +/* This is simply a process that segfaults */ +#include +#include +#include + +#ifdef HAVE_SETRLIMIT +#include +#endif + +int +main (int argc, char **argv) +{ + char *p; + +#if HAVE_SETRLIMIT + struct rlimit r = { 0, }; + + getrlimit (RLIMIT_CORE, &r); + r.rlim_cur = 0; + setrlimit (RLIMIT_CORE, &r); + + raise (SIGSEGV); +#endif + p = NULL; + *p = 'a'; + + return 0; +} diff --git a/test/test-service.c b/test/test-service.c new file mode 100644 index 00000000..9a129aac --- /dev/null +++ b/test/test-service.c @@ -0,0 +1,489 @@ + +#include "test-utils.h" +#include + +static DBusLoop *loop; +static dbus_bool_t already_quit = FALSE; +static dbus_bool_t hello_from_self_reply_received = FALSE; + +static void +quit (void) +{ + if (!already_quit) + { + _dbus_loop_quit (loop); + already_quit = TRUE; + } +} + +static void +die (const char *message) +{ + fprintf (stderr, "*** test-service: %s", message); + exit (1); +} + +static void +check_hello_from_self_reply (DBusPendingCall *pcall, + void *user_data) +{ + DBusMessage *reply; + DBusMessage *echo_message, *echo_reply = NULL; + DBusError error; + DBusConnection *connection; + + int type; + + dbus_error_init (&error); + + connection = dbus_bus_get (DBUS_BUS_STARTER, &error); + if (connection == NULL) + { + fprintf (stderr, "*** Failed to open connection to activating message bus: %s\n", + error.message); + dbus_error_free (&error); + die("no memory"); + } + + + echo_message = (DBusMessage *)user_data; + + reply = dbus_pending_call_steal_reply (pcall); + + type = dbus_message_get_type (reply); + + if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN) + { + const char *s; + printf ("Reply from HelloFromSelf received\n"); + + if (!dbus_message_get_args (echo_message, + &error, + DBUS_TYPE_STRING, &s, + DBUS_TYPE_INVALID)) + { + echo_reply = dbus_message_new_error (echo_message, + error.name, + error.message); + + if (echo_reply == NULL) + die ("No memory\n"); + + } + else + { + echo_reply = dbus_message_new_method_return (echo_message); + if (echo_reply == NULL) + die ("No memory\n"); + + if (!dbus_message_append_args (echo_reply, + DBUS_TYPE_STRING, &s, + DBUS_TYPE_INVALID)) + die ("No memory"); + } + + if (!dbus_connection_send (connection, echo_reply, NULL)) + die ("No memory\n"); + + dbus_message_unref (echo_reply); + } + else if (type == DBUS_MESSAGE_TYPE_ERROR) + { + dbus_set_error_from_message (&error, reply); + printf ("Error type in reply: %s\n", error.message); + + if (strcmp (error.name, DBUS_ERROR_NO_MEMORY) != 0) + { + echo_reply = dbus_message_new_error (echo_reply, + error.name, + error.message); + + if (echo_reply == NULL) + die ("No memory\n"); + + if (!dbus_connection_send (connection, echo_reply, NULL)) + die ("No memory\n"); + + dbus_message_unref (echo_reply); + } + dbus_error_free (&error); + } + else + _dbus_assert_not_reached ("Unexpected message received\n"); + + hello_from_self_reply_received = TRUE; + + dbus_message_unref (reply); + dbus_message_unref (echo_message); + dbus_pending_call_unref (pcall); + dbus_connection_unref (connection); +} + +static DBusHandlerResult +handle_run_hello_from_self (DBusConnection *connection, + DBusMessage *message) +{ + DBusError error; + DBusMessage *reply, *self_message; + DBusPendingCall *pcall; + char *s; + + _dbus_verbose ("sending reply to Echo method\n"); + + dbus_error_init (&error); + + if (!dbus_message_get_args (message, + &error, + DBUS_TYPE_STRING, &s, + DBUS_TYPE_INVALID)) + { + reply = dbus_message_new_error (message, + error.name, + error.message); + + if (reply == NULL) + die ("No memory\n"); + + if (!dbus_connection_send (connection, reply, NULL)) + die ("No memory\n"); + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + printf ("Sending HelloFromSelf\n"); + + _dbus_verbose ("*** Sending message to self\n"); + self_message = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuiteEchoService", + "/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "HelloFromSelf"); + + if (self_message == NULL) + die ("No memory"); + + if (!dbus_connection_send_with_reply (connection, self_message, &pcall, -1)) + die("No memory"); + + dbus_message_ref (message); + if (!dbus_pending_call_set_notify (pcall, check_hello_from_self_reply, (void *)message, NULL)) + die("No memory"); + + printf ("Sent HelloFromSelf\n"); + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult +handle_echo (DBusConnection *connection, + DBusMessage *message) +{ + DBusError error; + DBusMessage *reply; + char *s; + + _dbus_verbose ("sending reply to Echo method\n"); + + dbus_error_init (&error); + + if (!dbus_message_get_args (message, + &error, + DBUS_TYPE_STRING, &s, + DBUS_TYPE_INVALID)) + { + reply = dbus_message_new_error (message, + error.name, + error.message); + + if (reply == NULL) + die ("No memory\n"); + + if (!dbus_connection_send (connection, reply, NULL)) + die ("No memory\n"); + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + die ("No memory\n"); + + if (!dbus_message_append_args (reply, + DBUS_TYPE_STRING, &s, + DBUS_TYPE_INVALID)) + die ("No memory"); + + if (!dbus_connection_send (connection, reply, NULL)) + die ("No memory\n"); + + fprintf (stderr, "Echo service echoed string: \"%s\"\n", s); + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult +handle_delay_echo (DBusConnection *connection, + DBusMessage *message) +{ + DBusError error; + DBusMessage *reply; + char *s; + + _dbus_verbose ("sleeping for a short time\n"); + + usleep (50000); + + _dbus_verbose ("sending reply to DelayEcho method\n"); + + dbus_error_init (&error); + + if (!dbus_message_get_args (message, + &error, + DBUS_TYPE_STRING, &s, + DBUS_TYPE_INVALID)) + { + reply = dbus_message_new_error (message, + error.name, + error.message); + + if (reply == NULL) + die ("No memory\n"); + + if (!dbus_connection_send (connection, reply, NULL)) + die ("No memory\n"); + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + die ("No memory\n"); + + if (!dbus_message_append_args (reply, + DBUS_TYPE_STRING, &s, + DBUS_TYPE_INVALID)) + die ("No memory"); + + if (!dbus_connection_send (connection, reply, NULL)) + die ("No memory\n"); + + fprintf (stderr, "DelayEcho service echoed string: \"%s\"\n", s); + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + + +static void +path_unregistered_func (DBusConnection *connection, + void *user_data) +{ + /* connection was finalized */ +} + +static DBusHandlerResult +path_message_func (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + if (dbus_message_is_method_call (message, + "org.freedesktop.TestSuite", + "Echo")) + return handle_echo (connection, message); + else if (dbus_message_is_method_call (message, + "org.freedesktop.TestSuite", + "DelayEcho")) + return handle_delay_echo (connection, message); + else if (dbus_message_is_method_call (message, + "org.freedesktop.TestSuite", + "Exit")) + { + quit (); + return DBUS_HANDLER_RESULT_HANDLED; + } + else if (dbus_message_is_method_call (message, + "org.freedesktop.TestSuite", + "EmitFoo")) + { + /* Emit the Foo signal */ + DBusMessage *signal; + double v_DOUBLE; + + _dbus_verbose ("emitting signal Foo\n"); + + signal = dbus_message_new_signal ("/org/freedesktop/TestSuite", + "org.freedesktop.TestSuite", + "Foo"); + if (signal == NULL) + die ("No memory\n"); + + v_DOUBLE = 42.6; + if (!dbus_message_append_args (signal, + DBUS_TYPE_DOUBLE, &v_DOUBLE, + DBUS_TYPE_INVALID)) + die ("No memory"); + + if (!dbus_connection_send (connection, signal, NULL)) + die ("No memory\n"); + + return DBUS_HANDLER_RESULT_HANDLED; + } + + else if (dbus_message_is_method_call (message, + "org.freedesktop.TestSuite", + "RunHelloFromSelf")) + { + return handle_run_hello_from_self (connection, message); + } + else if (dbus_message_is_method_call (message, + "org.freedesktop.TestSuite", + "HelloFromSelf")) + { + DBusMessage *reply; + printf ("Received the HelloFromSelf message\n"); + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + die ("No memory"); + + if (!dbus_connection_send (connection, reply, NULL)) + die ("No memory"); + + return DBUS_HANDLER_RESULT_HANDLED; + } + else + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusObjectPathVTable +echo_vtable = { + path_unregistered_func, + path_message_func, + NULL, +}; + + +static const char* echo_path = "/org/freedesktop/TestSuite" ; + +static DBusHandlerResult +filter_func (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + if (dbus_message_is_signal (message, + DBUS_INTERFACE_LOCAL, + "Disconnected")) + { + quit (); + return DBUS_HANDLER_RESULT_HANDLED; + } + else + { + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } +} + +int +main (int argc, + char **argv) +{ + DBusError error; + int result; + DBusConnection *connection; + const char *name; + dbus_bool_t do_fork; + + if (argc != 3) + { + name = "org.freedesktop.DBus.TestSuiteEchoService"; + do_fork = FALSE; + } + else + { + name = argv[1]; + do_fork = strcmp (argv[2], "fork") == 0; + } + + /* The bare minimum for simulating a program "daemonizing"; the intent + * is to test services which move from being legacy init scripts to + * activated services. + * https://bugzilla.redhat.com/show_bug.cgi?id=545267 + */ + if (do_fork) + { + pid_t pid = fork (); + if (pid != 0) + exit (0); + sleep (1); + } + + dbus_error_init (&error); + connection = dbus_bus_get (DBUS_BUS_STARTER, &error); + if (connection == NULL) + { + fprintf (stderr, "*** Failed to open connection to activating message bus: %s\n", + error.message); + dbus_error_free (&error); + return 1; + } + + loop = _dbus_loop_new (); + if (loop == NULL) + die ("No memory\n"); + + if (!test_connection_setup (loop, connection)) + die ("No memory\n"); + + if (!dbus_connection_add_filter (connection, + filter_func, NULL, NULL)) + die ("No memory"); + + if (!dbus_connection_register_object_path (connection, + echo_path, + &echo_vtable, + (void*) 0xdeadbeef)) + die ("No memory"); + + { + void *d; + if (!dbus_connection_get_object_path_data (connection, echo_path, &d)) + die ("No memory"); + if (d != (void*) 0xdeadbeef) + die ("dbus_connection_get_object_path_data() doesn't seem to work right\n"); + } + + result = dbus_bus_request_name (connection, name, + 0, &error); + if (dbus_error_is_set (&error)) + { + fprintf (stderr, "Error %s\n", error.message); + _dbus_verbose ("*** Failed to acquire service: %s\n", + error.message); + dbus_error_free (&error); + exit (1); + } + + _dbus_verbose ("*** Test service entering main loop\n"); + _dbus_loop_run (loop); + + test_connection_shutdown (loop, connection); + + dbus_connection_remove_filter (connection, filter_func, NULL); + + dbus_connection_unref (connection); + + _dbus_loop_unref (loop); + loop = NULL; + + dbus_shutdown (); + + _dbus_verbose ("*** Test service exiting\n"); + + return 0; +} diff --git a/test/test-shell-service.c b/test/test-shell-service.c new file mode 100644 index 00000000..21801c7b --- /dev/null +++ b/test/test-shell-service.c @@ -0,0 +1,195 @@ + +#include "test-utils.h" + +static DBusLoop *loop; +static dbus_bool_t already_quit = FALSE; +static const char* echo_path = "/org/freedesktop/TestSuite"; + +typedef struct +{ + int argc; + char **argv; +} EchoData; + +static void +quit (void) +{ + if (!already_quit) + { + _dbus_loop_quit (loop); + already_quit = TRUE; + } +} + +static void +die (const char *message) +{ + fprintf (stderr, "*** test-service: %s", message); + exit (1); +} + +static DBusHandlerResult +handle_echo (DBusConnection *connection, + DBusMessage *message) +{ + DBusError error; + DBusMessage *reply; + DBusMessageIter iter; + int i; + EchoData *d; + + _dbus_verbose ("sending reply to Echo method\n"); + + if (!dbus_connection_get_object_path_data (connection, echo_path, (void **)&d)) + die ("No memory"); + + + dbus_error_init (&error); + + reply = dbus_message_new_method_return (message); + if (reply == NULL) + die ("No memory\n"); + + dbus_message_iter_init_append (reply, &iter); + for (i = 0; i < d->argc; ++i) + if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &(d->argv[i]))) + die ("No memory\n"); + + if (!dbus_connection_send (connection, reply, NULL)) + die ("No memory\n"); + + fprintf (stderr, "Shell echo service echoed the command line\n"); + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static void +path_unregistered_func (DBusConnection *connection, + void *user_data) +{ + /* connection was finalized */ +} + +static DBusHandlerResult +path_message_func (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + if (dbus_message_is_method_call (message, + "org.freedesktop.TestSuite", + "Echo")) + return handle_echo (connection, message); + else if (dbus_message_is_method_call (message, + "org.freedesktop.TestSuite", + "Exit")) + { + quit (); + return DBUS_HANDLER_RESULT_HANDLED; + } + else + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusObjectPathVTable +echo_vtable = { + path_unregistered_func, + path_message_func, + NULL, +}; + +static DBusHandlerResult +filter_func (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + if (dbus_message_is_signal (message, + DBUS_INTERFACE_LOCAL, + "Disconnected")) + { + quit (); + return DBUS_HANDLER_RESULT_HANDLED; + } + else + { + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } +} + +int +main (int argc, + char **argv) +{ + DBusConnection *connection; + DBusError error; + EchoData echo_data; + int result; + + echo_data.argc = argc; + echo_data.argv = argv; + + dbus_error_init (&error); + connection = dbus_bus_get (DBUS_BUS_STARTER, &error); + if (connection == NULL) + { + fprintf (stderr, "*** Failed to open connection to activating message bus: %s\n", + error.message); + dbus_error_free (&error); + return 1; + } + + loop = _dbus_loop_new (); + if (loop == NULL) + die ("No memory\n"); + + if (!test_connection_setup (loop, connection)) + die ("No memory\n"); + + if (!dbus_connection_add_filter (connection, + filter_func, NULL, NULL)) + die ("No memory"); + + if (!dbus_connection_register_object_path (connection, + echo_path, + &echo_vtable, + (void*) &echo_data)) + die ("No memory"); + + { + void *d; + if (!dbus_connection_get_object_path_data (connection, echo_path, &d)) + die ("No memory"); + if (d != (void*) &echo_data) + die ("dbus_connection_get_object_path_data() doesn't seem to work right\n"); + } + + result = dbus_bus_request_name (connection, "org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess", + 0, &error); + if (dbus_error_is_set (&error)) + { + fprintf (stderr, "Error %s\n", error.message); + _dbus_verbose ("*** Failed to acquire service: %s\n", + error.message); + dbus_error_free (&error); + exit (1); + } + + _dbus_verbose ("*** Test service entering main loop\n"); + _dbus_loop_run (loop); + + test_connection_shutdown (loop, connection); + + dbus_connection_remove_filter (connection, filter_func, NULL); + + dbus_connection_unref (connection); + + _dbus_loop_unref (loop); + loop = NULL; + + dbus_shutdown (); + + _dbus_verbose ("*** Test service exiting\n"); + + return 0; +} diff --git a/test/test-sleep-forever.c b/test/test-sleep-forever.c new file mode 100644 index 00000000..ff0d8e26 --- /dev/null +++ b/test/test-sleep-forever.c @@ -0,0 +1,16 @@ +/* This is a process that just sleeps infinitely. */ + +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +int +main (int argc, char **argv) +{ + while (1) + sleep (10000000); + + return 1; +} diff --git a/test/test-utils.c b/test/test-utils.c new file mode 100644 index 00000000..d875cc95 --- /dev/null +++ b/test/test-utils.c @@ -0,0 +1,343 @@ +#include "test-utils.h" + +typedef struct +{ + DBusLoop *loop; + DBusConnection *connection; + +} CData; + +static dbus_bool_t +connection_watch_callback (DBusWatch *watch, + unsigned int condition, + void *data) +{ + return dbus_watch_handle (watch, condition); +} + +static dbus_bool_t +add_watch (DBusWatch *watch, + void *data) +{ + CData *cd = data; + + return _dbus_loop_add_watch (cd->loop, + watch, + connection_watch_callback, + cd, NULL); +} + +static void +remove_watch (DBusWatch *watch, + void *data) +{ + CData *cd = data; + + _dbus_loop_remove_watch (cd->loop, + watch, connection_watch_callback, cd); +} + +static void +connection_timeout_callback (DBusTimeout *timeout, + void *data) +{ + /* Can return FALSE on OOM but we just let it fire again later */ + dbus_timeout_handle (timeout); +} + +static dbus_bool_t +add_timeout (DBusTimeout *timeout, + void *data) +{ + CData *cd = data; + + return _dbus_loop_add_timeout (cd->loop, + timeout, connection_timeout_callback, cd, NULL); +} + +static void +remove_timeout (DBusTimeout *timeout, + void *data) +{ + CData *cd = data; + + _dbus_loop_remove_timeout (cd->loop, + timeout, connection_timeout_callback, cd); +} + +static void +dispatch_status_function (DBusConnection *connection, + DBusDispatchStatus new_status, + void *data) +{ + DBusLoop *loop = data; + + if (new_status != DBUS_DISPATCH_COMPLETE) + { + while (!_dbus_loop_queue_dispatch (loop, connection)) + _dbus_wait_for_memory (); + } +} + +static void +cdata_free (void *data) +{ + CData *cd = data; + + dbus_connection_unref (cd->connection); + _dbus_loop_unref (cd->loop); + + dbus_free (cd); +} + +static CData* +cdata_new (DBusLoop *loop, + DBusConnection *connection) +{ + CData *cd; + + cd = dbus_new0 (CData, 1); + if (cd == NULL) + return NULL; + + cd->loop = loop; + cd->connection = connection; + + dbus_connection_ref (cd->connection); + _dbus_loop_ref (cd->loop); + + return cd; +} + +dbus_bool_t +test_connection_setup (DBusLoop *loop, + DBusConnection *connection) +{ + CData *cd; + + cd = NULL; + + dbus_connection_set_dispatch_status_function (connection, dispatch_status_function, + loop, NULL); + + cd = cdata_new (loop, connection); + if (cd == NULL) + goto nomem; + + /* Because dbus-mainloop.c checks dbus_timeout_get_enabled(), + * dbus_watch_get_enabled() directly, we don't have to provide + * "toggled" callbacks. + */ + + if (!dbus_connection_set_watch_functions (connection, + add_watch, + remove_watch, + NULL, + cd, cdata_free)) + goto nomem; + + + cd = cdata_new (loop, connection); + if (cd == NULL) + goto nomem; + + if (!dbus_connection_set_timeout_functions (connection, + add_timeout, + remove_timeout, + NULL, + cd, cdata_free)) + goto nomem; + + if (dbus_connection_get_dispatch_status (connection) != DBUS_DISPATCH_COMPLETE) + { + if (!_dbus_loop_queue_dispatch (loop, connection)) + goto nomem; + } + + return TRUE; + + nomem: + if (cd) + cdata_free (cd); + + dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); + dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, NULL, NULL); + dbus_connection_set_timeout_functions (connection, NULL, NULL, NULL, NULL, NULL); + + return FALSE; +} + +void +test_connection_shutdown (DBusLoop *loop, + DBusConnection *connection) +{ + if (!dbus_connection_set_watch_functions (connection, + NULL, + NULL, + NULL, + NULL, NULL)) + _dbus_assert_not_reached ("setting watch functions to NULL failed"); + + if (!dbus_connection_set_timeout_functions (connection, + NULL, + NULL, + NULL, + NULL, NULL)) + _dbus_assert_not_reached ("setting timeout functions to NULL failed"); + + dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); +} + +typedef struct +{ + DBusLoop *loop; + DBusServer *server; +} ServerData; + +static void +serverdata_free (void *data) +{ + ServerData *sd = data; + + dbus_server_unref (sd->server); + _dbus_loop_unref (sd->loop); + + dbus_free (sd); +} + +static ServerData* +serverdata_new (DBusLoop *loop, + DBusServer *server) +{ + ServerData *sd; + + sd = dbus_new0 (ServerData, 1); + if (sd == NULL) + return NULL; + + sd->loop = loop; + sd->server = server; + + dbus_server_ref (sd->server); + _dbus_loop_ref (sd->loop); + + return sd; +} + +static dbus_bool_t +server_watch_callback (DBusWatch *watch, + unsigned int condition, + void *data) +{ + /* FIXME this can be done in dbus-mainloop.c + * if the code in activation.c for the babysitter + * watch handler is fixed. + */ + + return dbus_watch_handle (watch, condition); +} + +static dbus_bool_t +add_server_watch (DBusWatch *watch, + void *data) +{ + ServerData *context = data; + + return _dbus_loop_add_watch (context->loop, + watch, server_watch_callback, context, + NULL); +} + +static void +remove_server_watch (DBusWatch *watch, + void *data) +{ + ServerData *context = data; + + _dbus_loop_remove_watch (context->loop, + watch, server_watch_callback, context); +} + +static void +server_timeout_callback (DBusTimeout *timeout, + void *data) +{ + /* can return FALSE on OOM but we just let it fire again later */ + dbus_timeout_handle (timeout); +} + +static dbus_bool_t +add_server_timeout (DBusTimeout *timeout, + void *data) +{ + ServerData *context = data; + + return _dbus_loop_add_timeout (context->loop, + timeout, server_timeout_callback, context, NULL); +} + +static void +remove_server_timeout (DBusTimeout *timeout, + void *data) +{ + ServerData *context = data; + + _dbus_loop_remove_timeout (context->loop, + timeout, server_timeout_callback, context); +} + +dbus_bool_t +test_server_setup (DBusLoop *loop, + DBusServer *server) +{ + ServerData *sd; + + sd = serverdata_new (loop, server); + if (sd == NULL) + goto nomem; + + if (!dbus_server_set_watch_functions (server, + add_server_watch, + remove_server_watch, + NULL, + sd, + serverdata_free)) + { + return FALSE; + } + + if (!dbus_server_set_timeout_functions (server, + add_server_timeout, + remove_server_timeout, + NULL, + sd, serverdata_free)) + { + return FALSE; + } + return TRUE; + + nomem: + if (sd) + serverdata_free (sd); + + test_server_shutdown (loop, server); + + return FALSE; +} + +void +test_server_shutdown (DBusLoop *loop, + DBusServer *server) +{ + if (!dbus_server_set_watch_functions (server, + NULL, NULL, NULL, + NULL, + NULL)) + _dbus_assert_not_reached ("setting watch functions to NULL failed"); + + if (!dbus_server_set_timeout_functions (server, + NULL, NULL, NULL, + NULL, + NULL)) + _dbus_assert_not_reached ("setting timeout functions to NULL failed"); +} diff --git a/test/test-utils.h b/test/test-utils.h new file mode 100644 index 00000000..90d87767 --- /dev/null +++ b/test/test-utils.h @@ -0,0 +1,26 @@ +#ifndef TEST_UTILS_H +#define TEST_UTILS_H +#include +#ifndef DBUS_COMPILATION +#define DBUS_COMPILATION /* Cheat and use private stuff */ +#endif +#include +#include +#include +#include +#include +#undef DBUS_COMPILATION + +dbus_bool_t test_connection_setup (DBusLoop *loop, + DBusConnection *connection); +void test_connection_shutdown (DBusLoop *loop, + DBusConnection *connection); +void test_connection_dispatch_all_messages (DBusConnection *connection); +dbus_bool_t test_connection_dispatch_one_message (DBusConnection *connection); + +dbus_bool_t test_server_setup (DBusLoop *loop, + DBusServer *server); +void test_server_shutdown (DBusLoop *loop, + DBusServer *server); + +#endif diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 00000000..9fad7a78 --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,47 @@ +configdir=$(sysconfdir)/dbus-1 + +INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_X_CFLAGS) -DDBUS_LOCALEDIR=\"@EXPANDED_DATADIR@/locale\" -DDBUS_COMPILATION -DDBUS_DAEMONDIR=\"@DBUS_DAEMONDIR@\" -DDBUS_MACHINE_UUID_FILE=\""$(localstatedir)/lib/dbus/machine-id"\" + +bin_PROGRAMS=dbus-send dbus-monitor dbus-launch dbus-cleanup-sockets dbus-uuidgen + +dbus_send_SOURCES= \ + dbus-print-message.c \ + dbus-print-message.h \ + dbus-send.c + +dbus_monitor_SOURCES= \ + dbus-monitor.c \ + dbus-print-message.c \ + dbus-print-message.h + +dbus_launch_SOURCES= \ + dbus-launch.c \ + dbus-launch-x11.c \ + dbus-launch.h + +dbus_cleanup_sockets_SOURCES= \ + dbus-cleanup-sockets.c + +dbus_uuidgen_SOURCES= \ + dbus-uuidgen.c + +dbus_send_LDADD= $(top_builddir)/dbus/libdbus-1.la $(DBUS_CLIENT_LIBS) +dbus_send_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +dbus_monitor_LDADD= $(top_builddir)/dbus/libdbus-1.la $(DBUS_CLIENT_LIBS) +dbus_monitor_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +dbus_uuidgen_LDADD= $(top_builddir)/dbus/libdbus-1.la $(DBUS_CLIENT_LIBS) +dbus_uuidgen_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +dbus_launch_LDADD= $(DBUS_X_LIBS) $(DBUS_CLIENT_LIBS) +dbus_launch_LDFLAGS=@R_DYNAMIC_LDFLAG@ + +man_MANS = dbus-send.1 dbus-monitor.1 dbus-launch.1 dbus-cleanup-sockets.1 dbus-uuidgen.1 +EXTRA_DIST = $(man_MANS) run-with-tmp-session-bus.sh +CLEANFILES = \ + run-with-tmp-session-bus.conf + +#create the /var/lib/data directory for dbus-uuidgen +localstatelibdir = $(localstatedir)/lib/dbus +localstatelib_DATA = diff --git a/tools/Makefile.in b/tools/Makefile.in new file mode 100644 index 00000000..14d048bc --- /dev/null +++ b/tools/Makefile.in @@ -0,0 +1,797 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = dbus-send$(EXEEXT) dbus-monitor$(EXEEXT) \ + dbus-launch$(EXEEXT) dbus-cleanup-sockets$(EXEEXT) \ + dbus-uuidgen$(EXEEXT) +subdir = tools +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \ + "$(DESTDIR)$(localstatelibdir)" +PROGRAMS = $(bin_PROGRAMS) +am_dbus_cleanup_sockets_OBJECTS = dbus-cleanup-sockets.$(OBJEXT) +dbus_cleanup_sockets_OBJECTS = $(am_dbus_cleanup_sockets_OBJECTS) +dbus_cleanup_sockets_LDADD = $(LDADD) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am_dbus_launch_OBJECTS = dbus-launch.$(OBJEXT) \ + dbus-launch-x11.$(OBJEXT) +dbus_launch_OBJECTS = $(am_dbus_launch_OBJECTS) +am__DEPENDENCIES_1 = +dbus_launch_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +dbus_launch_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(dbus_launch_LDFLAGS) $(LDFLAGS) -o $@ +am_dbus_monitor_OBJECTS = dbus-monitor.$(OBJEXT) \ + dbus-print-message.$(OBJEXT) +dbus_monitor_OBJECTS = $(am_dbus_monitor_OBJECTS) +dbus_monitor_DEPENDENCIES = $(top_builddir)/dbus/libdbus-1.la \ + $(am__DEPENDENCIES_1) +dbus_monitor_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(dbus_monitor_LDFLAGS) $(LDFLAGS) -o $@ +am_dbus_send_OBJECTS = dbus-print-message.$(OBJEXT) \ + dbus-send.$(OBJEXT) +dbus_send_OBJECTS = $(am_dbus_send_OBJECTS) +dbus_send_DEPENDENCIES = $(top_builddir)/dbus/libdbus-1.la \ + $(am__DEPENDENCIES_1) +dbus_send_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(dbus_send_LDFLAGS) $(LDFLAGS) -o $@ +am_dbus_uuidgen_OBJECTS = dbus-uuidgen.$(OBJEXT) +dbus_uuidgen_OBJECTS = $(am_dbus_uuidgen_OBJECTS) +dbus_uuidgen_DEPENDENCIES = $(top_builddir)/dbus/libdbus-1.la \ + $(am__DEPENDENCIES_1) +dbus_uuidgen_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(dbus_uuidgen_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(dbus_cleanup_sockets_SOURCES) $(dbus_launch_SOURCES) \ + $(dbus_monitor_SOURCES) $(dbus_send_SOURCES) \ + $(dbus_uuidgen_SOURCES) +DIST_SOURCES = $(dbus_cleanup_sockets_SOURCES) $(dbus_launch_SOURCES) \ + $(dbus_monitor_SOURCES) $(dbus_send_SOURCES) \ + $(dbus_uuidgen_SOURCES) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(man_MANS) +DATA = $(localstatelib_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DBUS_BINDIR = @DBUS_BINDIR@ +DBUS_BUS_CFLAGS = @DBUS_BUS_CFLAGS@ +DBUS_BUS_LIBS = @DBUS_BUS_LIBS@ +DBUS_CLIENT_CFLAGS = @DBUS_CLIENT_CFLAGS@ +DBUS_CLIENT_LIBS = @DBUS_CLIENT_LIBS@ +DBUS_CONSOLE_AUTH_DIR = @DBUS_CONSOLE_AUTH_DIR@ +DBUS_CONSOLE_OWNER_FILE = @DBUS_CONSOLE_OWNER_FILE@ +DBUS_DAEMONDIR = @DBUS_DAEMONDIR@ +DBUS_DATADIR = @DBUS_DATADIR@ +DBUS_HAVE_INT64 = @DBUS_HAVE_INT64@ +DBUS_INT16_TYPE = @DBUS_INT16_TYPE@ +DBUS_INT32_TYPE = @DBUS_INT32_TYPE@ +DBUS_INT64_CONSTANT = @DBUS_INT64_CONSTANT@ +DBUS_INT64_TYPE = @DBUS_INT64_TYPE@ +DBUS_LAUNCHER_CFLAGS = @DBUS_LAUNCHER_CFLAGS@ +DBUS_LAUNCHER_LIBS = @DBUS_LAUNCHER_LIBS@ +DBUS_LIBEXECDIR = @DBUS_LIBEXECDIR@ +DBUS_MAJOR_VERSION = @DBUS_MAJOR_VERSION@ +DBUS_MICRO_VERSION = @DBUS_MICRO_VERSION@ +DBUS_MINOR_VERSION = @DBUS_MINOR_VERSION@ +DBUS_PATH_OR_ABSTRACT = @DBUS_PATH_OR_ABSTRACT@ +DBUS_SESSION_SOCKET_DIR = @DBUS_SESSION_SOCKET_DIR@ +DBUS_SYSTEM_BUS_DEFAULT_ADDRESS = @DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@ +DBUS_SYSTEM_PID_FILE = @DBUS_SYSTEM_PID_FILE@ +DBUS_SYSTEM_SOCKET = @DBUS_SYSTEM_SOCKET@ +DBUS_TEST_CFLAGS = @DBUS_TEST_CFLAGS@ +DBUS_TEST_LIBS = @DBUS_TEST_LIBS@ +DBUS_UINT64_CONSTANT = @DBUS_UINT64_CONSTANT@ +DBUS_USER = @DBUS_USER@ +DBUS_VERSION = @DBUS_VERSION@ +DBUS_X_CFLAGS = @DBUS_X_CFLAGS@ +DBUS_X_LIBS = @DBUS_X_LIBS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXPANDED_BINDIR = @EXPANDED_BINDIR@ +EXPANDED_DATADIR = @EXPANDED_DATADIR@ +EXPANDED_LIBDIR = @EXPANDED_LIBDIR@ +EXPANDED_LIBEXECDIR = @EXPANDED_LIBEXECDIR@ +EXPANDED_LOCALSTATEDIR = @EXPANDED_LOCALSTATEDIR@ +EXPANDED_SYSCONFDIR = @EXPANDED_SYSCONFDIR@ +FGREP = @FGREP@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML_CFLAGS = @LIBXML_CFLAGS@ +LIBXML_LIBS = @LIBXML_LIBS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_AGE = @LT_AGE@ +LT_CURRENT = @LT_CURRENT@ +LT_REVISION = @LT_REVISION@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIC_CFLAGS = @PIC_CFLAGS@ +PIC_LDFLAGS = @PIC_LDFLAGS@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +R_DYNAMIC_LDFLAG = @R_DYNAMIC_LDFLAG@ +SECTION_FLAGS = @SECTION_FLAGS@ +SECTION_LDFLAGS = @SECTION_LDFLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TEST_BUS_BINARY = @TEST_BUS_BINARY@ +TEST_EXIT_BINARY = @TEST_EXIT_BINARY@ +TEST_INVALID_SERVICE_DIR = @TEST_INVALID_SERVICE_DIR@ +TEST_INVALID_SERVICE_SYSTEM_DIR = @TEST_INVALID_SERVICE_SYSTEM_DIR@ +TEST_LAUNCH_HELPER_BINARY = @TEST_LAUNCH_HELPER_BINARY@ +TEST_PRIVSERVER_BINARY = @TEST_PRIVSERVER_BINARY@ +TEST_SEGFAULT_BINARY = @TEST_SEGFAULT_BINARY@ +TEST_SERVICE_BINARY = @TEST_SERVICE_BINARY@ +TEST_SHELL_SERVICE_BINARY = @TEST_SHELL_SERVICE_BINARY@ +TEST_SLEEP_FOREVER_BINARY = @TEST_SLEEP_FOREVER_BINARY@ +TEST_SOCKET_DIR = @TEST_SOCKET_DIR@ +TEST_VALID_SERVICE_DIR = @TEST_VALID_SERVICE_DIR@ +TEST_VALID_SERVICE_SYSTEM_DIR = @TEST_VALID_SERVICE_SYSTEM_DIR@ +VERSION = @VERSION@ +XMKMF = @XMKMF@ +XMLTO = @XMLTO@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +configdir = $(sysconfdir)/dbus-1 +INCLUDES = -I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_X_CFLAGS) -DDBUS_LOCALEDIR=\"@EXPANDED_DATADIR@/locale\" -DDBUS_COMPILATION -DDBUS_DAEMONDIR=\"@DBUS_DAEMONDIR@\" -DDBUS_MACHINE_UUID_FILE=\""$(localstatedir)/lib/dbus/machine-id"\" +dbus_send_SOURCES = \ + dbus-print-message.c \ + dbus-print-message.h \ + dbus-send.c + +dbus_monitor_SOURCES = \ + dbus-monitor.c \ + dbus-print-message.c \ + dbus-print-message.h + +dbus_launch_SOURCES = \ + dbus-launch.c \ + dbus-launch-x11.c \ + dbus-launch.h + +dbus_cleanup_sockets_SOURCES = \ + dbus-cleanup-sockets.c + +dbus_uuidgen_SOURCES = \ + dbus-uuidgen.c + +dbus_send_LDADD = $(top_builddir)/dbus/libdbus-1.la $(DBUS_CLIENT_LIBS) +dbus_send_LDFLAGS = @R_DYNAMIC_LDFLAG@ +dbus_monitor_LDADD = $(top_builddir)/dbus/libdbus-1.la $(DBUS_CLIENT_LIBS) +dbus_monitor_LDFLAGS = @R_DYNAMIC_LDFLAG@ +dbus_uuidgen_LDADD = $(top_builddir)/dbus/libdbus-1.la $(DBUS_CLIENT_LIBS) +dbus_uuidgen_LDFLAGS = @R_DYNAMIC_LDFLAG@ +dbus_launch_LDADD = $(DBUS_X_LIBS) $(DBUS_CLIENT_LIBS) +dbus_launch_LDFLAGS = @R_DYNAMIC_LDFLAG@ +man_MANS = dbus-send.1 dbus-monitor.1 dbus-launch.1 dbus-cleanup-sockets.1 dbus-uuidgen.1 +EXTRA_DIST = $(man_MANS) run-with-tmp-session-bus.sh +CLEANFILES = \ + run-with-tmp-session-bus.conf + + +#create the /var/lib/data directory for dbus-uuidgen +localstatelibdir = $(localstatedir)/lib/dbus +localstatelib_DATA = +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tools/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu tools/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +dbus-cleanup-sockets$(EXEEXT): $(dbus_cleanup_sockets_OBJECTS) $(dbus_cleanup_sockets_DEPENDENCIES) + @rm -f dbus-cleanup-sockets$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(dbus_cleanup_sockets_OBJECTS) $(dbus_cleanup_sockets_LDADD) $(LIBS) +dbus-launch$(EXEEXT): $(dbus_launch_OBJECTS) $(dbus_launch_DEPENDENCIES) + @rm -f dbus-launch$(EXEEXT) + $(AM_V_CCLD)$(dbus_launch_LINK) $(dbus_launch_OBJECTS) $(dbus_launch_LDADD) $(LIBS) +dbus-monitor$(EXEEXT): $(dbus_monitor_OBJECTS) $(dbus_monitor_DEPENDENCIES) + @rm -f dbus-monitor$(EXEEXT) + $(AM_V_CCLD)$(dbus_monitor_LINK) $(dbus_monitor_OBJECTS) $(dbus_monitor_LDADD) $(LIBS) +dbus-send$(EXEEXT): $(dbus_send_OBJECTS) $(dbus_send_DEPENDENCIES) + @rm -f dbus-send$(EXEEXT) + $(AM_V_CCLD)$(dbus_send_LINK) $(dbus_send_OBJECTS) $(dbus_send_LDADD) $(LIBS) +dbus-uuidgen$(EXEEXT): $(dbus_uuidgen_OBJECTS) $(dbus_uuidgen_DEPENDENCIES) + @rm -f dbus-uuidgen$(EXEEXT) + $(AM_V_CCLD)$(dbus_uuidgen_LINK) $(dbus_uuidgen_OBJECTS) $(dbus_uuidgen_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-cleanup-sockets.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-launch-x11.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-launch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-monitor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-print-message.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-send.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-uuidgen.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man1: $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" + @list=''; test -n "$(man1dir)" || exit 0; \ + { for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list=''; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ + sed -n '/\.1[a-z]*$$/p'; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + test -z "$$files" || { \ + echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(man1dir)" && rm -f $$files; } +install-localstatelibDATA: $(localstatelib_DATA) + @$(NORMAL_INSTALL) + test -z "$(localstatelibdir)" || $(MKDIR_P) "$(DESTDIR)$(localstatelibdir)" + @list='$(localstatelib_DATA)'; test -n "$(localstatelibdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(localstatelibdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(localstatelibdir)" || exit $$?; \ + done + +uninstall-localstatelibDATA: + @$(NORMAL_UNINSTALL) + @list='$(localstatelib_DATA)'; test -n "$(localstatelibdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(localstatelibdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(localstatelibdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @list='$(MANS)'; if test -n "$$list"; then \ + list=`for p in $$list; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ + if test -n "$$list" && \ + grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ + echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ + grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ + echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ + echo " typically \`make maintainer-clean' will remove them" >&2; \ + exit 1; \ + else :; fi; \ + else :; fi + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(MANS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(localstatelibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-localstatelibDATA install-man + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man1 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-localstatelibDATA \ + uninstall-man + +uninstall-man: uninstall-man1 + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-localstatelibDATA install-man install-man1 install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-localstatelibDATA uninstall-man uninstall-man1 + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tools/dbus-cleanup-sockets.1 b/tools/dbus-cleanup-sockets.1 new file mode 100644 index 00000000..ca669f49 --- /dev/null +++ b/tools/dbus-cleanup-sockets.1 @@ -0,0 +1,43 @@ +.\" +.\" dbus-cleanup-sockets manual page. +.\" Copyright (C) 2003 Red Hat, Inc. +.\" +.TH dbus-cleanup-sockets 1 +.SH NAME +dbus-cleanup-sockets \- clean up leftover sockets in a directory +.SH SYNOPSIS +.PP +.B dbus-cleanup-sockets [DIRECTORY] + +.SH DESCRIPTION + +The \fIdbus-cleanup-sockets\fP command cleans up unused D-Bus +connection sockets. See http://www.freedesktop.org/software/dbus/ for +more information about the big picture. + +.PP +If given no arguments, \fIdbus-cleanup-sockets\fP cleans up sockets +in the standard default socket directory for the +per-user-login-session message bus; this is usually /tmp. +Optionally, you can pass a different directory on the command line. + +.PP +On Linux, this program is essentially useless, because D-Bus defaults +to using "abstract sockets" that exist only in memory and don't have a +corresponding file in /tmp. + +.PP +On most other flavors of UNIX, it's possible for the socket files to +leak when programs using D-Bus exit abnormally or without closing +their D-Bus connections. Thus, it might be interesting to run +dbus-cleanup-sockets in a cron job to mop up any leaked sockets. +Or you can just ignore the leaked sockets, they aren't really hurting +anything, other than cluttering the output of "ls /tmp" + +.SH AUTHOR +dbus-cleanup-sockets was adapted by Havoc Pennington from +linc-cleanup-sockets written by Michael Meeks. + +.SH BUGS +Please send bug reports to the D-Bus mailing list or bug tracker, +see http://www.freedesktop.org/software/dbus/ diff --git a/tools/dbus-cleanup-sockets.c b/tools/dbus-cleanup-sockets.c new file mode 100644 index 00000000..487c4b07 --- /dev/null +++ b/tools/dbus-cleanup-sockets.c @@ -0,0 +1,431 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-cleanup-sockets.c dbus-cleanup-sockets utility + * + * Copyright (C) 2003 Red Hat, Inc. + * Copyright (C) 2002 Michael Meeks + * + * Note that this file is NOT licensed under the Academic Free License, + * as it is based on linc-cleanup-sockets which is LGPL. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef NULL +#define NULL ((void*) 0) +#endif + +static void* +xmalloc (size_t bytes) +{ + void *mem; + + if (bytes == 0) + return NULL; + + mem = malloc (bytes); + + if (mem == NULL) + { + fprintf (stderr, "Allocation of %d bytes failed\n", + (int) bytes); + exit (1); + } + + return mem; +} + +static void* +xrealloc (void *old, size_t bytes) +{ + void *mem; + + if (bytes == 0) + { + free (old); + return NULL; + } + + mem = realloc (old, bytes); + + if (mem == NULL) + { + fprintf (stderr, "Reallocation of %d bytes failed\n", + (int) bytes); + exit (1); + } + + return mem; +} + +#ifdef AF_UNIX + +typedef enum + { + SOCKET_UNKNOWN, + SOCKET_FAILED_TO_HANDLE, + SOCKET_DEAD, + SOCKET_ALIVE, + SOCKET_UNLINKED + } SocketStatus; + +static int alive_count = 0; +static int cleaned_count = 0; +static int unhandled_count = 0; + +typedef struct +{ + char *name; + int fd; + SocketStatus status; + int n_retries; +} SocketEntry; + +static SocketEntry* +socket_entry_new (const char *dir, + const char *fname) +{ + SocketEntry *se; + int len; + + se = xmalloc (sizeof (SocketEntry)); + + len = strlen (dir) + strlen (fname) + 2; /* 2 = nul and '/' */ + se->name = xmalloc (len); + + strcpy (se->name, dir); + strcat (se->name, "/"); + strcat (se->name, fname); + + se->fd = -1; + + se->status = SOCKET_UNKNOWN; + + se->n_retries = 0; + + return se; +} + +#if 0 +static void +free_socket_entry (SocketEntry *se) +{ + free (se->name); + if (se->fd >= 0) + close (se->fd); + free (se); +} +#endif + +static void +read_sockets (const char *dir, + SocketEntry ***entries_p, + int *n_entries_p) +{ + DIR *dirh; + struct dirent *dent; + SocketEntry **entries; + int n_entries; + int allocated; + + n_entries = 0; + allocated = 2; + entries = xmalloc (sizeof (SocketEntry*) * allocated); + + dirh = opendir (dir); + if (dirh == NULL) + { + fprintf (stderr, "Failed to open directory %s: %s\n", + dir, strerror (errno)); + exit (1); + } + + while ((dent = readdir (dirh))) + { + SocketEntry *se; + + if (strncmp (dent->d_name, "dbus-", 5) != 0) + continue; + + se = socket_entry_new (dir, dent->d_name); + + if (n_entries == allocated) + { + allocated *= 2; + entries = xrealloc (entries, sizeof (SocketEntry*) * allocated); + } + + entries[n_entries] = se; + n_entries += 1; + } + + closedir (dirh); + + *entries_p = entries; + *n_entries_p = n_entries; +} + +static SocketStatus +open_socket (SocketEntry *se) +{ + int ret; + struct sockaddr_un saddr; + + if (se->n_retries > 5) + { + fprintf (stderr, "Warning: giving up on socket %s after several retries; unable to determine socket's status\n", + se->name); + return SOCKET_FAILED_TO_HANDLE; + } + + se->n_retries += 1; + + se->fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (se->fd < 0) + { + fprintf (stderr, "Warning: failed to open a socket to use for connecting: %s\n", + strerror (errno)); + return SOCKET_UNKNOWN; + } + + if (fcntl (se->fd, F_SETFL, O_NONBLOCK) < 0) + { + fprintf (stderr, "Warning: failed set socket %s nonblocking: %s\n", + se->name, strerror (errno)); + return SOCKET_UNKNOWN; + } + + + memset (&saddr, '\0', sizeof (saddr)); /* nul-terminates the sun_path */ + + saddr.sun_family = AF_UNIX; + strncpy (saddr.sun_path, se->name, sizeof (saddr.sun_path) - 1); + + do + { + ret = connect (se->fd, (struct sockaddr*) &saddr, sizeof (saddr)); + } + while (ret < 0 && errno == EINTR); + + if (ret >= 0) + return SOCKET_ALIVE; + else + { + switch (errno) + { + case EINPROGRESS: + case EAGAIN: + return SOCKET_UNKNOWN; + case ECONNREFUSED: + return SOCKET_DEAD; + default: + fprintf (stderr, "Warning: unexpected error connecting to socket %s: %s\n", + se->name, strerror (errno)); + return SOCKET_FAILED_TO_HANDLE; + } + } +} + +static int +handle_sockets (SocketEntry **entries, + int n_entries) +{ + int i; + int n_unknown; + + n_unknown = 0; + + i = 0; + while (i < n_entries) + { + SocketEntry *se; + SocketStatus status; + + se = entries[i]; + ++i; + + if (se->fd >= 0) + { + fprintf (stderr, "Internal error, socket has fd kept open while status = %d\n", + se->status); + exit (1); + } + + if (se->status != SOCKET_UNKNOWN) + continue; + + status = open_socket (se); + + switch (status) + { + case SOCKET_DEAD: + cleaned_count += 1; + if (unlink (se->name) < 0) + { + fprintf (stderr, "Warning: Failed to delete %s: %s\n", + se->name, strerror (errno)); + + se->status = SOCKET_FAILED_TO_HANDLE; + } + else + se->status = SOCKET_UNLINKED; + break; + + case SOCKET_ALIVE: + alive_count += 1; + /* FALL THRU */ + + case SOCKET_FAILED_TO_HANDLE: + case SOCKET_UNKNOWN: + se->status = status; + break; + + case SOCKET_UNLINKED: + fprintf (stderr, "Bad status from open_socket(), should not happen\n"); + exit (1); + break; + } + + if (se->fd >= 0) + { + close (se->fd); + se->fd = -1; + } + + if (se->status == SOCKET_UNKNOWN) + n_unknown += 1; + } + + return n_unknown == 0; +} + +static void +clean_dir (const char *dir) +{ + SocketEntry **entries; + int n_entries; + + read_sockets (dir, &entries, &n_entries); + + /* open_socket() will fail conclusively after + * several retries, so this loop is guaranteed + * to terminate eventually + */ + while (!handle_sockets (entries, n_entries)) + { + fprintf (stderr, "Unable to determine state of some sockets, retrying in 2 seconds\n"); + sleep (2); + } + + unhandled_count += (n_entries - alive_count - cleaned_count); +} + +#endif /* AF_UNIX */ + +static void +usage (int ecode) +{ + fprintf (stderr, "dbus-cleanup-sockets [--version] [--help] \n"); + exit (ecode); +} + +static void +version (void) +{ + printf ("D-Bus Socket Cleanup Utility %s\n" + "Copyright (C) 2003 Red Hat, Inc.\n" + "Copyright (C) 2002 Michael Meeks\n" + "This is free software; see the source for copying conditions.\n" + "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", + VERSION); + exit (0); +} + +int +main (int argc, char **argv) +{ + int i; + int saw_doubledash; + const char *dirname; + + saw_doubledash = FALSE; + dirname = NULL; + i = 1; + while (i < argc) + { + const char *arg = argv[i]; + + if (strcmp (arg, "--help") == 0 || + strcmp (arg, "-h") == 0 || + strcmp (arg, "-?") == 0) + usage (0); + else if (strcmp (arg, "--version") == 0) + version (); + else if (!saw_doubledash) + { + if (strcmp (arg, "--") == 0) + saw_doubledash = TRUE; + else if (*arg == '-') + usage (1); + } + else + { + if (dirname != NULL) + { + fprintf (stderr, "dbus-cleanup-sockets only supports a single directory name\n"); + exit (1); + } + + dirname = arg; + } + + ++i; + } + + /* Default to session socket dir, usually /tmp */ + if (dirname == NULL) + dirname = DBUS_SESSION_SOCKET_DIR; + +#ifdef AF_UNIX + clean_dir (dirname); + + printf ("Cleaned up %d sockets in %s; %d sockets are still in use; %d in unknown state\n", + cleaned_count, dirname, alive_count, unhandled_count); +#else + printf ("This system does not support UNIX domain sockets, so dbus-cleanup-sockets does nothing\n"); +#endif + + return 0; +} diff --git a/tools/dbus-launch-x11.c b/tools/dbus-launch-x11.c new file mode 100644 index 00000000..56d7f744 --- /dev/null +++ b/tools/dbus-launch-x11.c @@ -0,0 +1,463 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-launch.h dbus-launch utility + * + * Copyright (C) 2006 Thiago Macieira + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-launch.h" + +#ifdef DBUS_BUILD_X11 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Display *xdisplay = NULL; +static Atom selection_atom; +static Atom address_atom; +static Atom pid_atom; + +static int +x_io_error_handler (Display *xdisplay) +{ + verbose ("X IO error\n"); + kill_bus_and_exit (0); + return 0; +} + +static void +remove_prefix (char *s, + char *prefix) +{ + int plen; + + plen = strlen (prefix); + + if (strncmp (s, prefix, plen) == 0) + { + memmove (s, s + plen, strlen (s) - plen + 1); + } +} + +static const char* +get_homedir (void) +{ + const char *home; + + home = getenv ("HOME"); + if (home == NULL) + { + /* try from the user database */ + struct passwd *user = getpwuid (getuid()); + if (user != NULL) + home = user->pw_dir; + } + + if (home == NULL) + { + fprintf (stderr, "Can't get user home directory\n"); + exit (1); + } + + return home; +} + +#define DBUS_DIR ".dbus" +#define DBUS_SESSION_BUS_DIR "session-bus" + +static char * +get_session_file (void) +{ + static const char prefix[] = "/" DBUS_DIR "/" DBUS_SESSION_BUS_DIR "/"; + const char *machine; + const char *home; + char *display; + char *result; + char *p; + + machine = get_machine_uuid (); + if (machine == NULL) + return NULL; + + display = xstrdup (getenv ("DISPLAY")); + if (display == NULL) + { + verbose ("X11 integration disabled because X11 is not running\n"); + return NULL; + } + + /* remove the screen part of the display name */ + p = strrchr (display, ':'); + if (p != NULL) + { + for ( ; *p; ++p) + { + if (*p == '.') + { + *p = '\0'; + break; + } + } + } + + /* Note that we leave the hostname in the display most of the + * time. The idea is that we want to be per-(machine,display,user) + * triplet to be extra-sure we get a bus we can connect to. Ideally + * we'd recognize when the hostname matches the machine we're on in + * all cases; we do try to drop localhost and localhost.localdomain + * as a special common case so that alternate spellings of DISPLAY + * don't result in extra bus instances. + * + * We also kill the ":" if there's nothing in front of it. This + * avoids an ugly double underscore in the filename. + */ + remove_prefix (display, "localhost.localdomain:"); + remove_prefix (display, "localhost:"); + remove_prefix (display, ":"); + + /* replace the : in the display with _ if the : is still there. + * use _ instead of - since it can't be in hostnames. + */ + for (p = display; *p; ++p) + { + if (*p == ':') + *p = '_'; + } + + home = get_homedir (); + + result = malloc (strlen (home) + strlen (prefix) + strlen (machine) + + strlen (display) + 2); + if (result == NULL) + { + /* out of memory */ + free (display); + return NULL; + } + + strcpy (result, home); + strcat (result, prefix); + strcat (result, machine); + strcat (result, "-"); + strcat (result, display); + free (display); + + verbose ("session file: %s\n", result); + return result; +} + +static void +ensure_session_directory (void) +{ + const char *home; + char *dir; + + home = get_homedir (); + + /* be sure we have space for / and nul */ + dir = malloc (strlen (home) + strlen (DBUS_DIR) + strlen (DBUS_SESSION_BUS_DIR) + 3); + if (dir == NULL) + { + fprintf (stderr, "no memory\n"); + exit (1); + } + + strcpy (dir, home); + strcat (dir, "/"); + strcat (dir, DBUS_DIR); + + if (mkdir (dir, 0700) < 0) + { + /* only print a warning here, writing the session file itself will fail later */ + if (errno != EEXIST) + fprintf (stderr, "Unable to create %s\n", dir); + } + + strcat (dir, "/"); + strcat (dir, DBUS_SESSION_BUS_DIR); + + if (mkdir (dir, 0700) < 0) + { + /* only print a warning here, writing the session file itself will fail later */ + if (errno != EEXIST) + fprintf (stderr, "Unable to create %s\n", dir); + } + + free (dir); +} + +static Display * +open_x11 (void) +{ + if (xdisplay != NULL) + return xdisplay; + + xdisplay = XOpenDisplay (NULL); + if (xdisplay != NULL) + { + verbose ("Connected to X11 display '%s'\n", DisplayString (xdisplay)); + XSetIOErrorHandler (x_io_error_handler); + } + return xdisplay; +} + +static int +init_x_atoms (Display *display) +{ + static const char selection_prefix[] = "_DBUS_SESSION_BUS_SELECTION_"; + static const char address_prefix[] = "_DBUS_SESSION_BUS_ADDRESS"; + static const char pid_prefix[] = "_DBUS_SESSION_BUS_PID"; + static int init = FALSE; + char *atom_name; + const char *machine; + char *user_name; + struct passwd *user; + + if (init) + return TRUE; + + machine = get_machine_uuid (); + if (machine == NULL) + return FALSE; + + user = getpwuid (getuid ()); + if (user == NULL) + { + verbose ("Could not determine the user informations; aborting X11 integration.\n"); + return FALSE; + } + user_name = xstrdup(user->pw_name); + + atom_name = malloc (strlen (machine) + strlen (user_name) + 2 + + MAX (strlen (selection_prefix), + MAX (strlen (address_prefix), + strlen (pid_prefix)))); + if (atom_name == NULL) + { + verbose ("Could not create X11 atoms; aborting X11 integration.\n"); + free (user_name); + return FALSE; + } + + /* create the selection atom */ + strcpy (atom_name, selection_prefix); + strcat (atom_name, user_name); + strcat (atom_name, "_"); + strcat (atom_name, machine); + selection_atom = XInternAtom (display, atom_name, FALSE); + + /* create the address property atom */ + strcpy (atom_name, address_prefix); + address_atom = XInternAtom (display, atom_name, FALSE); + + /* create the PID property atom */ + strcpy (atom_name, pid_prefix); + pid_atom = XInternAtom (display, atom_name, FALSE); + + free (atom_name); + free (user_name); + init = TRUE; + return TRUE; +} + +/* + * Gets the daemon address from the X11 display. + * Returns FALSE if there was an error. Returning + * TRUE does not mean the address exists. + */ +int +x11_get_address (char **paddress, pid_t *pid, long *wid) +{ + Atom type; + Window owner; + int format; + unsigned long items; + unsigned long after; + char *data; + + *paddress = NULL; + + /* locate the selection owner */ + owner = XGetSelectionOwner (xdisplay, selection_atom); + if (owner == None) + return TRUE; /* no owner */ + if (wid != NULL) + *wid = (long) owner; + + /* get the bus address */ + XGetWindowProperty (xdisplay, owner, address_atom, 0, 1024, False, + XA_STRING, &type, &format, &items, &after, + (unsigned char **) &data); + if (type == None || after != 0 || data == NULL || format != 8) + return FALSE; /* error */ + + *paddress = xstrdup (data); + XFree (data); + + /* get the PID */ + if (pid != NULL) + { + *pid = 0; + XGetWindowProperty (xdisplay, owner, pid_atom, 0, sizeof pid, False, + XA_CARDINAL, &type, &format, &items, &after, + (unsigned char **) &data); + if (type != None && after == 0 && data != NULL && format == 32) + *pid = (pid_t) *(long*) data; + XFree (data); + } + + return TRUE; /* success */ +} + +/* + * Saves the address in the X11 display. Returns 0 on success. + * If an error occurs, returns -1. If the selection already exists, + * returns 1. (i.e. another daemon is already running) + */ +static Window +set_address_in_x11(char *address, pid_t pid) +{ + char *current_address; + Window wid = None; + unsigned long pid32; /* Xlib property functions want _long_ not 32-bit for format "32" */ + + /* lock the X11 display to make sure we're doing this atomically */ + XGrabServer (xdisplay); + + if (!x11_get_address (¤t_address, NULL, NULL)) + { + /* error! */ + goto out; + } + + if (current_address != NULL) + { + /* someone saved the address in the meantime */ + free (current_address); + goto out; + } + + /* Create our window */ + wid = XCreateWindow (xdisplay, RootWindow (xdisplay, 0), -20, -20, 10, 10, + 0, CopyFromParent, InputOnly, CopyFromParent, + 0, NULL); + verbose ("Created window %d\n", wid); + + /* Save the property in the window */ + XChangeProperty (xdisplay, wid, address_atom, XA_STRING, 8, PropModeReplace, + (unsigned char *)address, strlen (address)); + pid32 = pid; + XChangeProperty (xdisplay, wid, pid_atom, XA_CARDINAL, 32, PropModeReplace, + (unsigned char *)&pid32, 1); + + /* Now grab the selection */ + XSetSelectionOwner (xdisplay, selection_atom, wid, CurrentTime); + + out: + /* Ungrab the server to let other people use it too */ + XUngrabServer (xdisplay); + + /* And make sure that the ungrab gets sent to X11 */ + XFlush (xdisplay); + + return wid; +} + +/* + * Saves the session address in session file. Returns TRUE on + * success, FALSE if an error occurs. + */ +static int +set_address_in_file (char *address, pid_t pid, Window wid) +{ + char *session_file; + FILE *f; + + ensure_session_directory (); + session_file = get_session_file(); + if (session_file == NULL) + return FALSE; + + f = fopen (session_file, "w"); + if (f == NULL) + return FALSE; /* some kind of error */ + fprintf (f, + "# This file allows processes on the machine with id %s using \n" + "# display %s to find the D-Bus session bus with the below address.\n" + "# If the DBUS_SESSION_BUS_ADDRESS environment variable is set, it will\n" + "# be used rather than this file.\n" + "# See \"man dbus-launch\" for more details.\n" + "DBUS_SESSION_BUS_ADDRESS=%s\n" + "DBUS_SESSION_BUS_PID=%ld\n" + "DBUS_SESSION_BUS_WINDOWID=%ld\n", + get_machine_uuid (), + getenv ("DISPLAY"), + address, (long)pid, (long)wid); + + fclose (f); + free (session_file); + + return TRUE; +} + +int +x11_save_address (char *address, pid_t pid, long *wid) +{ + Window id = set_address_in_x11 (address, pid); + if (id != None) + { + if (!set_address_in_file (address, pid, id)) + return FALSE; + + if (wid != NULL) + *wid = (long) id; + return TRUE; + } + return FALSE; +} + +int +x11_init (void) +{ + return open_x11 () != NULL && init_x_atoms (xdisplay); +} + +void +x11_handle_event (void) +{ + if (xdisplay != NULL) + { + while (XPending (xdisplay)) + { + XEvent ignored; + XNextEvent (xdisplay, &ignored); + } + } +} + +#else +void dummy_dbus_launch_x11 (void) { } +#endif diff --git a/tools/dbus-launch.1 b/tools/dbus-launch.1 new file mode 100644 index 00000000..0ea19495 --- /dev/null +++ b/tools/dbus-launch.1 @@ -0,0 +1,183 @@ +.\" +.\" dbus-launch manual page. +.\" Copyright (C) 2003 Red Hat, Inc. +.\" +.TH dbus-launch 1 +.SH NAME +dbus-launch \- Utility to start a message bus from a shell script +.SH SYNOPSIS +.PP +.B dbus-launch [\-\-version] [\-\-sh-syntax] [\-\-csh-syntax] [\-\-auto-syntax] [\-\-exit-with-session] [\-\-autolaunch=MACHINEID] [\-\-config-file=FILENAME] [PROGRAM] [ARGS...] + +.SH DESCRIPTION + +The \fIdbus-launch\fP command is used to start a session bus +instance of \fIdbus-daemon\fP from a shell script. +It would normally be called from a user's login +scripts. Unlike the daemon itself, \fIdbus-launch\fP exits, so +backticks or the $() construct can be used to read information from +\fIdbus-launch\fP. + +With no arguments, \fIdbus-launch\fP will launch a session bus +instance and print the address and pid of that instance to standard +output. + +You may specify a program to be run; in this case, \fIdbus-launch\fP +will launch a session bus instance, set the appropriate environment +variables so the specified program can find the bus, and then execute the +specified program, with the specified arguments. See below for +examples. + +If you launch a program, \fIdbus-launch\fP will not print the +information about the new bus to standard output. + +When \fIdbus-launch\fP prints bus information to standard output, by +default it is in a simple key-value pairs format. However, you may +request several alternate syntaxes using the \-\-sh-syntax, \-\-csh-syntax, +\-\-binary-syntax, or +\-\-auto-syntax options. Several of these cause \fIdbus-launch\fP to emit shell code +to set up the environment. + +With the \-\-auto-syntax option, \fIdbus-launch\fP looks at the value +of the SHELL environment variable to determine which shell syntax +should be used. If SHELL ends in "csh", then csh-compatible code is +emitted; otherwise Bourne shell code is emitted. Instead of passing +\-\-auto-syntax, you may explicity specify a particular one by using +\-\-sh-syntax for Bourne syntax, or \-\-csh-syntax for csh syntax. +In scripts, it's more robust to avoid \-\-auto-syntax and you hopefully +know which shell your script is written in. + +.PP +See http://www.freedesktop.org/software/dbus/ for more information +about D-Bus. See also the man page for \fIdbus-daemon\fP. + +.PP +Here is an example of how to use \fIdbus-launch\fP with an +sh-compatible shell to start the per-session bus daemon: +.nf + + ## test for an existing bus daemon, just to be safe + if test -z "$DBUS_SESSION_BUS_ADDRESS" ; then + ## if not found, launch a new one + eval `dbus-launch --sh-syntax --exit-with-session` + echo "D-Bus per-session daemon address is: $DBUS_SESSION_BUS_ADDRESS" + fi + +.fi +You might run something like that in your login scripts. + +.PP +Another way to use \fIdbus-launch\fP is to run your main session +program, like so: +.nf + +dbus-launch gnome-session + +.fi +The above would likely be appropriate for ~/.xsession or ~/.Xclients. + +.SH AUTOMATIC LAUNCHING + +.PP +If DBUS_SESSION_BUS_ADDRESS is not set for a process that tries to use +D-Bus, by default the process will attempt to invoke dbus-launch with +the --autolaunch option to start up a new session bus or find the +existing bus address on the X display or in a file in +~/.dbus/session-bus/ + +.PP +Whenever an autolaunch occurs, the application that had to +start a new bus will be in its own little world; it can effectively +end up starting a whole new session if it tries to use a lot of +bus services. This can be suboptimal or even totally broken, depending +on the app and what it tries to do. + +.PP +There are two common reasons for autolaunch. One is ssh to a remote +machine. The ideal fix for that would be forwarding of +DBUS_SESSION_BUS_ADDRESS in the same way that DISPLAY is forwarded. +In the meantime, you can edit the session.conf config file to +have your session bus listen on TCP, and manually set +DBUS_SESSION_BUS_ADDRESS, if you like. + +.PP +The second common reason for autolaunch is an su to another user, and +display of X applications running as the second user on the display +belonging to the first user. Perhaps the ideal fix in this case +would be to allow the second user to connect to the session bus of the +first user, just as they can connect to the first user's display. +However, a mechanism for that has not been coded. + +.PP +You can always avoid autolaunch by manually setting +DBUS_SESSION_BUS_ADDRESS. Autolaunch happens because the default +address if none is set is "autolaunch:", so if any other address is +set there will be no autolaunch. You can however include autolaunch in +an explicit session bus address as a fallback, for example +DBUS_SESSION_BUS_ADDRESS="something:,autolaunch:" - in that case if +the first address doesn't work, processes will autolaunch. (The bus +address variable contains a comma-separated list of addresses to try.) + +.PP +The --autolaunch option is considered an internal implementation +detail of libdbus, and in fact there are plans to change it. There's +no real reason to use it outside of the libdbus implementation anyhow. + +.SH OPTIONS +The following options are supported: +.TP +.I "--auto-syntax" +Choose \-\-csh-syntax or \-\-sh-syntax based on the SHELL environment variable. + +.I "--binary-syntax" +Write to stdout a nul-terminated bus address, then the bus PID as a +binary integer of size sizeof(pid_t), then the bus X window ID as a +binary integer of size sizeof(long). Integers are in the machine's +byte order, not network byte order or any other canonical byte order. + +.TP +.I "--close-stderr" +Close the standard error output stream before starting the D-Bus +daemon. This is useful if you want to capture dbus-launch error +messages but you don't want dbus-daemon to keep the stream open to +your application. + +.TP +.I "--config-file=FILENAME" +Pass \-\-config-file=FILENAME to the bus daemon, instead of passing it +the \-\-session argument. See the man page for dbus-daemon + +.TP +.I "--csh-syntax" +Emit csh compatible code to set up environment variables. + +.TP +.I "--exit-with-session" +If this option is provided, a persistent "babysitter" process will be +created that watches stdin for HUP and tries to connect to the X +server. If this process gets a HUP on stdin or loses its X connection, +it kills the message bus daemon. + +.TP +.I "--autolaunch=MACHINEID" +This option implies that \fIdbus-launch\fP should scan for a +previously-started session and reuse the values found there. If no +session is found, it will start a new session. The +\-\-exit-with-session option is implied if \-\-autolaunch is given. +This option is for the exclusive use of libdbus, you do not want to +use it manually. It may change in the future. + +.TP +.I "--sh-syntax" +Emit Bourne-shell compatible code to set up environment variables. + +.TP +.I "--version" +Print the version of dbus-launch + +.SH AUTHOR +See http://www.freedesktop.org/software/dbus/doc/AUTHORS + +.SH BUGS +Please send bug reports to the D-Bus mailing list or bug tracker, +see http://www.freedesktop.org/software/dbus/ diff --git a/tools/dbus-launch.c b/tools/dbus-launch.c new file mode 100644 index 00000000..d3553e81 --- /dev/null +++ b/tools/dbus-launch.c @@ -0,0 +1,1214 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-launch.c dbus-launch utility + * + * Copyright (C) 2003, 2006 Red Hat, Inc. + * Copyright (C) 2006 Thiago Macieira + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-launch.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DBUS_BUILD_X11 +#include +extern Display *xdisplay; +#endif + +static char* machine_uuid = NULL; + +const char* +get_machine_uuid (void) +{ + return machine_uuid; +} + +static void +save_machine_uuid (const char *uuid_arg) +{ + if (strlen (uuid_arg) != 32) + { + fprintf (stderr, "machine ID '%s' looks like it's the wrong length, should be 32 hex digits", + uuid_arg); + exit (1); + } + + machine_uuid = xstrdup (uuid_arg); +} + +#define UUID_MAXLEN 40 +/* Read the machine uuid from file if needed. Returns TRUE if machine_uuid is + * set after this function */ +static int +read_machine_uuid_if_needed (void) +{ + FILE *f; + char uuid[UUID_MAXLEN]; + size_t len; + int ret = FALSE; + + if (machine_uuid != NULL) + return TRUE; + + f = fopen (DBUS_MACHINE_UUID_FILE, "r"); + if (f == NULL) + return FALSE; + + if (fgets (uuid, UUID_MAXLEN, f) == NULL) + goto out; + + len = strlen (uuid); + if (len < 32) + goto out; + + /* rstrip the read uuid */ + while (len > 31 && isspace(uuid[len - 1])) + len--; + + if (len != 32) + goto out; + + uuid[len] = '\0'; + machine_uuid = xstrdup (uuid); + verbose ("UID: %s\n", machine_uuid); + ret = TRUE; + +out: + fclose(f); + return ret; +} + + +void +verbose (const char *format, + ...) +{ + va_list args; + static int verbose = TRUE; + static int verbose_initted = FALSE; + + /* things are written a bit oddly here so that + * in the non-verbose case we just have the one + * conditional and return immediately. + */ + if (!verbose) + return; + + if (!verbose_initted) + { + verbose = getenv ("DBUS_VERBOSE") != NULL; + verbose_initted = TRUE; + if (!verbose) + return; + } + + fprintf (stderr, "%lu: ", (unsigned long) getpid ()); + + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); +} + +static void +usage (int ecode) +{ + fprintf (stderr, "dbus-launch [--version] [--help] [--sh-syntax] [--csh-syntax] [--auto-syntax] [--exit-with-session]\n"); + exit (ecode); +} + +static void +version (void) +{ + printf ("D-Bus Message Bus Launcher %s\n" + "Copyright (C) 2003 Red Hat, Inc.\n" + "This is free software; see the source for copying conditions.\n" + "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", + VERSION); + exit (0); +} + +char * +xstrdup (const char *str) +{ + int len; + char *copy; + + if (str == NULL) + return NULL; + + len = strlen (str); + + copy = malloc (len + 1); + if (copy == NULL) + return NULL; + + memcpy (copy, str, len + 1); + + return copy; +} + +typedef enum +{ + READ_STATUS_OK, /**< Read succeeded */ + READ_STATUS_ERROR, /**< Some kind of error */ + READ_STATUS_EOF /**< EOF returned */ +} ReadStatus; + +static ReadStatus +read_line (int fd, + char *buf, + size_t maxlen) +{ + size_t bytes = 0; + ReadStatus retval; + + memset (buf, '\0', maxlen); + maxlen -= 1; /* ensure nul term */ + + retval = READ_STATUS_OK; + + while (TRUE) + { + ssize_t chunk; + size_t to_read; + + again: + to_read = maxlen - bytes; + + if (to_read == 0) + break; + + chunk = read (fd, + buf + bytes, + to_read); + if (chunk < 0 && errno == EINTR) + goto again; + + if (chunk < 0) + { + retval = READ_STATUS_ERROR; + break; + } + else if (chunk == 0) + { + retval = READ_STATUS_EOF; + break; /* EOF */ + } + else /* chunk > 0 */ + bytes += chunk; + } + + if (retval == READ_STATUS_EOF && + bytes > 0) + retval = READ_STATUS_OK; + + /* whack newline */ + if (retval != READ_STATUS_ERROR && + bytes > 0 && + buf[bytes-1] == '\n') + buf[bytes-1] = '\0'; + + return retval; +} + +static ReadStatus +read_pid (int fd, + pid_t *buf) +{ + size_t bytes = 0; + ReadStatus retval; + + retval = READ_STATUS_OK; + + while (TRUE) + { + ssize_t chunk; + size_t to_read; + + again: + to_read = sizeof (pid_t) - bytes; + + if (to_read == 0) + break; + + chunk = read (fd, + ((char*)buf) + bytes, + to_read); + if (chunk < 0 && errno == EINTR) + goto again; + + if (chunk < 0) + { + retval = READ_STATUS_ERROR; + break; + } + else if (chunk == 0) + { + retval = READ_STATUS_EOF; + break; /* EOF */ + } + else /* chunk > 0 */ + bytes += chunk; + } + + return retval; +} + +static void +do_write (int fd, const void *buf, size_t count) +{ + size_t bytes_written; + int ret; + + bytes_written = 0; + + again: + + ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written); + + if (ret < 0) + { + if (errno == EINTR) + goto again; + else + { + fprintf (stderr, "Failed to write data to pipe! %s\n", + strerror (errno)); + exit (1); /* give up, we suck */ + } + } + else + bytes_written += ret; + + if (bytes_written < count) + goto again; +} + +static void +write_pid (int fd, + pid_t pid) +{ + do_write (fd, &pid, sizeof (pid)); +} + +static int +do_waitpid (pid_t pid) +{ + int ret; + + again: + ret = waitpid (pid, NULL, 0); + + if (ret < 0 && + errno == EINTR) + goto again; + + return ret; +} + +static pid_t bus_pid_to_kill = -1; + +static void +kill_bus(void) +{ + verbose ("Killing message bus and exiting babysitter\n"); + kill (bus_pid_to_kill, SIGTERM); + sleep (3); + kill (bus_pid_to_kill, SIGKILL); +} + +void +kill_bus_and_exit (int exitcode) +{ + /* in case these point to any NFS mounts, get rid of them immediately */ + close (0); + close (1); + close (2); + + kill_bus(); + + exit (exitcode); +} + +static void +print_variables (const char *bus_address, pid_t bus_pid, long bus_wid, + int c_shell_syntax, int bourne_shell_syntax, + int binary_syntax) +{ + if (binary_syntax) + { + write (1, bus_address, strlen (bus_address) + 1); + write (1, &bus_pid, sizeof bus_pid); + write (1, &bus_wid, sizeof bus_wid); + return; + } + else if (c_shell_syntax) + { + printf ("setenv DBUS_SESSION_BUS_ADDRESS '%s';\n", bus_address); + printf ("set DBUS_SESSION_BUS_PID=%ld;\n", (long) bus_pid); + if (bus_wid) + printf ("set DBUS_SESSION_BUS_WINDOWID=%ld;\n", (long) bus_wid); + fflush (stdout); + } + else if (bourne_shell_syntax) + { + printf ("DBUS_SESSION_BUS_ADDRESS='%s';\n", bus_address); + printf ("export DBUS_SESSION_BUS_ADDRESS;\n"); + printf ("DBUS_SESSION_BUS_PID=%ld;\n", (long) bus_pid); + if (bus_wid) + printf ("DBUS_SESSION_BUS_WINDOWID=%ld;\n", (long) bus_wid); + fflush (stdout); + } + else + { + printf ("DBUS_SESSION_BUS_ADDRESS=%s\n", bus_address); + printf ("DBUS_SESSION_BUS_PID=%ld\n", (long) bus_pid); + if (bus_wid) + printf ("DBUS_SESSION_BUS_WINDOWID=%ld\n", (long) bus_wid); + fflush (stdout); + } +} + +static int got_sighup = FALSE; + +static void +signal_handler (int sig) +{ + switch (sig) + { +#ifdef SIGHUP + case SIGHUP: +#endif + case SIGINT: + case SIGTERM: + got_sighup = TRUE; + break; + } +} + +static void +kill_bus_when_session_ends (void) +{ + int tty_fd; + int x_fd; + fd_set read_set; + fd_set err_set; + struct sigaction act; + sigset_t empty_mask; + + /* install SIGHUP handler */ + got_sighup = FALSE; + sigemptyset (&empty_mask); + act.sa_handler = signal_handler; + act.sa_mask = empty_mask; + act.sa_flags = 0; + sigaction (SIGHUP, &act, NULL); + sigaction (SIGTERM, &act, NULL); + sigaction (SIGINT, &act, NULL); + +#ifdef DBUS_BUILD_X11 + x11_init(); + if (xdisplay != NULL) + { + x_fd = ConnectionNumber (xdisplay); + } + else + x_fd = -1; +#else + x_fd = -1; +#endif + + if (isatty (0)) + tty_fd = 0; + else + tty_fd = -1; + + if (tty_fd >= 0) + verbose ("stdin isatty(), monitoring it\n"); + else + verbose ("stdin was not a TTY, not monitoring it\n"); + + if (tty_fd < 0 && x_fd < 0) + { + fprintf (stderr, "No terminal on standard input and no X display; cannot attach message bus to session lifetime\n"); + exit (1); + } + + while (TRUE) + { +#ifdef DBUS_BUILD_X11 + /* Dump events on the floor, and let + * IO error handler run if we lose + * the X connection. It's important to + * run this before going into select() since + * we might have queued outgoing messages or + * events. + */ + x11_handle_event (); +#endif + + FD_ZERO (&read_set); + FD_ZERO (&err_set); + + if (tty_fd >= 0) + { + FD_SET (tty_fd, &read_set); + FD_SET (tty_fd, &err_set); + } + + if (x_fd >= 0) + { + FD_SET (x_fd, &read_set); + FD_SET (x_fd, &err_set); + } + + select (MAX (tty_fd, x_fd) + 1, + &read_set, NULL, &err_set, NULL); + + if (got_sighup) + { + verbose ("Got SIGHUP, exiting\n"); + kill_bus_and_exit (0); + } + +#ifdef DBUS_BUILD_X11 + /* Events will be processed before we select again + */ + if (x_fd >= 0) + verbose ("X fd condition reading = %d error = %d\n", + FD_ISSET (x_fd, &read_set), + FD_ISSET (x_fd, &err_set)); +#endif + + if (tty_fd >= 0) + { + if (FD_ISSET (tty_fd, &read_set)) + { + int bytes_read; + char discard[512]; + + verbose ("TTY ready for reading\n"); + + bytes_read = read (tty_fd, discard, sizeof (discard)); + + verbose ("Read %d bytes from TTY errno = %d\n", + bytes_read, errno); + + if (bytes_read == 0) + kill_bus_and_exit (0); /* EOF */ + else if (bytes_read < 0 && errno != EINTR) + { + /* This shouldn't happen I don't think; to avoid + * spinning on the fd forever we exit. + */ + fprintf (stderr, "dbus-launch: error reading from stdin: %s\n", + strerror (errno)); + kill_bus_and_exit (0); + } + } + else if (FD_ISSET (tty_fd, &err_set)) + { + verbose ("TTY has error condition\n"); + + kill_bus_and_exit (0); + } + } + } +} + +static void +babysit (int exit_with_session, + pid_t child_pid, + int read_bus_pid_fd) /* read pid from here */ +{ + int ret; + int dev_null_fd; + const char *s; + + verbose ("babysitting, exit_with_session = %d, child_pid = %ld, read_bus_pid_fd = %d\n", + exit_with_session, (long) child_pid, read_bus_pid_fd); + + /* We chdir ("/") since we are persistent and daemon-like, and fork + * again so dbus-launch can reap the parent. However, we don't + * setsid() or close fd 0 because the idea is to remain attached + * to the tty and the X server in order to kill the message bus + * when the session ends. + */ + + if (chdir ("/") < 0) + { + fprintf (stderr, "Could not change to root directory: %s\n", + strerror (errno)); + exit (1); + } + + /* Close stdout/stderr so we don't block an "eval" or otherwise + * lock up. stdout is still chaining through to dbus-launch + * and in turn to the parent shell. + */ + dev_null_fd = open ("/dev/null", O_RDWR); + if (dev_null_fd >= 0) + { + if (!exit_with_session) + dup2 (dev_null_fd, 0); + dup2 (dev_null_fd, 1); + s = getenv ("DBUS_DEBUG_OUTPUT"); + if (s == NULL || *s == '\0') + dup2 (dev_null_fd, 2); + } + else + { + fprintf (stderr, "Failed to open /dev/null: %s\n", + strerror (errno)); + /* continue, why not */ + } + + ret = fork (); + + if (ret < 0) + { + fprintf (stderr, "fork() failed in babysitter: %s\n", + strerror (errno)); + exit (1); + } + + if (ret > 0) + { + /* Parent reaps pre-fork part of bus daemon, then exits and is + * reaped so the babysitter isn't a zombie + */ + + verbose ("=== Babysitter's intermediate parent continues again\n"); + + if (do_waitpid (child_pid) < 0) + { + /* shouldn't happen */ + fprintf (stderr, "Failed waitpid() waiting for bus daemon's parent\n"); + exit (1); + } + + verbose ("Babysitter's intermediate parent exiting\n"); + + exit (0); + } + + /* Child continues */ + verbose ("=== Babysitter process created\n"); + + verbose ("Reading PID from bus\n"); + + switch (read_pid (read_bus_pid_fd, &bus_pid_to_kill)) + { + case READ_STATUS_OK: + break; + case READ_STATUS_EOF: + fprintf (stderr, "EOF in dbus-launch reading PID from bus daemon\n"); + exit (1); + break; + case READ_STATUS_ERROR: + fprintf (stderr, "Error in dbus-launch reading PID from bus daemon: %s\n", + strerror (errno)); + exit (1); + break; + } + + verbose ("Got PID %ld from daemon\n", + (long) bus_pid_to_kill); + + if (exit_with_session) + { + /* Bus is now started and launcher has needed info; + * we connect to X display and tty and wait to + * kill bus if requested. + */ + + kill_bus_when_session_ends (); + } + + verbose ("Babysitter exiting\n"); + + exit (0); +} + +static void +do_close_stderr (void) +{ + int fd; + + fflush (stderr); + + /* dbus-launch is a Unix-only program, so we can rely on /dev/null being there. + * We're including unistd.h and we're dealing with sh/csh launch sequences... + */ + fd = open ("/dev/null", O_RDWR); + if (fd == -1) + { + fprintf (stderr, "Internal error: cannot open /dev/null: %s", strerror (errno)); + exit (1); + } + + close (2); + if (dup2 (fd, 2) == -1) + { + /* error; we can't report an error anymore... */ + exit (1); + } + close (fd); +} + +static void +pass_info (const char *runprog, const char *bus_address, pid_t bus_pid, + long bus_wid, int c_shell_syntax, int bourne_shell_syntax, + int binary_syntax, + int argc, char **argv, int remaining_args) +{ + if (runprog) + { + char *envvar; + char **args; + int i; + + envvar = malloc (strlen ("DBUS_SESSION_BUS_ADDRESS=") + + strlen (bus_address) + 1); + args = malloc (sizeof (char *) * ((argc-remaining_args)+2)); + + if (envvar == NULL || args == NULL) + goto oom; + + args[0] = xstrdup (runprog); + if (!args[0]) + goto oom; + for (i = 1; i <= (argc-remaining_args); i++) + { + size_t len = strlen (argv[remaining_args+i-1])+1; + args[i] = malloc (len); + if (!args[i]) + goto oom; + strncpy (args[i], argv[remaining_args+i-1], len); + } + args[i] = NULL; + + strcpy (envvar, "DBUS_SESSION_BUS_ADDRESS="); + strcat (envvar, bus_address); + putenv (envvar); + + execvp (runprog, args); + fprintf (stderr, "Couldn't exec %s: %s\n", runprog, strerror (errno)); + exit (1); + } + else + { + print_variables (bus_address, bus_pid, bus_wid, c_shell_syntax, + bourne_shell_syntax, binary_syntax); + } + verbose ("dbus-launch exiting\n"); + + fflush (stdout); + fflush (stderr); + close (1); + close (2); + exit (0); +oom: + fprintf (stderr, "Out of memory!"); + exit (1); +} + +#define READ_END 0 +#define WRITE_END 1 + +int +main (int argc, char **argv) +{ + const char *prev_arg; + const char *shname; + const char *runprog = NULL; + int remaining_args = 0; + int exit_with_session; + int binary_syntax = FALSE; + int c_shell_syntax = FALSE; + int bourne_shell_syntax = FALSE; + int auto_shell_syntax = FALSE; + int autolaunch = FALSE; + int requires_arg = FALSE; + int close_stderr = FALSE; + int i; + int ret; + int bus_pid_to_launcher_pipe[2]; + int bus_pid_to_babysitter_pipe[2]; + int bus_address_to_launcher_pipe[2]; + char *config_file; + + exit_with_session = FALSE; + config_file = NULL; + + prev_arg = NULL; + i = 1; + while (i < argc) + { + const char *arg = argv[i]; + + if (strcmp (arg, "--help") == 0 || + strcmp (arg, "-h") == 0 || + strcmp (arg, "-?") == 0) + usage (0); + else if (strcmp (arg, "--auto-syntax") == 0) + auto_shell_syntax = TRUE; + else if (strcmp (arg, "-c") == 0 || + strcmp (arg, "--csh-syntax") == 0) + c_shell_syntax = TRUE; + else if (strcmp (arg, "-s") == 0 || + strcmp (arg, "--sh-syntax") == 0) + bourne_shell_syntax = TRUE; + else if (strcmp (arg, "--binary-syntax") == 0) + binary_syntax = TRUE; + else if (strcmp (arg, "--version") == 0) + version (); + else if (strcmp (arg, "--exit-with-session") == 0) + exit_with_session = TRUE; + else if (strcmp (arg, "--close-stderr") == 0) + close_stderr = TRUE; + else if (strstr (arg, "--autolaunch=") == arg) + { + const char *s; + + if (autolaunch) + { + fprintf (stderr, "--autolaunch given twice\n"); + exit (1); + } + + autolaunch = TRUE; + + s = strchr (arg, '='); + ++s; + + save_machine_uuid (s); + } + else if (prev_arg && + strcmp (prev_arg, "--autolaunch") == 0) + { + if (autolaunch) + { + fprintf (stderr, "--autolaunch given twice\n"); + exit (1); + } + + autolaunch = TRUE; + + save_machine_uuid (arg); + requires_arg = FALSE; + } + else if (strcmp (arg, "--autolaunch") == 0) + requires_arg = TRUE; + else if (strstr (arg, "--config-file=") == arg) + { + const char *file; + + if (config_file != NULL) + { + fprintf (stderr, "--config-file given twice\n"); + exit (1); + } + + file = strchr (arg, '='); + ++file; + + config_file = xstrdup (file); + } + else if (prev_arg && + strcmp (prev_arg, "--config-file") == 0) + { + if (config_file != NULL) + { + fprintf (stderr, "--config-file given twice\n"); + exit (1); + } + + config_file = xstrdup (arg); + requires_arg = FALSE; + } + else if (strcmp (arg, "--config-file") == 0) + requires_arg = TRUE; + else if (arg[0] == '-') + { + if (strcmp (arg, "--") != 0) + { + fprintf (stderr, "Option `%s' is unknown.\n", arg); + exit (1); + } + else + { + runprog = argv[i+1]; + remaining_args = i+2; + break; + } + } + else + { + runprog = arg; + remaining_args = i+1; + break; + } + + prev_arg = arg; + + ++i; + } + if (requires_arg) + { + fprintf (stderr, "Option `%s' requires an argument.\n", prev_arg); + exit (1); + } + + if (auto_shell_syntax) + { + if ((shname = getenv ("SHELL")) != NULL) + { + if (!strncmp (shname + strlen (shname) - 3, "csh", 3)) + c_shell_syntax = TRUE; + else + bourne_shell_syntax = TRUE; + } + else + bourne_shell_syntax = TRUE; + } + + if (exit_with_session) + verbose ("--exit-with-session enabled\n"); + + if (autolaunch) + { +#ifndef DBUS_BUILD_X11 + fprintf (stderr, "Autolaunch requested, but X11 support not compiled in.\n" + "Cannot continue.\n"); + exit (1); +#else + char *address; + pid_t pid; + long wid; + + if (get_machine_uuid () == NULL) + { + fprintf (stderr, "Machine UUID not provided as arg to --autolaunch\n"); + exit (1); + } + + verbose ("Autolaunch enabled (using X11).\n"); + if (!exit_with_session) + { + verbose ("--exit-with-session automatically enabled\n"); + exit_with_session = TRUE; + } + + if (!x11_init ()) + { + fprintf (stderr, "Autolaunch error: X11 initialization failed.\n"); + exit (1); + } + + if (!x11_get_address (&address, &pid, &wid)) + { + fprintf (stderr, "Autolaunch error: X11 communication error.\n"); + exit (1); + } + + if (address != NULL) + { + verbose ("dbus-daemon is already running. Returning existing parameters.\n"); + pass_info (runprog, address, pid, wid, c_shell_syntax, + bourne_shell_syntax, binary_syntax, argc, argv, remaining_args); + exit (0); + } + } + else if (read_machine_uuid_if_needed()) + { + x11_init(); +#endif + } + + + if (pipe (bus_pid_to_launcher_pipe) < 0 || + pipe (bus_address_to_launcher_pipe) < 0 || + pipe (bus_pid_to_babysitter_pipe) < 0) + { + fprintf (stderr, + "Failed to create pipe: %s\n", + strerror (errno)); + exit (1); + } + + ret = fork (); + if (ret < 0) + { + fprintf (stderr, "Failed to fork: %s\n", + strerror (errno)); + exit (1); + } + + if (ret == 0) + { + /* Child */ +#define MAX_FD_LEN 64 + char write_pid_fd_as_string[MAX_FD_LEN]; + char write_address_fd_as_string[MAX_FD_LEN]; + +#ifdef DBUS_BUILD_X11 + xdisplay = NULL; +#endif + + if (close_stderr) + do_close_stderr (); + + verbose ("=== Babysitter's intermediate parent created\n"); + + /* Fork once more to create babysitter */ + + ret = fork (); + if (ret < 0) + { + fprintf (stderr, "Failed to fork: %s\n", + strerror (errno)); + exit (1); + } + + if (ret > 0) + { + /* In babysitter */ + verbose ("=== Babysitter's intermediate parent continues\n"); + + close (bus_pid_to_launcher_pipe[READ_END]); + close (bus_pid_to_launcher_pipe[WRITE_END]); + close (bus_address_to_launcher_pipe[READ_END]); + close (bus_address_to_launcher_pipe[WRITE_END]); + close (bus_pid_to_babysitter_pipe[WRITE_END]); + + /* babysit() will fork *again* + * and will also reap the pre-forked bus + * daemon + */ + babysit (exit_with_session, ret, + bus_pid_to_babysitter_pipe[READ_END]); + exit (0); + } + + verbose ("=== Bus exec process created\n"); + + /* Now we are the bus process (well, almost; + * dbus-daemon itself forks again) + */ + close (bus_pid_to_launcher_pipe[READ_END]); + close (bus_address_to_launcher_pipe[READ_END]); + close (bus_pid_to_babysitter_pipe[READ_END]); + close (bus_pid_to_babysitter_pipe[WRITE_END]); + + sprintf (write_pid_fd_as_string, + "%d", bus_pid_to_launcher_pipe[WRITE_END]); + + sprintf (write_address_fd_as_string, + "%d", bus_address_to_launcher_pipe[WRITE_END]); + + verbose ("Calling exec()\n"); + +#ifdef DBUS_BUILD_TESTS + /* exec from testdir */ + if (getenv("DBUS_USE_TEST_BINARY") != NULL) + { + execl (TEST_BUS_BINARY, + TEST_BUS_BINARY, + "--fork", + "--print-pid", write_pid_fd_as_string, + "--print-address", write_address_fd_as_string, + config_file ? "--config-file" : "--session", + config_file, /* has to be last in this varargs list */ + NULL); + + fprintf (stderr, + "Failed to execute test message bus daemon %s: %s. Will try again with the system path.\n", + TEST_BUS_BINARY, strerror (errno)); + } + #endif /* DBUS_BUILD_TESTS */ + + execl (DBUS_DAEMONDIR"/dbus-daemon", + DBUS_DAEMONDIR"/dbus-daemon", + "--fork", + "--print-pid", write_pid_fd_as_string, + "--print-address", write_address_fd_as_string, + config_file ? "--config-file" : "--session", + config_file, /* has to be last in this varargs list */ + NULL); + + fprintf (stderr, + "Failed to execute message bus daemon %s: %s. Will try again without full path.\n", + DBUS_DAEMONDIR"/dbus-daemon", strerror (errno)); + + /* + * If it failed, try running without full PATH. Note this is needed + * because the build process builds the run-with-tmp-session-bus.conf + * file and the dbus-daemon will not be in the install location during + * build time. + */ + execlp ("dbus-daemon", + "dbus-daemon", + "--fork", + "--print-pid", write_pid_fd_as_string, + "--print-address", write_address_fd_as_string, + config_file ? "--config-file" : "--session", + config_file, /* has to be last in this varargs list */ + NULL); + + fprintf (stderr, + "Failed to execute message bus daemon: %s\n", + strerror (errno)); + exit (1); + } + else + { + /* Parent */ +#define MAX_PID_LEN 64 + pid_t bus_pid; + char bus_address[MAX_ADDR_LEN]; + char buf[MAX_PID_LEN]; + char *end; + long wid = 0; + long val; + int ret2; + + verbose ("=== Parent dbus-launch continues\n"); + + close (bus_pid_to_launcher_pipe[WRITE_END]); + close (bus_address_to_launcher_pipe[WRITE_END]); + close (bus_pid_to_babysitter_pipe[READ_END]); + + verbose ("Waiting for babysitter's intermediate parent\n"); + + /* Immediately reap parent of babysitter + * (which was created just for us to reap) + */ + if (do_waitpid (ret) < 0) + { + fprintf (stderr, "Failed to waitpid() for babysitter intermediate process: %s\n", + strerror (errno)); + exit (1); + } + + verbose ("Reading address from bus\n"); + + /* Read the pipe data, print, and exit */ + switch (read_line (bus_address_to_launcher_pipe[READ_END], + bus_address, MAX_ADDR_LEN)) + { + case READ_STATUS_OK: + break; + case READ_STATUS_EOF: + fprintf (stderr, "EOF in dbus-launch reading address from bus daemon\n"); + exit (1); + break; + case READ_STATUS_ERROR: + fprintf (stderr, "Error in dbus-launch reading address from bus daemon: %s\n", + strerror (errno)); + exit (1); + break; + } + + close (bus_address_to_launcher_pipe[READ_END]); + + verbose ("Reading PID from daemon\n"); + /* Now read data */ + switch (read_line (bus_pid_to_launcher_pipe[READ_END], buf, MAX_PID_LEN)) + { + case READ_STATUS_OK: + break; + case READ_STATUS_EOF: + fprintf (stderr, "EOF reading PID from bus daemon\n"); + exit (1); + break; + case READ_STATUS_ERROR: + fprintf (stderr, "Error reading PID from bus daemon: %s\n", + strerror (errno)); + exit (1); + break; + } + + end = NULL; + val = strtol (buf, &end, 0); + if (buf == end || end == NULL) + { + fprintf (stderr, "Failed to parse bus PID \"%s\": %s\n", + buf, strerror (errno)); + exit (1); + } + + bus_pid = val; + + close (bus_pid_to_launcher_pipe[READ_END]); + +#ifdef DBUS_BUILD_X11 + if (xdisplay != NULL) + { + verbose("Saving x11 address\n"); + ret2 = x11_save_address (bus_address, bus_pid, &wid); + /* Only get an existing dbus session when autolaunching */ + if (autolaunch) + { + if (ret2 == 0) + { + char *address = NULL; + /* another window got added. Return its address */ + bus_pid_to_kill = bus_pid; + if (x11_get_address (&address, &bus_pid, &wid) + && address != NULL) + { + verbose ("dbus-daemon is already running. Returning existing parameters.\n"); + /* Kill the old bus */ + kill_bus(); + pass_info (runprog, address, bus_pid, wid, + c_shell_syntax, bourne_shell_syntax, binary_syntax, + argc, argv, remaining_args); + } + } + if (ret2 < 0) + { + fprintf (stderr, "Error saving bus information.\n"); + bus_pid_to_kill = bus_pid; + kill_bus_and_exit (1); + } + } + } +#endif + + /* Forward the pid to the babysitter */ + write_pid (bus_pid_to_babysitter_pipe[WRITE_END], bus_pid); + close (bus_pid_to_babysitter_pipe[WRITE_END]); + + pass_info (runprog, bus_address, bus_pid, wid, c_shell_syntax, + bourne_shell_syntax, binary_syntax, argc, argv, remaining_args); + } + + return 0; +} diff --git a/tools/dbus-launch.h b/tools/dbus-launch.h new file mode 100644 index 00000000..d0d0617d --- /dev/null +++ b/tools/dbus-launch.h @@ -0,0 +1,58 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-launch.h dbus-launch utility + * + * Copyright (C) 2006 Thiago Macieira + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef DBUS_LAUNCH_H +#define DBUS_LAUNCH_H + +#include +#include + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#undef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#define MAX_ADDR_LEN 512 + +/* defined in dbus-launch.c */ +void verbose (const char *format, ...); +char *xstrdup (const char *str); +void kill_bus_and_exit (int exitcode); + +const char* get_machine_uuid (void); + +#ifdef DBUS_BUILD_X11 +/* defined in dbus-launch-x11.c */ +int x11_init (void); +int x11_get_address (char **paddress, pid_t *pid, long *wid); +int x11_save_address (char *address, pid_t pid, long *wid); +void x11_handle_event (void); +#endif + +#endif diff --git a/tools/dbus-monitor.1 b/tools/dbus-monitor.1 new file mode 100644 index 00000000..c24c14d9 --- /dev/null +++ b/tools/dbus-monitor.1 @@ -0,0 +1,78 @@ +.\" +.\" dbus-monitor manual page. +.\" Copyright (C) 2003 Red Hat, Inc. +.\" +.TH dbus-monitor 1 +.SH NAME +dbus-monitor \- debug probe to print message bus messages +.SH SYNOPSIS +.PP +.B dbus-monitor +[\-\-system | \-\-session | \-\-address ADDRESS] [\-\-profile | \-\-monitor] +[watch expressions] + +.SH DESCRIPTION + +The \fIdbus-monitor\fP command is used to monitor messages going +through a D-Bus message bus. See +http://www.freedesktop.org/software/dbus/ for more information about +the big picture. + +.PP +There are two well-known message buses: the systemwide message bus +(installed on many systems as the "messagebus" service) and the +per-user-login-session message bus (started each time a user logs in). +The \-\-system and \-\-session options direct \fIdbus-monitor\fP to +monitor the system or session buses respectively. If neither is +specified, \fIdbus-monitor\fP monitors the session bus. + +.PP +\fIdbus-monitor\fP has two different output modes, the 'classic'-style +monitoring mode and profiling mode. The profiling format is a compact +format with a single line per message and microsecond-resolution timing +information. The \-\-profile and \-\-monitor options select the profiling +and monitoring output format respectively. If neither is specified, +\fIdbus-monitor\fP uses the monitoring output format. + +.PP +In order to get \fIdbus-monitor\fP to see the messages you are interested +in, you should specify a set of watch expressions as you would expect to +be passed to the \fIdbus_bus_add_match\fP function. + +.PP +The message bus configuration may keep \fIdbus-monitor\fP from seeing +all messages, especially if you run the monitor as a non-root user. + +.SH OPTIONS +.TP +.I "--system" +Monitor the system message bus. +.TP +.I "--session" +Monitor the session message bus. (This is the default.) +.TP +.I "--address ADDRESS" +Monitor an arbitrary message bus given at ADDRESS. +.TP +.I "--profile" +Use the profiling output format. +.TP +.I "--monitor" +Use the monitoring output format. (This is the default.) + +.SH EXAMPLE +Here is an example of using dbus-monitor to watch for the gnome typing +monitor to say things +.nf + + dbus-monitor "type='signal',sender='org.gnome.TypingMonitor',interface='org.gnome.TypingMonitor'" + +.fi + +.SH AUTHOR +dbus-monitor was written by Philip Blundell. +The profiling output mode was added by Olli Salli. + +.SH BUGS +Please send bug reports to the D-Bus mailing list or bug tracker, +see http://www.freedesktop.org/software/dbus/ diff --git a/tools/dbus-monitor.c b/tools/dbus-monitor.c new file mode 100644 index 00000000..c3681289 --- /dev/null +++ b/tools/dbus-monitor.c @@ -0,0 +1,354 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-monitor.c Utility program to monitor messages on the bus + * + * Copyright (C) 2003 Philip Blundell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#ifdef DBUS_WIN +#include +#undef interface +#else +#include +#endif + +#include + +#include "dbus-print-message.h" + +#ifdef DBUS_WIN + +/* gettimeofday is not defined on windows */ +#define DBUS_SECONDS_SINCE_1601 11644473600LL +#define DBUS_USEC_IN_SEC 1000000LL + +static int +gettimeofday (struct timeval *__p, + void *__t) +{ + union { + unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */ + FILETIME ft; + } now; + + GetSystemTimeAsFileTime (&now.ft); + __p->tv_usec = (long) ((now.ns100 / 10LL) % DBUS_USEC_IN_SEC); + __p->tv_sec = (long)(((now.ns100 / 10LL) / DBUS_SECONDS_SINCE_1601) - DBUS_SECONDS_SINCE_1601); + + return 0; +} +#endif + +static DBusHandlerResult +monitor_filter_func (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + print_message (message, FALSE); + + if (dbus_message_is_signal (message, + DBUS_INTERFACE_LOCAL, + "Disconnected")) + exit (0); + + /* Conceptually we want this to be + * DBUS_HANDLER_RESULT_NOT_YET_HANDLED, but this raises + * some problems. See bug 1719. + */ + return DBUS_HANDLER_RESULT_HANDLED; +} + +#define PROFILE_TIMED_FORMAT "%s\t%lu\t%lu" +#define TRAP_NULL_STRING(str) ((str) ? (str) : "") + +typedef enum +{ + PROFILE_ATTRIBUTE_FLAG_SERIAL = 1, + PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL = 2, + PROFILE_ATTRIBUTE_FLAG_SENDER = 4, + PROFILE_ATTRIBUTE_FLAG_DESTINATION = 8, + PROFILE_ATTRIBUTE_FLAG_PATH = 16, + PROFILE_ATTRIBUTE_FLAG_INTERFACE = 32, + PROFILE_ATTRIBUTE_FLAG_MEMBER = 64, + PROFILE_ATTRIBUTE_FLAG_ERROR_NAME = 128 +} ProfileAttributeFlags; + +static void +profile_print_with_attrs (const char *type, DBusMessage *message, + struct timeval *t, ProfileAttributeFlags attrs) +{ + printf (PROFILE_TIMED_FORMAT, type, t->tv_sec, t->tv_usec); + + if (attrs & PROFILE_ATTRIBUTE_FLAG_SERIAL) + printf ("\t%u", dbus_message_get_serial (message)); + + if (attrs & PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL) + printf ("\t%u", dbus_message_get_reply_serial (message)); + + if (attrs & PROFILE_ATTRIBUTE_FLAG_SENDER) + printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_sender (message))); + + if (attrs & PROFILE_ATTRIBUTE_FLAG_DESTINATION) + printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_destination (message))); + + if (attrs & PROFILE_ATTRIBUTE_FLAG_PATH) + printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_path (message))); + + if (attrs & PROFILE_ATTRIBUTE_FLAG_INTERFACE) + printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_interface (message))); + + if (attrs & PROFILE_ATTRIBUTE_FLAG_MEMBER) + printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_member (message))); + + if (attrs & PROFILE_ATTRIBUTE_FLAG_ERROR_NAME) + printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_error_name (message))); + + printf ("\n"); +} + +static void +print_message_profile (DBusMessage *message) +{ + struct timeval t; + + if (gettimeofday (&t, NULL) < 0) + { + printf ("un\n"); + return; + } + + switch (dbus_message_get_type (message)) + { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + profile_print_with_attrs ("mc", message, &t, + PROFILE_ATTRIBUTE_FLAG_SERIAL | + PROFILE_ATTRIBUTE_FLAG_SENDER | + PROFILE_ATTRIBUTE_FLAG_PATH | + PROFILE_ATTRIBUTE_FLAG_INTERFACE | + PROFILE_ATTRIBUTE_FLAG_MEMBER); + break; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + profile_print_with_attrs ("mr", message, &t, + PROFILE_ATTRIBUTE_FLAG_SERIAL | + PROFILE_ATTRIBUTE_FLAG_DESTINATION | + PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL); + break; + case DBUS_MESSAGE_TYPE_ERROR: + profile_print_with_attrs ("err", message, &t, + PROFILE_ATTRIBUTE_FLAG_SERIAL | + PROFILE_ATTRIBUTE_FLAG_DESTINATION | + PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL); + break; + case DBUS_MESSAGE_TYPE_SIGNAL: + profile_print_with_attrs ("sig", message, &t, + PROFILE_ATTRIBUTE_FLAG_SERIAL | + PROFILE_ATTRIBUTE_FLAG_PATH | + PROFILE_ATTRIBUTE_FLAG_INTERFACE | + PROFILE_ATTRIBUTE_FLAG_MEMBER); + break; + default: + printf (PROFILE_TIMED_FORMAT "\n", "tun", t.tv_sec, t.tv_usec); + break; + } +} + +static DBusHandlerResult +profile_filter_func (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + print_message_profile (message); + + if (dbus_message_is_signal (message, + DBUS_INTERFACE_LOCAL, + "Disconnected")) + exit (0); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static void +usage (char *name, int ecode) +{ + fprintf (stderr, "Usage: %s [--system | --session | --address ADDRESS] [--monitor | --profile ] [watch expressions]\n", name); + exit (ecode); +} + +static dbus_bool_t sigint_received = FALSE; + +static void +sigint_handler (int signum) +{ + sigint_received = TRUE; +} + +int +main (int argc, char *argv[]) +{ + DBusConnection *connection; + DBusError error; + DBusBusType type = DBUS_BUS_SESSION; + DBusHandleMessageFunction filter_func = monitor_filter_func; + char *address = NULL; + + int i = 0, j = 0, numFilters = 0; + char **filters = NULL; + + /* Set stdout to be unbuffered; this is basically so that if people + * do dbus-monitor > file, then send SIGINT via Control-C, they + * don't lose the last chunk of messages. + */ + setvbuf (stdout, NULL, _IOLBF, 0); + + for (i = 1; i < argc; i++) + { + char *arg = argv[i]; + + if (!strcmp (arg, "--system")) + type = DBUS_BUS_SYSTEM; + else if (!strcmp (arg, "--session")) + type = DBUS_BUS_SESSION; + else if (!strcmp (arg, "--address")) + { + if (i+1 < argc) + { + address = argv[i+1]; + i++; + } + else + usage (argv[0], 1); + } + else if (!strcmp (arg, "--help")) + usage (argv[0], 0); + else if (!strcmp (arg, "--monitor")) + filter_func = monitor_filter_func; + else if (!strcmp (arg, "--profile")) + filter_func = profile_filter_func; + else if (!strcmp (arg, "--")) + continue; + else if (arg[0] == '-') + usage (argv[0], 1); + else { + numFilters++; + filters = (char **)realloc(filters, numFilters * sizeof(char *)); + filters[j] = (char *)malloc((strlen(arg) + 1) * sizeof(char *)); + snprintf(filters[j], strlen(arg) + 1, "%s", arg); + j++; + } + } + + dbus_error_init (&error); + + if (address != NULL) + { + connection = dbus_connection_open (address, &error); + if (connection) + { + if (!dbus_bus_register (connection, &error)) + { + fprintf (stderr, "Failed to register connection to bus at %s: %s\n", + address, error.message); + dbus_error_free (&error); + exit (1); + } + } + } + else + connection = dbus_bus_get (type, &error); + if (connection == NULL) + { + const char *where; + if (address != NULL) + where = address; + else + { + switch (type) + { + case DBUS_BUS_SYSTEM: + where = "system bus"; + break; + case DBUS_BUS_SESSION: + where = "session bus"; + break; + default: + where = ""; + } + } + fprintf (stderr, "Failed to open connection to %s: %s\n", + where, + error.message); + dbus_error_free (&error); + exit (1); + } + + if (numFilters) + { + for (i = 0; i < j; i++) + { + dbus_bus_add_match (connection, filters[i], &error); + if (dbus_error_is_set (&error)) + { + fprintf (stderr, "Failed to setup match \"%s\": %s\n", + filters[i], error.message); + dbus_error_free (&error); + exit (1); + } + free(filters[i]); + } + } + else + { + dbus_bus_add_match (connection, + "type='signal'", + &error); + if (dbus_error_is_set (&error)) + goto lose; + dbus_bus_add_match (connection, + "type='method_call'", + &error); + if (dbus_error_is_set (&error)) + goto lose; + dbus_bus_add_match (connection, + "type='method_return'", + &error); + if (dbus_error_is_set (&error)) + goto lose; + dbus_bus_add_match (connection, + "type='error'", + &error); + if (dbus_error_is_set (&error)) + goto lose; + } + + if (!dbus_connection_add_filter (connection, filter_func, NULL, NULL)) { + fprintf (stderr, "Couldn't add filter!\n"); + exit (1); + } + + while (dbus_connection_read_write_dispatch(connection, -1)) + ; + exit (0); + lose: + fprintf (stderr, "Error: %s\n", error.message); + exit (1); +} + diff --git a/tools/dbus-print-message.c b/tools/dbus-print-message.c new file mode 100644 index 00000000..fac5cc1f --- /dev/null +++ b/tools/dbus-print-message.c @@ -0,0 +1,407 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-print-message.h Utility function to print out a message + * + * Copyright (C) 2003 Philip Blundell + * Copyright (C) 2003 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "dbus-print-message.h" + +#include +#include "config.h" + +static const char* +type_to_name (int message_type) +{ + switch (message_type) + { + case DBUS_MESSAGE_TYPE_SIGNAL: + return "signal"; + case DBUS_MESSAGE_TYPE_METHOD_CALL: + return "method call"; + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + return "method return"; + case DBUS_MESSAGE_TYPE_ERROR: + return "error"; + default: + return "(unknown message type)"; + } +} + +#define INDENT 3 + +static void +indent (int depth) +{ + while (depth-- > 0) + printf (" "); /* INDENT spaces. */ +} + +static void +print_hex (unsigned char *bytes, unsigned int len, int depth) +{ + int i, columns; + + printf ("array of bytes [\n"); + + indent (depth + 1); + + /* Each byte takes 3 cells (two hexits, and a space), except the last one. */ + columns = (80 - ((depth + 1) * INDENT)) / 3; + + if (columns < 8) + columns = 8; + + i = 0; + + while (i < len) + { + printf ("%02x", bytes[i]); + i++; + + if (i != len) + { + if (i % columns == 0) + { + printf ("\n"); + indent (depth + 1); + } + else + { + printf (" "); + } + } + } + + printf ("\n"); + indent (depth); + printf ("]\n"); +} + +#define DEFAULT_SIZE 100 + +static void +print_ay (DBusMessageIter *iter, int depth) +{ + /* Not using DBusString because it's not public API. It's 2009, and I'm + * manually growing a string chunk by chunk. + */ + unsigned char *bytes = malloc (DEFAULT_SIZE + 1); + unsigned int len = 0; + unsigned int max = DEFAULT_SIZE; + dbus_bool_t all_ascii = TRUE; + int current_type; + + while ((current_type = dbus_message_iter_get_arg_type (iter)) + != DBUS_TYPE_INVALID) + { + unsigned char val; + + dbus_message_iter_get_basic (iter, &val); + bytes[len] = val; + len++; + + if (val < 32 || val > 126) + all_ascii = FALSE; + + if (len == max) + { + max *= 2; + bytes = realloc (bytes, max + 1); + } + + dbus_message_iter_next (iter); + } + + if (all_ascii) + { + bytes[len] = '\0'; + printf ("array of bytes \"%s\"\n", bytes); + } + else + { + print_hex (bytes, len, depth); + } + + free (bytes); +} + +static void +print_iter (DBusMessageIter *iter, dbus_bool_t literal, int depth) +{ + do + { + int type = dbus_message_iter_get_arg_type (iter); + + if (type == DBUS_TYPE_INVALID) + break; + + indent(depth); + + switch (type) + { + case DBUS_TYPE_STRING: + { + char *val; + dbus_message_iter_get_basic (iter, &val); + if (!literal) + printf ("string \""); + printf ("%s", val); + if (!literal) + printf ("\"\n"); + break; + } + + case DBUS_TYPE_SIGNATURE: + { + char *val; + dbus_message_iter_get_basic (iter, &val); + if (!literal) + printf ("signature \""); + printf ("%s", val); + if (!literal) + printf ("\"\n"); + break; + } + + case DBUS_TYPE_OBJECT_PATH: + { + char *val; + dbus_message_iter_get_basic (iter, &val); + if (!literal) + printf ("object path \""); + printf ("%s", val); + if (!literal) + printf ("\"\n"); + break; + } + + case DBUS_TYPE_INT16: + { + dbus_int16_t val; + dbus_message_iter_get_basic (iter, &val); + printf ("int16 %d\n", val); + break; + } + + case DBUS_TYPE_UINT16: + { + dbus_uint16_t val; + dbus_message_iter_get_basic (iter, &val); + printf ("uint16 %u\n", val); + break; + } + + case DBUS_TYPE_INT32: + { + dbus_int32_t val; + dbus_message_iter_get_basic (iter, &val); + printf ("int32 %d\n", val); + break; + } + + case DBUS_TYPE_UINT32: + { + dbus_uint32_t val; + dbus_message_iter_get_basic (iter, &val); + printf ("uint32 %u\n", val); + break; + } + + case DBUS_TYPE_INT64: + { + dbus_int64_t val; + dbus_message_iter_get_basic (iter, &val); +#ifdef DBUS_INT64_PRINTF_MODIFIER + printf ("int64 %" DBUS_INT64_PRINTF_MODIFIER "d\n", val); +#else + printf ("int64 (omitted)\n"); +#endif + break; + } + + case DBUS_TYPE_UINT64: + { + dbus_uint64_t val; + dbus_message_iter_get_basic (iter, &val); +#ifdef DBUS_INT64_PRINTF_MODIFIER + printf ("uint64 %" DBUS_INT64_PRINTF_MODIFIER "u\n", val); +#else + printf ("uint64 (omitted)\n"); +#endif + break; + } + + case DBUS_TYPE_DOUBLE: + { + double val; + dbus_message_iter_get_basic (iter, &val); + printf ("double %g\n", val); + break; + } + + case DBUS_TYPE_BYTE: + { + unsigned char val; + dbus_message_iter_get_basic (iter, &val); + printf ("byte %d\n", val); + break; + } + + case DBUS_TYPE_BOOLEAN: + { + dbus_bool_t val; + dbus_message_iter_get_basic (iter, &val); + printf ("boolean %s\n", val ? "true" : "false"); + break; + } + + case DBUS_TYPE_VARIANT: + { + DBusMessageIter subiter; + + dbus_message_iter_recurse (iter, &subiter); + + printf ("variant "); + print_iter (&subiter, literal, depth+1); + break; + } + case DBUS_TYPE_ARRAY: + { + int current_type; + DBusMessageIter subiter; + + dbus_message_iter_recurse (iter, &subiter); + + current_type = dbus_message_iter_get_arg_type (&subiter); + + if (current_type == DBUS_TYPE_BYTE) + { + print_ay (&subiter, depth); + break; + } + + printf("array [\n"); + while (current_type != DBUS_TYPE_INVALID) + { + print_iter (&subiter, literal, depth+1); + + dbus_message_iter_next (&subiter); + current_type = dbus_message_iter_get_arg_type (&subiter); + + if (current_type != DBUS_TYPE_INVALID) + printf (","); + } + indent(depth); + printf("]\n"); + break; + } + case DBUS_TYPE_DICT_ENTRY: + { + DBusMessageIter subiter; + + dbus_message_iter_recurse (iter, &subiter); + + printf("dict entry(\n"); + print_iter (&subiter, literal, depth+1); + dbus_message_iter_next (&subiter); + print_iter (&subiter, literal, depth+1); + indent(depth); + printf(")\n"); + break; + } + + case DBUS_TYPE_STRUCT: + { + int current_type; + DBusMessageIter subiter; + + dbus_message_iter_recurse (iter, &subiter); + + printf("struct {\n"); + while ((current_type = dbus_message_iter_get_arg_type (&subiter)) != DBUS_TYPE_INVALID) + { + print_iter (&subiter, literal, depth+1); + dbus_message_iter_next (&subiter); + if (dbus_message_iter_get_arg_type (&subiter) != DBUS_TYPE_INVALID) + printf (","); + } + indent(depth); + printf("}\n"); + break; + } + + default: + printf (" (dbus-monitor too dumb to decipher arg type '%c')\n", type); + break; + } + } while (dbus_message_iter_next (iter)); +} + +void +print_message (DBusMessage *message, dbus_bool_t literal) +{ + DBusMessageIter iter; + const char *sender; + const char *destination; + int message_type; + + message_type = dbus_message_get_type (message); + sender = dbus_message_get_sender (message); + destination = dbus_message_get_destination (message); + + if (!literal) + { + printf ("%s sender=%s -> dest=%s", + type_to_name (message_type), + sender ? sender : "(null sender)", + destination ? destination : "(null destination)"); + + switch (message_type) + { + case DBUS_MESSAGE_TYPE_METHOD_CALL: + case DBUS_MESSAGE_TYPE_SIGNAL: + printf (" serial=%u path=%s; interface=%s; member=%s\n", + dbus_message_get_serial (message), + dbus_message_get_path (message), + dbus_message_get_interface (message), + dbus_message_get_member (message)); + break; + + case DBUS_MESSAGE_TYPE_METHOD_RETURN: + printf (" reply_serial=%u\n", + dbus_message_get_reply_serial (message)); + break; + + case DBUS_MESSAGE_TYPE_ERROR: + printf (" error_name=%s reply_serial=%u\n", + dbus_message_get_error_name (message), + dbus_message_get_reply_serial (message)); + break; + + default: + printf ("\n"); + break; + } + } + + dbus_message_iter_init (message, &iter); + print_iter (&iter, literal, 1); + fflush (stdout); + +} + diff --git a/tools/dbus-print-message.h b/tools/dbus-print-message.h new file mode 100644 index 00000000..26700d84 --- /dev/null +++ b/tools/dbus-print-message.h @@ -0,0 +1,31 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-print-message.h Utility function to print out a message + * + * Copyright (C) 2003 Philip Blundell + * Copyright (C) 2003 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_PRINT_MESSAGE_H +#define DBUS_PRINT_MESSAGE_H + +#include +#include +#include + +void print_message (DBusMessage *message, dbus_bool_t literal); + +#endif /* DBUS_PRINT_MESSAGE_H */ diff --git a/tools/dbus-send.1 b/tools/dbus-send.1 new file mode 100644 index 00000000..4878c3d9 --- /dev/null +++ b/tools/dbus-send.1 @@ -0,0 +1,95 @@ +.\" +.\" dbus-send manual page. +.\" Copyright (C) 2003 Red Hat, Inc. +.\" +.TH dbus-send 1 +.SH NAME +dbus-send \- Send a message to a message bus +.SH SYNOPSIS +.PP +.B dbus-send +[\-\-system | \-\-session] [\-\-dest=NAME] [\-\-print-reply] +[\-\-type=TYPE] [contents ...] + +.SH DESCRIPTION + +The \fIdbus-send\fP command is used to send a message to a D-Bus message +bus. See http://www.freedesktop.org/software/dbus/ for more +information about the big picture. + +.PP +There are two well-known message buses: the systemwide message bus +(installed on many systems as the "messagebus" service) and the +per-user-login-session message bus (started each time a user logs in). +The \-\-system and \-\-session options direct \fIdbus-send\fP to send +messages to the system or session buses respectively. If neither is +specified, \fIdbus-send\fP sends to the session bus. + +.PP +Nearly all uses of \fIdbus-send\fP must provide the \-\-dest argument +which is the name of a connection on the bus to send the message to. If +\-\-dest is omitted, no destination is set. + +.PP +The object path and the name of the message to send must always be +specified. Following arguments, if any, are the message contents +(message arguments). These are given as type-specified values and +may include containers (arrays, dicts, and variants) as described below. + +.nf + ::= | [ | ...] + ::= : + ::= | | + ::= array::[,...] + ::= dict:::,[,,...] + ::= variant:: + ::= string | int16 | uint 16 | int32 | uint32 | int64 | uint64 | double | byte | boolean | objpath +.fi + +D-Bus supports more types than these, but \fIdbus-send\fP currently +does not. Also, \fIdbus-send\fP does not permit empty containers +or nested containers (e.g. arrays of variants). + +.PP +Here is an example invocation: +.nf + + dbus-send \-\-dest=org.freedesktop.ExampleName \\ + /org/freedesktop/sample/object/name \\ + org.freedesktop.ExampleInterface.ExampleMethod \\ + int32:47 string:'hello world' double:65.32 \\ + array:string:"1st item","next item","last item" \\ + dict:string:int32:"one",1,"two",2,"three",3 \\ + variant:int32:-8 \\ + objpath:/org/freedesktop/sample/object/name + +.fi + +Note that the interface is separated from a method or signal +name by a dot, though in the actual protocol the interface +and the interface member are separate fields. + +.SH OPTIONS +The following options are supported: +.TP +.I "--dest=NAME" +Specify the name of the connection to receive the message. +.TP +.I "--print-reply" +Block for a reply to the message sent, and print any reply received. +.TP +.I "--system" +Send to the system message bus. +.TP +.I "--session" +Send to the session message bus. (This is the default.) +.TP +.I "--type=TYPE" +Specify "method_call" or "signal" (defaults to "signal"). + +.SH AUTHOR +dbus-send was written by Philip Blundell. + +.SH BUGS +Please send bug reports to the D-Bus mailing list or bug tracker, +see http://www.freedesktop.org/software/dbus/ diff --git a/tools/dbus-send.c b/tools/dbus-send.c new file mode 100644 index 00000000..c9c9be27 --- /dev/null +++ b/tools/dbus-send.c @@ -0,0 +1,526 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-send.c Utility program to send messages from the command line + * + * Copyright (C) 2003 Philip Blundell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#include + +#include "dbus-print-message.h" + +static const char *appname; + +static void +usage (int ecode) +{ + fprintf (stderr, "Usage: %s [--help] [--system | --session | --address=ADDRESS] [--dest=NAME] [--type=TYPE] [--print-reply=(literal)] [--reply-timeout=MSEC] [contents ...]\n", appname); + exit (ecode); +} + +static void +append_arg (DBusMessageIter *iter, int type, const char *value) +{ + dbus_uint16_t uint16; + dbus_int16_t int16; + dbus_uint32_t uint32; + dbus_int32_t int32; + dbus_uint64_t uint64; + dbus_int64_t int64; + double d; + unsigned char byte; + dbus_bool_t v_BOOLEAN; + + /* FIXME - we are ignoring OOM returns on all these functions */ + switch (type) + { + case DBUS_TYPE_BYTE: + byte = strtoul (value, NULL, 0); + dbus_message_iter_append_basic (iter, DBUS_TYPE_BYTE, &byte); + break; + + case DBUS_TYPE_DOUBLE: + d = strtod (value, NULL); + dbus_message_iter_append_basic (iter, DBUS_TYPE_DOUBLE, &d); + break; + + case DBUS_TYPE_INT16: + int16 = strtol (value, NULL, 0); + dbus_message_iter_append_basic (iter, DBUS_TYPE_INT16, &int16); + break; + + case DBUS_TYPE_UINT16: + uint16 = strtoul (value, NULL, 0); + dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT16, &uint16); + break; + + case DBUS_TYPE_INT32: + int32 = strtol (value, NULL, 0); + dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &int32); + break; + + case DBUS_TYPE_UINT32: + uint32 = strtoul (value, NULL, 0); + dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT32, &uint32); + break; + + case DBUS_TYPE_INT64: + int64 = strtoll (value, NULL, 0); + dbus_message_iter_append_basic (iter, DBUS_TYPE_INT64, &int64); + break; + + case DBUS_TYPE_UINT64: + uint64 = strtoull (value, NULL, 0); + dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT64, &uint64); + break; + + case DBUS_TYPE_STRING: + dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &value); + break; + + case DBUS_TYPE_OBJECT_PATH: + dbus_message_iter_append_basic (iter, DBUS_TYPE_OBJECT_PATH, &value); + break; + + case DBUS_TYPE_BOOLEAN: + if (strcmp (value, "true") == 0) + { + v_BOOLEAN = TRUE; + dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &v_BOOLEAN); + } + else if (strcmp (value, "false") == 0) + { + v_BOOLEAN = FALSE; + dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &v_BOOLEAN); + } + else + { + fprintf (stderr, "%s: Expected \"true\" or \"false\" instead of \"%s\"\n", appname, value); + exit (1); + } + break; + + default: + fprintf (stderr, "%s: Unsupported data type %c\n", appname, (char) type); + exit (1); + } +} + +static void +append_array (DBusMessageIter *iter, int type, const char *value) +{ + const char *val; + char *dupval = strdup (value); + + val = strtok (dupval, ","); + while (val != NULL) + { + append_arg (iter, type, val); + val = strtok (NULL, ","); + } + free (dupval); +} + +static void +append_dict (DBusMessageIter *iter, int keytype, int valtype, const char *value) +{ + const char *val; + char *dupval = strdup (value); + + val = strtok (dupval, ","); + while (val != NULL) + { + DBusMessageIter subiter; + + dbus_message_iter_open_container (iter, + DBUS_TYPE_DICT_ENTRY, + NULL, + &subiter); + + append_arg (&subiter, keytype, val); + val = strtok (NULL, ","); + if (val == NULL) + { + fprintf (stderr, "%s: Malformed dictionary\n", appname); + exit (1); + } + append_arg (&subiter, valtype, val); + + dbus_message_iter_close_container (iter, &subiter); + val = strtok (NULL, ","); + } + free (dupval); +} + +static int +type_from_name (const char *arg) +{ + int type; + if (!strcmp (arg, "string")) + type = DBUS_TYPE_STRING; + else if (!strcmp (arg, "int16")) + type = DBUS_TYPE_INT16; + else if (!strcmp (arg, "uint16")) + type = DBUS_TYPE_UINT16; + else if (!strcmp (arg, "int32")) + type = DBUS_TYPE_INT32; + else if (!strcmp (arg, "uint32")) + type = DBUS_TYPE_UINT32; + else if (!strcmp (arg, "int64")) + type = DBUS_TYPE_INT64; + else if (!strcmp (arg, "uint64")) + type = DBUS_TYPE_UINT64; + else if (!strcmp (arg, "double")) + type = DBUS_TYPE_DOUBLE; + else if (!strcmp (arg, "byte")) + type = DBUS_TYPE_BYTE; + else if (!strcmp (arg, "boolean")) + type = DBUS_TYPE_BOOLEAN; + else if (!strcmp (arg, "objpath")) + type = DBUS_TYPE_OBJECT_PATH; + else + { + fprintf (stderr, "%s: Unknown type \"%s\"\n", appname, arg); + exit (1); + } + return type; +} + +int +main (int argc, char *argv[]) +{ + DBusConnection *connection; + DBusError error; + DBusMessage *message; + int print_reply; + int print_reply_literal; + int reply_timeout; + DBusMessageIter iter; + int i; + DBusBusType type = DBUS_BUS_SESSION; + const char *dest = NULL; + const char *name = NULL; + const char *path = NULL; + int message_type = DBUS_MESSAGE_TYPE_SIGNAL; + const char *type_str = NULL; + const char *address = NULL; + int session_or_system = FALSE; + + appname = argv[0]; + + if (argc < 3) + usage (1); + + print_reply = FALSE; + print_reply_literal = FALSE; + reply_timeout = -1; + + for (i = 1; i < argc && name == NULL; i++) + { + char *arg = argv[i]; + + if (strcmp (arg, "--system") == 0) + { + type = DBUS_BUS_SYSTEM; + session_or_system = TRUE; + } + else if (strcmp (arg, "--session") == 0) + { + type = DBUS_BUS_SESSION; + session_or_system = TRUE; + } + else if (strstr (arg, "--address") == arg) + { + address = strchr (arg, '='); + + if (address == NULL) + { + fprintf (stderr, "\"--address=\" requires an ADDRESS\n"); + usage (1); + } + else + { + address = address + 1; + } + } + else if (strncmp (arg, "--print-reply", 13) == 0) + { + print_reply = TRUE; + message_type = DBUS_MESSAGE_TYPE_METHOD_CALL; + if (*(arg + 13) != '\0') + print_reply_literal = TRUE; + } + else if (strstr (arg, "--reply-timeout=") == arg) + { + reply_timeout = strtol (strchr (arg, '=') + 1, + NULL, 10); + } + else if (strstr (arg, "--dest=") == arg) + dest = strchr (arg, '=') + 1; + else if (strstr (arg, "--type=") == arg) + type_str = strchr (arg, '=') + 1; + else if (!strcmp(arg, "--help")) + usage (0); + else if (arg[0] == '-') + usage (1); + else if (path == NULL) + path = arg; + else if (name == NULL) + name = arg; + else + usage (1); + } + + if (name == NULL) + usage (1); + + if (session_or_system && + (address != NULL)) + { + fprintf (stderr, "\"--address\" may not be used with \"--system\" or \"--session\"\n"); + usage (1); + } + + if (type_str != NULL) + { + message_type = dbus_message_type_from_string (type_str); + if (!(message_type == DBUS_MESSAGE_TYPE_METHOD_CALL || + message_type == DBUS_MESSAGE_TYPE_SIGNAL)) + { + fprintf (stderr, "Message type \"%s\" is not supported\n", + type_str); + exit (1); + } + } + + dbus_error_init (&error); + + if (address != NULL) + { + connection = dbus_connection_open (address, &error); + } + else + { + connection = dbus_bus_get (type, &error); + } + + if (connection == NULL) + { + fprintf (stderr, "Failed to open connection to \"%s\" message bus: %s\n", + (address != NULL) ? address : + ((type == DBUS_BUS_SYSTEM) ? "system" : "session"), + error.message); + dbus_error_free (&error); + exit (1); + } + + if (message_type == DBUS_MESSAGE_TYPE_METHOD_CALL) + { + char *last_dot; + + last_dot = strrchr (name, '.'); + if (last_dot == NULL) + { + fprintf (stderr, "Must use org.mydomain.Interface.Method notation, no dot in \"%s\"\n", + name); + exit (1); + } + *last_dot = '\0'; + + message = dbus_message_new_method_call (NULL, + path, + name, + last_dot + 1); + dbus_message_set_auto_start (message, TRUE); + } + else if (message_type == DBUS_MESSAGE_TYPE_SIGNAL) + { + char *last_dot; + + last_dot = strrchr (name, '.'); + if (last_dot == NULL) + { + fprintf (stderr, "Must use org.mydomain.Interface.Signal notation, no dot in \"%s\"\n", + name); + exit (1); + } + *last_dot = '\0'; + + message = dbus_message_new_signal (path, name, last_dot + 1); + } + else + { + fprintf (stderr, "Internal error, unknown message type\n"); + exit (1); + } + + if (message == NULL) + { + fprintf (stderr, "Couldn't allocate D-Bus message\n"); + exit (1); + } + + if (dest && !dbus_message_set_destination (message, dest)) + { + fprintf (stderr, "Not enough memory\n"); + exit (1); + } + + dbus_message_iter_init_append (message, &iter); + + while (i < argc) + { + char *arg; + char *c; + int type; + int secondary_type; + int container_type; + DBusMessageIter *target_iter; + DBusMessageIter container_iter; + + type = DBUS_TYPE_INVALID; + arg = argv[i++]; + c = strchr (arg, ':'); + + if (c == NULL) + { + fprintf (stderr, "%s: Data item \"%s\" is badly formed\n", argv[0], arg); + exit (1); + } + + *(c++) = 0; + + container_type = DBUS_TYPE_INVALID; + + if (strcmp (arg, "variant") == 0) + container_type = DBUS_TYPE_VARIANT; + else if (strcmp (arg, "array") == 0) + container_type = DBUS_TYPE_ARRAY; + else if (strcmp (arg, "dict") == 0) + container_type = DBUS_TYPE_DICT_ENTRY; + + if (container_type != DBUS_TYPE_INVALID) + { + arg = c; + c = strchr (arg, ':'); + if (c == NULL) + { + fprintf (stderr, "%s: Data item \"%s\" is badly formed\n", argv[0], arg); + exit (1); + } + *(c++) = 0; + } + + if (arg[0] == 0) + type = DBUS_TYPE_STRING; + else + type = type_from_name (arg); + + if (container_type == DBUS_TYPE_DICT_ENTRY) + { + char sig[5]; + arg = c; + c = strchr (c, ':'); + if (c == NULL) + { + fprintf (stderr, "%s: Data item \"%s\" is badly formed\n", argv[0], arg); + exit (1); + } + *(c++) = 0; + secondary_type = type_from_name (arg); + sig[0] = DBUS_DICT_ENTRY_BEGIN_CHAR; + sig[1] = type; + sig[2] = secondary_type; + sig[3] = DBUS_DICT_ENTRY_END_CHAR; + sig[4] = '\0'; + dbus_message_iter_open_container (&iter, + DBUS_TYPE_ARRAY, + sig, + &container_iter); + target_iter = &container_iter; + } + else if (container_type != DBUS_TYPE_INVALID) + { + char sig[2]; + sig[0] = type; + sig[1] = '\0'; + dbus_message_iter_open_container (&iter, + container_type, + sig, + &container_iter); + target_iter = &container_iter; + } + else + target_iter = &iter; + + if (container_type == DBUS_TYPE_ARRAY) + { + append_array (target_iter, type, c); + } + else if (container_type == DBUS_TYPE_DICT_ENTRY) + { + append_dict (target_iter, type, secondary_type, c); + } + else + append_arg (target_iter, type, c); + + if (container_type != DBUS_TYPE_INVALID) + { + dbus_message_iter_close_container (&iter, + &container_iter); + } + } + + if (print_reply) + { + DBusMessage *reply; + + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (connection, + message, reply_timeout, + &error); + if (dbus_error_is_set (&error)) + { + fprintf (stderr, "Error %s: %s\n", + error.name, + error.message); + exit (1); + } + + if (reply) + { + print_message (reply, print_reply_literal); + dbus_message_unref (reply); + } + } + else + { + dbus_connection_send (connection, message, NULL); + dbus_connection_flush (connection); + } + + dbus_message_unref (message); + + dbus_connection_unref (connection); + + exit (0); +} diff --git a/tools/dbus-uuidgen.1 b/tools/dbus-uuidgen.1 new file mode 100644 index 00000000..480fd18f --- /dev/null +++ b/tools/dbus-uuidgen.1 @@ -0,0 +1,89 @@ +.\" +.\" dbus-uuidgen manual page. +.\" Copyright (C) 2006 Red Hat, Inc. +.\" +.TH dbus-uuidgen 1 +.SH NAME +dbus-uuidgen \- Utility to generate UUIDs +.SH SYNOPSIS +.PP +.B dbus-uuidgen [\-\-version] [\-\-ensure[=FILENAME]] [\-\-get[=FILENAME]] + +.SH DESCRIPTION + +The \fIdbus-uuidgen\fP command generates or reads a universally unique ID. + +.PP +Note that the D-Bus UUID has no relationship to RFC 4122 and does not generate +UUIDs compatible with that spec. Many systems have a separate command +for that (often called "uuidgen"). + +.PP +See http://www.freedesktop.org/software/dbus/ for more information +about D-Bus. + +.PP +The primary usage of \fIdbus-uuidgen\fP is to run in the post-install +script of a D-Bus package like this: +.nf + dbus-uuidgen --ensure +.fi + +.PP +This will ensure that /var/lib/dbus/machine-id exists and has the uuid in it. +It won't overwrite an existing uuid, since this id should remain fixed +for a single machine until the next reboot at least. + +.PP +The important properties of the machine UUID are that 1) it remains +unchanged until the next reboot and 2) it is different for any two +running instances of the OS kernel. That is, if two processes see the +same UUID, they should also see the same shared memory, UNIX domain +sockets, local X displays, localhost.localdomain resolution, process +IDs, and so forth. + +.PP +If you run \fIdbus-uuidgen\fP with no options it just prints a new uuid made +up out of thin air. + +.PP +If you run it with --get, it prints the machine UUID by default, or +the UUID in the specified file if you specify a file. + +.PP +If you try to change an existing machine-id on a running system, it will +probably result in bad things happening. Don't try to change this file. Also, +don't make it the same on two different systems; it needs to be different +anytime there are two different kernels running. + +.PP +The UUID should be different on two different virtual machines, +because there are two different kernels. + +.SH OPTIONS +The following options are supported: +.TP +.I "--get[=FILENAME]" +If a filename is not given, defaults to localstatedir/lib/dbus/machine-id +(localstatedir is usually /var). If this file exists and is valid, the +uuid in the file is printed on stdout. Otherwise, the command exits +with a nonzero status. + +.TP +.I "--ensure[=FILENAME]" +If a filename is not given, defaults to localstatedir/lib/dbus/machine-id +(localstatedir is usually /var). If this file exists then it will be +validated, and a failure code returned if it contains the wrong thing. +If the file does not exist, it will be created with a new uuid in it. +On success, prints no output. + +.TP +.I "--version" +Print the version of dbus-uuidgen + +.SH AUTHOR +See http://www.freedesktop.org/software/dbus/doc/AUTHORS + +.SH BUGS +Please send bug reports to the D-Bus mailing list or bug tracker, +see http://www.freedesktop.org/software/dbus/ diff --git a/tools/dbus-uuidgen.c b/tools/dbus-uuidgen.c new file mode 100644 index 00000000..c8ba1cf7 --- /dev/null +++ b/tools/dbus-uuidgen.c @@ -0,0 +1,161 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-uuidgen.c Utility program to create UUIDs + * + * Copyright (C) 2006 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#include +#include + +static void +usage (char *name, int ecode) +{ + if (name == NULL) + name = "dbus-uuidgen"; + + fprintf (stderr, "Usage: %s [--ensure[=FILENAME]] [--get[=FILENAME]]\n", name); + exit (ecode); +} + +static void +version (void) +{ + printf ("D-Bus UUID Generator %s\n" + "Copyright (C) 2006 Red Hat, Inc.\n" + "This is free software; see the source for copying conditions.\n" + "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", + VERSION); + exit (0); +} + +static dbus_bool_t +get_arg (const char *arg, + const char *option, + const char **value_p) +{ + const char *fn; + + if (strlen(arg) < strlen(option)) + return FALSE; + + fn = arg + strlen(option); + + if (!(*fn == '=' || *fn == ' ' || *fn == '\0')) + { + usage (NULL, 1); + } + + if (*fn == '=') + ++fn; + + while (*fn == ' ' && *fn != '\0') + ++fn; + + if (*fn != '\0') + { + *value_p = fn; + return TRUE; + } + + return FALSE; +} + +int +main (int argc, char *argv[]) +{ + int i; + const char *filename; + dbus_bool_t ensure_uuid; + dbus_bool_t get_uuid; + DBusError error; + + ensure_uuid = FALSE; + get_uuid = FALSE; + + filename = NULL; + + for (i = 1; i < argc; i++) + { + char *arg = argv[i]; + + if (strncmp (arg, "--ensure", strlen("--ensure")) == 0) + { + get_arg (arg, "--ensure", &filename); + ensure_uuid = TRUE; + } + else if (strncmp (arg, "--get", strlen("--get")) == 0) + { + get_arg (arg, "--get", &filename); + get_uuid = TRUE; + } + else if (strcmp (arg, "--help") == 0) + usage (argv[0], 0); + else if (strcmp (arg, "--version") == 0) + version (); + else + usage (argv[0], 1); + } + + if (get_uuid && ensure_uuid) + { + fprintf (stderr, "Can't specify both --get and --ensure\n"); + exit (1); + } + + dbus_error_init (&error); + + if (get_uuid || ensure_uuid) + { + char *uuid; + if (dbus_internal_do_not_use_get_uuid (filename, &uuid, ensure_uuid, &error)) + { + if (get_uuid) /* print nothing on --ensure */ + printf ("%s\n", uuid); + dbus_free (uuid); + } + } + else + { + char *uuid; + if (dbus_internal_do_not_use_create_uuid (&uuid)) + { + printf ("%s\n", uuid); + dbus_free (uuid); + } + else + { + dbus_set_error (&error, DBUS_ERROR_NO_MEMORY, "No memory"); + } + } + + if (dbus_error_is_set (&error)) + { + fprintf (stderr, "%s\n", error.message); + dbus_error_free (&error); + exit (1); + } + else + { + exit (0); + } +} diff --git a/tools/run-with-tmp-session-bus.sh b/tools/run-with-tmp-session-bus.sh new file mode 100755 index 00000000..982184a2 --- /dev/null +++ b/tools/run-with-tmp-session-bus.sh @@ -0,0 +1,76 @@ +#! /bin/bash + +SCRIPTNAME=$0 +WRAPPED_SCRIPT=$1 +shift + +die() +{ + if ! test -z "$DBUS_SESSION_BUS_PID" ; then + echo "killing message bus "$DBUS_SESSION_BUS_PID >&2 + kill -9 $DBUS_SESSION_BUS_PID + fi + echo $SCRIPTNAME: $* >&2 + exit 1 +} + +if test -z "$DBUS_TOP_BUILDDIR" ; then + die "Must set DBUS_TOP_BUILDDIR" +fi + +## convenient to be able to ctrl+C without leaking the message bus process +trap 'die "Received SIGINT"' INT + +CONFIG_FILE=./run-with-tmp-session-bus.conf +SERVICE_DIR="$DBUS_TOP_BUILDDIR/test/data/valid-service-files" +ESCAPED_SERVICE_DIR=`echo $SERVICE_DIR | sed -e 's/\//\\\\\\//g'` +echo "escaped service dir is: $ESCAPED_SERVICE_DIR" >&2 + +if test -z "$SOURCE_CONFIG_FILE"; then + SOURCE_CONFIG_FILE="$DBUS_TOP_BUILDDIR/bus/session.conf"; +fi +## create a configuration file based on the standard session.conf +cat $SOURCE_CONFIG_FILE | \ + sed -e 's/'$ESCAPED_SERVICE_DIR'<\/servicedir>/g' | \ + sed -e 's/ $CONFIG_FILE + +echo "Created configuration file $CONFIG_FILE" >&2 + +if ! test -e "$DBUS_TOP_BUILDDIR"/bus/dbus-daemon ; then + die "$DBUS_TOP_BUILDDIR/bus/dbus-daemon does not exist" +fi + +PATH="$DBUS_TOP_BUILDDIR"/bus:$PATH +export PATH + +## the libtool script found by the path search should already do this, but +LD_LIBRARY_PATH=$DBUS_TOP_BUILDDIR/dbus/.libs:$LD_LIBRARY_PATH +export LD_LIBRARY_PATH +unset DBUS_SESSION_BUS_ADDRESS +unset DBUS_SESSION_BUS_PID + +echo "Running $DBUS_TOP_BUILDDIR/tools/dbus-launch --sh-syntax --config-file=$CONFIG_FILE" >&2 + +DBUS_USE_TEST_BINARY=1 +export DBUS_USE_TEST_BINARY +eval `$DBUS_TOP_BUILDDIR/tools/dbus-launch --sh-syntax --config-file=$CONFIG_FILE` + +if test -z "$DBUS_SESSION_BUS_PID" ; then + die "Failed to launch message bus for test script to run" +fi + +echo "Started bus pid $DBUS_SESSION_BUS_PID at $DBUS_SESSION_BUS_ADDRESS" >&2 + +# Execute wrapped script +echo "Running $WRAPPED_SCRIPT $@" >&2 +$WRAPPED_SCRIPT "$@" || die "script \"$WRAPPED_SCRIPT\" failed" + +kill -TERM $DBUS_SESSION_BUS_PID || die "Message bus vanished! should not have happened" && echo "Killed daemon $DBUS_SESSION_BUS_PID" >&2 + +sleep 2 + +## be sure it really died +kill -9 $DBUS_SESSION_BUS_PID > /dev/null 2>&1 || true + +exit 0 -- cgit v1.2.3